访问grails/hibernate为域类生成的SQL

访问grails/hibernate为域类生成的SQL,hibernate,grails,gorm,jdbctemplate,Hibernate,Grails,Gorm,Jdbctemplate,在我的grails(1.3.7)应用程序中,我使用JDBC模板从CSV文件批量导入1000条记录(因为它比使用香草GORM/hibernate要快得多,正如您所期望的那样) e、 g 及 这种方法的问题是域类的更改(例如添加subject属性)需要同时更改域类和SQL insert语句 既然GORM/hibernate堆栈最终必须从域类定义派生SQL,那么有没有办法访问此功能,这样我就不必单独维护sqlinsert语句?或者在伪代码中,类似于以下内容: // would return somet

在我的grails(1.3.7)应用程序中,我使用JDBC模板从CSV文件批量导入1000条记录(因为它比使用香草GORM/hibernate要快得多,正如您所期望的那样)

e、 g

这种方法的问题是域类的更改(例如添加
subject
属性)需要同时更改域类和SQL insert语句

既然GORM/hibernate堆栈最终必须从域类定义派生SQL,那么有没有办法访问此功能,这样我就不必单独维护sqlinsert语句?或者在伪代码中,类似于以下内容:

// would return something like:
// "insert into book (id, title) values (nextval('hibernate_sequence'), 'thetitle')"
def insertStatement = hibernate.getSqlInsertForClass(Book, book.properties)

我对grails的了解还不足以说明这是否可能。我试图通过列出类属性并动态组合来生成SQLInsert字段,但结果出现了问题

您可以创建注释来定义该字段在CSV中的位置:

import java.lang.annotation.*

@Retention(RetentionPolicy.RUNTIME) @interface CSV { int position() }

class Product {
  @CSV(position=1) String description
  @CSV(position=3) BigDecimal price
  @CSV(position=4) Integer type
  @CSV(position=2) boolean soldout
}

如果您需要多个映射(例如,支持您自己的老CSVs),则应该考虑映射结构或XML,这将与实体分离。

然后需要迭代字段以组成查询:

def csv = '''rice;10.0;3;false
beet;12.0;2;false
mango;22.0;2;true'''

def properties = Product.declaredFields
  .findAll { it.declaredAnnotations }
  .sort { it.declaredAnnotations[0].position() }

def templateQuery = "INSERT INTO product(#fields) VALUES (#values)"

csv.eachLine { line ->
  def fields = line.split( /;/ )
  def sqlFields = [:]

  fields.eachWithIndex { field, i ->
    sqlFields[properties[i].name] = field
  }

  println templateQuery
    .replace('#fields', sqlFields.keySet().join(","))
    .replace('#values', sqlFields.values().join(","))
}
其中打印:

INSERT INTO product(description,price,type,soldout) VALUES (rice,10.0,3,false)
INSERT INTO product(description,price,type,soldout) VALUES (beet,12.0,2,false)
INSERT INTO product(description,price,type,soldout) VALUES (mango,22.0,2,true)
它非常原始,需要一些修饰,比如引用和一些针对sql注入的东西,但它可以工作,更像是一个概念证明

在我工作过的一个旧系统中,我们使用jboss seam,在那些大容量的东西上使用jpa批处理,即当所有的
persist()
都完成时手动刷新。你确定grails上没有类似的东西可以与gorm一起使用吗

显示了一篇关于在grails中使用批处理更新的博客文章,使用
withTransaction
,同时定期应用会话清除:

    List <Person> batch =[]
    (0..50000).each{
       Person person= new Person(....)
        batch.add(person)
        println "Created:::::"+it
        if(batch.size()>1000){
            Person.withTransaction{
                for(Person p in batch){
                    p.save()
                }
            }
            batch.clear()
        }
      session = sessionFactory.getCurrentSession()
      session.clear()             
    }
List批处理=[]
(0..50000)。每个{
人员=新人员(……)
批量添加(人)
println“创建:::”+它
如果(batch.size()>1000){
Person.withTransaction{
用于(批量p人){
p、 保存()
}
}
批处理清除()
}
session=sessionFactory.getCurrentSession()
会话.清除()
}
你确定那不行吗?如果不是,那么注释可能是一个解决方案

由于java的驼峰大小写和db中的下划线之间的差异,列命名也存在问题。在hibernate中,翻译背后的人是。也许你能从他那里得到些什么。或者在
@CSV
注释中添加列名。听起来像是回收JPA:-)


还有,但我认为它不能解决您的问题:您需要潜入hibernate sql生成。

我不知道您的优化需求是什么,但您仍然可以使用hibernate,保持gorm映射的灵活性并获得惊人的性能。考虑这一点:对于获取Hibernate INSERT语句,我不认为它们暴露了API,所以您必须截取日志或JDBC驱动程序。相当麻烦。@Raphael我在链接中尝试过这种方法(刷新hibernate缓存等),但我发现使用JDBC模板的速度比GORM快3倍左右,我的探查器显示大部分额外时间都花在了GORM(及其关联)的构建上我应该补充一点,在链接中使用这种方法确实在第一时间提供了显著的速度,但仍然不如JDBC模板。您可以尝试使用从域映射的持久属性来构建sql语句。此方法返回以下列表:新的DefaultGrailsDomainClass(YourDomainClazz)。persistantProperties@Raphael谢谢你的建议,但我认为这并不能真正回答我的问题。是的,我可以编写一些代码来从域类def动态地构建SQL,但我的观点是hibernate必须已经在这样做了(可能不可公开访问,但它正在发生)谢谢你,但请参阅我在Raphael的回答中的最新评论。
INSERT INTO product(description,price,type,soldout) VALUES (rice,10.0,3,false)
INSERT INTO product(description,price,type,soldout) VALUES (beet,12.0,2,false)
INSERT INTO product(description,price,type,soldout) VALUES (mango,22.0,2,true)
    List <Person> batch =[]
    (0..50000).each{
       Person person= new Person(....)
        batch.add(person)
        println "Created:::::"+it
        if(batch.size()>1000){
            Person.withTransaction{
                for(Person p in batch){
                    p.save()
                }
            }
            batch.clear()
        }
      session = sessionFactory.getCurrentSession()
      session.clear()             
    }