我刚开始学习Hibernate,并且每次交易使用以下模式(来自documentation):
private Session session;
private Transaction transaction;
protected List selectAll(Class clazz) throws HibernateException {
List objects = null;
try {
session = MyHibernateHelper.getSessionFactory().openSession();
transaction = session.beginTransaction();
// SELECT ALL
objects = session.createCriteria(clazz).list();
transaction.commit();
} catch (HibernateException exc) {
if (transaction != null) transaction.rollback();
throw exc;
} finally {
session.close();
}
return objects;
}
我可以接受每个操作都应该包含在一个事务中。但是,如果它失败,我似乎很奇怪而且没有必要回滚select
我想我可以安全地删除上面示例中的catch
块。从任何只读操作。我是对的吗?
答案 0 :(得分:9)
考虑到Hibernate必须在各种情况下使用各种数据库。他们在文档中给出的是如何在任何支持的数据库中使用Hibernate。他们试图支持很多数据库。其中一些数据库可能会处理清理失败的事务而无需显式回滚,但Hibernate希望确保它涵盖所有人。
另外,考虑让只读事务失败在现实生活中极为罕见。一旦发生这种情况,回滚就不会有太大的作用,但是它做了什么 - 如Marc B指出的那样释放锁定 - 不是你想要跳过的东西。所以你所倡导的是一种非常微小的优化(根据路径的执行频率很少),在某些情况下会产生不良后果。锁定未被释放是一种不良后果,在其他事务失败或挂起之前不会显示,因此很难找到原因。锁未被释放可能会导致死锁,因此性能/可用性影响可能会很严重。这也是一个难以测试的问题,如果出现问题,在生产环境出现危机之前可能会错过。在多种情况下,这是你想要避免的事情。
这里最大的问题是每个交易都要包含很多样板代码。我的建议是使用回调或Command模式实现一些实用方法(参见Bauer和King的书籍Java Persistence with Hibernate),或采用框架。有一种反对框架的论点,它们掩盖了实施细节并使学习变得更加困难,但是你已经有了学习这些片段的经验。有成熟的框架,如Seam或Spring,可以为您处理此问题。
答案 1 :(得分:1)
如果您使用的是框架或API,或者您实际上并不在您的控制之下,那么您应该始终尊重他们的失败策略,因为您不知道它的内部工作原理。可能还有其他资源可供免费使用。