2017-12-02 304 views
1

我试图理解READ COMMITED和READ UNCOMMITED隔离级别在Hibernate中的工作方式,需要一些解释。如何获取共享和排他锁在休眠

有2个线程THR1THR2两者执行相同的事务方法(春季Transactional注释与设置为READ COMMITED隔离级别)。创建名称交易为这些线程TRA1TRA2相应地。该交易方法如下所示:

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 
    } 
} 

的优先级与Entity(optimisticLock = OptimisticLockType.NONE)注释执行2PL模型为这个实体(我错了?)。我使用Oracle数据库。

考虑以下方案:

  1. 让我们假设线程THR1步骤1号线和查询的对象。如果我理解正确,则此线程创建的事务TRA1将为查询的entiry获取共享读锁。那么,如果THR2线程步入第3行,试图获取该实体的独占写入锁定,则不应阻止THR2,直到TRA1释放读取锁定为止?

  2. 我们假设线程THR1进入第3行并获得一个实体的独占写入锁定(独占锁定一直持续到TRA1 transaction completes)。然后,THR2线程步入第1行并尝试查询此实体。不应该阻止THR2,因为TRA2事务尝试获取读锁而其他事务TRA1为此实体保存独占写锁定?

  3. 如果我从第2点复制READ UNCOMMITED隔离级别的场景,则执行TRA2事务的THR2不会看到TRA1事务中由THR1所做的更改,即使在refreshing或再次查询实体后(“评估表达式”在调试下)。为什么?

回答

1

通过设置读锁,可以实现技术上的读提交。但不一定。如果你的DBMS支持MVCC,你总是读取提交的数据(除了你自己的事务中更改的内容)而不设置锁定。

所以我怀疑你使用oracle,mysql(INNODB)或postgres做你的测试?所有这些DBMS都默认支持MVCC,所以它们从不设置共享读锁。

由于您正在使用Oracle“MVCC”数据库,因此即使您在您的实体上配置了2PL协议,也不会实现2PL协议。如果你想找出真正的在本地陈述你的DBMS做到了激活本地语句的输出,你可以在persistence.xml中做到:

<property name="hibernate.show_sql" value="true" /> 

也许你也应该看看transaction-isolation-levels-relation-with-locks-on-table 或第一个在:locks and oracle

+0

我忘了提到Preference类用实体(optimisticLock = OptimisticLockType.NONE)进行了注释,我怀疑它会为给定的实体强制执行2PL模型。我错了吗? – pbartosz

+0

是的,我使用Oracle数据库。 – pbartosz