在我的grails(1.3.7)应用程序中,我使用JDBC模板从CSV文件批量导入1000个记录(因为它比使用vanilla GORM / hibernate快得多,正如您所期望的那样)。
e.g。
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 insert语句?或者在伪代码中,类似于以下内容:
// would return something like:
// "insert into book (id, title) values (nextval('hibernate_sequence'), 'thetitle')"
def insertStatement = hibernate.getSqlInsertForClass(Book, book.properties)
答案 0 :(得分:1)
我不知道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注入的东西,但它的工作原理,更像是一个概念验证。
在我工作的旧系统中,我们使用了jboss接缝和那些我们使用jpa批处理的大量内容,即在完成所有persist()
时手动刷新。你确定在grails上没有类似的东西吗?
This link显示了一篇关于在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()
}
你确定不行吗?如果没有,那么注释可能是一个解决方案。
由于java的camel case和db中的下划线之间存在差异,因此列命名存在问题。在hibernate中,该翻译背后的人是ImprovedNamingStrategy。也许你可以从他那里得到一些东西。或者在@CSV
注释中添加列名称。听起来像回收JPA: - )。
还有log4jdbc,但我认为它无法解决您的问题:您需要潜入hibernate sql生成。