根据Hibernate documentation,在Hibernate抛出异常后使用Session是不安全的。
如果Session抛出异常(包括任何SQLException),则立即回滚数据库事务,调用Session.close()并丢弃Session实例。 Session的某些方法不会使会话保持一致状态。 Hibernate抛出的异常都不能被视为可恢复的。确保通过在finally块中调用close()来关闭Session。
在我的代码中,我正在进行批量插入。我正在使用sessionFactory.getCurrentSession()
方法来获取会话。我的代码是这样的。
try {
//some code here....
....
Table1Entity table1Entity = .......
List<Table2Entity> table2Entities = .......
Session currentSession = sessionFactory.getCurrentSession();
for (int i = 0; i < table2Entities; i++) {
.............
currentSession.save(table2Entities.get(i));
if(i % batchSize == 0 || i + 1 == table2Entities) {
currentSession.flush();
currentSession.clear();
}
}
} catch (Exception e) {
currentSession.getTransaction().rollback();
//currentSession.close(); //According to documentation Session should be closed here
table1Entity.setError(true);
currentSession.save(table1Entity);//According to documentation Session should not be used here
.......
}
正如文档所说,在抛出异常后不应使用会话。我的问题是因为我使用currentSession
,如何在catch块中保存table1Entity
?我应该使用openSession()
方法还是以任何其他方式打开新会话?
答案 0 :(得分:0)
这是一个try..catch块。你怎么能确定在table1Entity上进行的任何处理都不会抛出Hibernate异常?如果在处理table1Entity时出现异常,那么尝试将其保存在当前会话中可能会产生更大的问题。
我的建议是将表上的处理分成单独的try..catch块,并在每个块中单独调用save。抛出异常后,尝试在catch块中的同一会话中保存事务是不安全的,并且假设table1Entity中没有问题,有时可能会违反直觉。
答案 1 :(得分:0)
如果与该数据库的连接发生异常,我建议不要写入数据库。所以基本上,我认为你的方法有严重的问题,修复它很可能对你没有好处。
在这种情况下,你应该非常小心你的批次不会抛出异常,无论如何。因此,如果发生异常,您可以假设数据库无法访问,或者无论如何都不会接受任何尝试。将错误写入其他地方(事实证明日志文件对此有用)。
我可以看到你的方法似乎是可行的情况(比如我更新所有有效的方法,我标记的其他方法。要识别“其他”我使用例外)但它旁边永远不会事实上这是一个好主意,而是“诙谐”的情况。 - 不要诙谐,不会得到回报。
而是以一种不会成为首选项的方式编写批处理,而是返回一个说“我没有工作”并正确处理的正确结果。
所以在你的情况下:
try {
//some code here....
....
Table1Entity table1Entity = .......
List<Table2Entity> table2Entities = .......
Session currentSession = sessionFactory.getCurrentSession();
for (int i = 0; i < table2Entities; i++) {
.............
// HERE you need to make sure that this call would succeed
currentSession.save(table2Entities.get(i));
if(i % batchSize == 0 || i + 1 == table2Entities) {
currentSession.flush();
currentSession.clear();
}
}
currentSession.save(table1Entity);
currentSession.getTransaction().commit();
} catch (Exception e) {
currentSession.getTransaction().rollback();
log.warn("Could not do what I wanted", e);
}
要么全部工作要么根本不工作,并为你提供一个正确的堆栈跟踪信息和所有信息(日志)。
也许你想在调用之前调查一个调用是否成功。
如果您认为自己必须按照自己的意愿行事,请在其答案下阅读CodeNewbie的评论:使用setGoingToWriteBatch(true)
创建table1Entry,然后在批处理setBatchWritten(true)
的末尾。这样你就可以找到第一个为真的那个,但第二个不是。