【问题标题】:How acquiring shared and exclusive locks works in Hibernate在 Hibernate 中如何获取共享锁和排他锁
【发布时间】:2018-05-16 18:00:10
【问题描述】:

我试图了解 READ COMMITED 和 READ UNCOMMITED 隔离级别在 Hibernate 中的工作方式,需要一些解释。

有 2 个线程 THR1THR2 都执行相同的事务方法(Spring 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
  }
}

Preference 类使用 Entity(optimisticLock = OptimisticLockType.NONE) 进行注释,以强制执行该实体的 2PL 模型(我错了吗?)。我使用 Oracle 数据库。

考虑以下场景:

  1. 假设线程 THR1 进入第 1 行并查询一个对象。如果我理解正确,该线程创建的事务 TRA1 会为查询的条目获取共享读锁。那么,如果 THR2 线程跳到第 3 行试图获取该实体的独占写锁,那么在 TRA1 释放读锁之前是否不应该阻塞 THR2?

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

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

【问题讨论】:

    标签: java spring hibernate transactions isolation-level


    【解决方案1】:

    技术上的读提交可以通过设置读锁来实现。但不一定。如果您的 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

    【讨论】:

    • 我忘了提到 Preference 类是用 Entity(optimisticLock = OptimisticLockType.NONE) 注释的,我怀疑它对给定实体强制执行 2PL 模型。我错了吗?
    • 是的,我使用 Oracle 数据库。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-09
    • 2013-11-15
    • 2015-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多