我试图了解READ COMMITED和READ UNCOMMITED隔离级别在Hibernate中的工作方式,并且需要一些解释。
有两个线程THR1和THR2都执行相同的事务方法(隔离级别设置为READ COMMITED的Spring Transactional注释)。相应地,通过这些线程TRA1和TRA2创建的名称事务。事务处理方法如下所示:
public void updateOrSavePreference(String name, String value) {
Preference preferenceToUpdate = findPreferenceUsingNamedQuery(name); // line 1. shared read lock acquired (uses HibernateTemplate.findByNamedQueryAndNamedParam(...))
if (preferenceToUpdate != null) { // line 2.
preferenceToUpdate.setValue(value); // line 3. exclusive write lock acquired (actually I use the HibernateTemplate.merge(...) method
// instead a setter because the entity type is immutable, but it seems irrelevant for this example)
} else { // line 4.
HibernateTemplate.save(preferenceToUpdate); // line 5. exclusive write lock acquired
}
}
Preference类用Entity(optimisticLock = OptimisticLockType.NONE)注释,以对此实体实施2PL模型(我错了吗?)。我使用Oracle数据库。
请考虑以下情形:
假设线程THR1步进到第1行并查询一个对象。如果我正确理解,则此线程创建的事务TRA1将为查询的条目获取共享的读取锁。然后,如果THR2线程转到第3行,尝试为此实体获取排他写锁,那么在TRA1释放读锁之前,是否不应阻止THR2?
假设线程THR1移至第3行并获取实体的排他写锁(排他锁一直保留到TRA1 transaction completes为止)。然后,THR2线程移至第1行,并尝试查询该实体。不应因为其他事务TRA1拥有该实体的独占写锁而TRA2事务试图获取读锁而阻止THR2吗?
如果我从第2点开始重现了READ UNCOMMITED隔离级别的方案,则执行TRA2事务的THR2即使在refreshing或再次查询该实体后,也看不到THR1在TRA1事务中所做的更改(调试时为“求值表达式”) 。为什么?
最佳答案
通过设置读取锁定,可以实现技术上已提交读操作。但不一定。如果您的DBMS支持MVCC,则您始终在未设置锁定的情况下读取已提交的数据(在您自己的事务中更改的数据除外)。
所以我怀疑您使用oracle,mysql(INNODB)或postgres进行测试吗?所有这些DBMS默认都支持MVCC,因此它们从未设置共享读取锁。
由于您使用的是Oracle“ MVCC”数据库,因此即使您在实体上进行配置,也不会实施2PL协议。如果您想在本机语句中找出对DBMS的实际操作,只需像在persistence.xml中那样激活本机语句的输出即可:
<property name="hibernate.show_sql" value="true" />
也许您还应该看看transaction-isolation-levels-relation-with-locks-on-table
或首先在:locks and oracle