我有一个使用Spring-JPA (Hibernate)持久化N个实体的需求,并且我已经设置了我的spring批量大小= M,其中M
我将向存储库提交所有N个实体,它遵循以下逻辑
entities.forEach(entity->entityManager.persist(entity));
entityManager.flush();
整个操作由@Transactional包装。
基于https://vladmihalcea.com/how-to-find-which-statement-failed-in-a-jdbc-batch-update,它给了我更好的结果,但挑战是,BatchUpdateException.getUpdateCounts()给出了每个批处理操作中持久化的总数,而不是失败前包括所有内部迭代在内的总计数。
例如,如果我需要持久化100个实体,spring batch size =5
spring.jpa.properties.hibernate.jdbc.batch_size=5
13记录是导致失败的坏记录。BatchUpdateException.getUpdateCounts()返回2,这是因为它在批处理周期的第三次迭代中失败。取而代之的是,我希望获得12次成功插入的计数。有没有任何API或某种方法可以跟踪这个,而不需要外部跟踪(这会通过多次调用flush来违背我的目的)
AtomicInteger ai = new AtomicInteger(0);
entities.forEach(entity->{ entityManager.persist(entity);
ai.getAndIncrement();
if(ai.get() % batchsize){
entityManager.flush();
});
entityManager.flush();
谢谢
发布于 2019-08-21 14:55:57
有一些关于使用Hibernate批量插入Oracle12的新闻。先来个不错的。
Hibernate Oracle12批插入
实际上,如果设置属性,Hibernate (至少在我测试的5.4.4版本中)支持批量插入
<property name="hibernate.jdbc.batch_size" value="3"/>识别它有点棘手,因为Hibernate日志记录与正常模式日志记录没有什么不同。可能是因为Oracle没有将值集合传递给INSERT的语法,所以您会看到单个insert语句的日志
Hibernate: insert into AUTHOR (name, AUTHOR_ID) values (?, ?)
Hibernate: insert into AUTHOR (name, AUTHOR_ID) values (?, ?)
Hibernate: insert into AUTHOR (name, AUTHOR_ID) values (?, ?)但是通过检查Oracle10046跟踪,您可以看到,每次执行INSERT游标都会处理行的批处理大小(参见EXEC跟踪行中的参数r=3 - batch_size设置为3)
PARSING IN CURSOR #347407728 ..
insert into AUTHOR (name, AUTHOR_ID) values (:1 , :2 )
END OF STMT
EXEC #347407728:....,r=3,...请注意,不幸的是,您不能在批处理模式中使用主键的标识列
AUTHOR_ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,使用IDENTITY将关闭批处理模式。
getUpdateCount
第二个好消息是,如果您在批处理中遇到异常,则可以获取当前批处理的updateCounts -您必须取消嵌套使用此伪代码接收的PersistenceException
e.getCause().getSQLException().getUpdateCounts()但是请注意,您需要在Oracle12上使用相应的JDBC驱动程序来查看确切的更新计数-在以前的版本中,您只会看到一个非特定的错误(单个负数)。
将其整合在一起
因此,结合这两个特征,您可以-至少在理论上-识别失败的记录
batch_size =3的示例
您将看到6个记录的行
Hibernate: insert into AUTHOR (name, AUTHOR_ID) values (?, ?)
Hibernate: insert into AUTHOR (name, AUTHOR_ID) values (?, ?)
Hibernate: insert into AUTHOR (name, AUTHOR_ID) values (?, ?)
Hibernate: insert into AUTHOR (name, AUTHOR_ID) values (?, ?)
Hibernate: insert into AUTHOR (name, AUTHOR_ID) values (?, ?)
Hibernate: insert into AUTHOR (name, AUTHOR_ID) values (?, ?)即,启动了2批,第二批失败,成功处理了两行
BatchUpdateException - update count: [1, 1]这意味着3+2行正常,而第6行失败
摘要
您可能会争辩说,Hibernate人员没有做好他们的功课,并且阅读日志不是识别问题的好方法。我对此没有异议,我只能提供一些你可能从Hibernate作者那里听到的见解(请注意,除了解决数据库问题之外,我与Hibernate没有任何关系)。
验证输入的
这当然是有争议的,但在使用批处理输入时,您应该预先验证数据,这样就不会出现异常。
刷新每个批处理
你反对它,但实际上它并没有真正的性能损失。每次刷新时,插入游标都会关闭并重新打开,但由于Oracle游标兑现,这没什么大不了的。
,性能不是您的第一个目标
最重要的是,虽然决定将Hibernate用于批量数据输入,但性能绝对不是您的首要目标。您选择了舒适的数据输入,并为此支付了一些性能税。
我的测试显示,在大约50秒内存储100K批处理大小为1000的简单对象所用的时间。这不是每个对象的平均.4毫秒数,但是使用直接的SQL INSERT来处理100K行所需的时间低于2秒。因此,对于单个步骤,例如时间窗口非常窄的迁移和升级,您可以从直接使用JDBC或事件SQL中获益。
https://stackoverflow.com/questions/57422704
复制相似问题