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

标签 hibernate grails grails-orm jdbctemplate

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

例如

class Book {
    String title
}


// For each CSV record...
insertStatementList.add("insert into book (id, title) values (nextval('hibernate_sequence'), thetitle)")
...
JdbcTemplate bulkInsert = ...
bulkInsert.batchUpdate(insertStatementList)

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

由于 GORM/hibernate 堆栈最终必须从域类定义派生 SQL,有没有办法访问此功能,以便我不必单独维护 SQL 插入语句?或者在伪代码中,可能类似于以下内容:
// would return something like:
// "insert into book (id, title) values (nextval('hibernate_sequence'), 'thetitle')"
def insertStatement = hibernate.getSqlInsertForClass(Book, book.properties)

最佳答案

我对 grails 的了解还不足以说明其中是否有可能。我尝试通过列出类属性并动态组合它来生成 SQL 插入字段,但它出现故障。

您可以创建一个注释来定义该字段在 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
}

如果您需要多个映射(例如,为了支持您自己的旧 CSV),您应该考虑从实体中分离出来的映射结构或 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 注入(inject)的东西,但它更有效,更像是一个概念证明。

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

This link显示在 grails 中使用批量更新的博客文章,使用 withTransaction同时定期应用 session 清除:
    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()             
    }

你确定这行不通?如果没有,那么注释可能是一个解决方案。

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

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

关于hibernate - 访问 grails/hibernate 为域类生成的 SQL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12487802/

相关文章:

java - 如何在spring data jpa中映射好友请求实体

tomcat - 将 Grails 2.5 应用程序部署到 Tomcat8

Grails[Groovy],如何获取一个类没有继承的所有方法的列表?

Grails - 按查询中的两个字段排序

每次提交命令对象时,Grails 2.3.7 乐观锁定版本都会更新

java - Eclipse 是否会搞乱 Servlet/JSP 映射?

spring - 在grails中左联接子查询?

java - Grails/hibernate 缓存不可预测

grails - 在设计领域类 Grails 时需要一些想法

带有 Hibernate 3 和 Spring 的 MySQL UTF8