在我的应用程序中,我隐藏了接口后面的底层存储对象,允许我随意切换存储。
问题在于,在测试hibernate时,似乎Hibernate非常面向事务。我能找到的关于这个主题的所有内容(主要是their official docs)都说自动提交很糟糕,应该很少使用。但是我的整个应用程序不是围绕Hibernate编写的,它是围绕接口编写的。这意味着从数据库中获取数据发生在一个方法中(例如工厂中的getObjects()),而不是事务。
由于我已经抽象出了存储实现,自动提交正确的解决方案?还是有替代方案吗?
答案 0 :(得分:1)
使用自动提交并不意味着事务不再用于访问数据。它只是意味着每个语句现在都在它自己的事务中执行。事务开始时的确切实例,并在JDBC规范中定义。为简洁起见,这通常取决于所执行语句的性质。
我不确定您的设计是如何实现的,但非事务性系统通常会遇到三个问题。使用自动提交可能会重新引入这些问题中的一个或多个。
脏读
考虑应用程序中的线程A,它将读取实体并更新它,但不提交新值。考虑另一个读取同一实体并查看更新值的线程B.如果线程A要回滚它的更改,或者提交更新的值失败,那么B实际上使用的是脏值,因为它执行了脏读。
在它自己的自动提交上不会导致脏读。但是,如果您有一系列最初在单个事务中执行的数据库读写操作,则在每次读/写操作后进行序列提交将导致在另一个事务中进行脏读操作,因为当前事务可能只是简单地回滚改变。
不可重复读取
在事务的上下文中,在事务的上下文中读取相同的实体(记录)两次,并且在第二次读取时看到不同的值被认为是不可重复的读取。当另一个事务已提交更改并且正在进行的事务读取新值时,就会发生这种情况。
使用自动提交(或者更确切地说,在两个不同的事务中执行读取操作)很可能会导致不可重复的读取,因为同一线程中的两个读取操作都将在不同的事务上下文中执行,从而导致第二个读取查看提交的值(来自不同线程中的事务)。
幻影读取
与非可重复读取非常相似,但并不完全相同。在这种情况下,执行第二次读取的执行线程将以新记录的形式看到其他数据(而不是更新的数据)。
同样,出于同样的原因,使用自动提交很可能会导致应用程序中出现幻像读取。
这些问题还取决于所使用的数据库事务隔离级别,但最终当使用ORM框架时,标记事务的开始和结束将留给应用程序开发人员。虽然数据库可以将各个读写操作彼此隔离,但是开发人员可以确保在事务上下文中进行工作。使用自动提交会更改每个操作的事务上下文。
<强> TLDR 强>
在执行事务活动时使用自动提交意味着在“业务事务上下文”期间发生故障时,无法执行回滚到安全状态。另外,出于这个原因,在JDBC中执行批量更新时应禁用自动提交。当真正需要在批处理结束时提交时,使用自动提交将强制对批处理中的每个更新进行提交。
我建议您阅读本书Java Transaction Design Strategies(以免费电子书形式提供),以进一步了解使用交易。
答案 1 :(得分:0)
肯定有一个属性'hibernate.connection.autocommit',你可以在你的hibernate配置XML中或在你的SessionFactory上以编程方式设置为true。
从您的问题中不清楚,在getObjects(
)接口方法的Hibernate实现中开始并提交事务会给您带来什么好处。