【问题标题】:When does Spring @Transactional lock the database table rowSpring @Transactional 何时锁定​​数据库表行
【发布时间】:2021-07-11 07:12:16
【问题描述】:

我正在使用 Spring 数据 JPA,并且我有一个使用 Spring 的 @Transactional 注释进行注释的方法。在该方法中,我从数据库中获取实体。一些实体用于只读目的,而一些实体在该事务中更新。举个例子吧

@Transactional
public void method1(Long id) {
    var entityA = repositoryA.findById(id);
    var entityB = repositoryB.findByOtherId(id);

    entityA.setProperty1(entityB.getProperty() + 1);
}

@Transactional
public void method2(Long id) {
    var entityA = repositoryA.findById(id);
    var entityB = repositoryB.findByOtherId(id);

    entityA.setProperty2(entityB.getProperty() + 2);
}

在上面的例子中,假设entityAentityB分别对应tableAtableBproperty1property2tableA的两列。 另外,我使用的是 SQL Server,所以默认隔离级别是READ_COMMITTED

我有以下问题:

  1. 执行var entityA = repositoryA.findById(id);行后,如何确定应该获取哪种类型的锁?上例中,我们更新tableA中的数据,读取tableB中的数据,那么这里获取的锁是不同的吗?

  2. 假设method1method2 使用相同的id 同时调用。首先获得锁的线程会阻塞第二个线程还是并行执行?我知道隔离级别是READ_COMMITTED,但数据库不知道我是否对第一个线程获取的行进行了任何更改。

  3. 如果我想为同一个id 并行执行这两种方法,应该设置什么隔离级别?同样在这两种方法中,我都在更新同一行的不同列,所以当两个事务提交时,它与串行执行这些事务的结果是否相同?附带说明一下,当 Hibernate 在提交阶段刷新更改时,对于更新语句,它会更新实体的所有字段,那么在这种情况下是否会丢失更新?

  4. 如果我在Transactional注解中指定readOnly=true,对获取锁有影响吗?

【问题讨论】:

  • "@Transactional" 本身在任何隔离级别上都不会启用任何锁定。要实现锁定行为,您应该在查询中使用“@Lock”注释或使用“for update”。在这里详细解释:stackoverflow.com/questions/58786195/…
  • "@Transactional" as itself on any isolation level doesn't enabling any locking这似乎与docs.microsoft.com/en-us/sql/t-sql/statements/…相矛盾
  • 是的,你是正确的,我应该更准确。根据隔离级别,可以获取 READ 锁或共享锁,但如果没有其他操作,则不会创建 WRITE 锁或排他锁。

标签: java multithreading hibernate spring-data-jpa


【解决方案1】:

以下是关于 Hibernate 作为 JPA 提供者的内容。

#1 代码中没有明确的锁。所以,数据库会根据事务隔离级别来执行锁。

#2 当事务提交时,entityA 表示的行将被数据库锁定。如果 method1 获胜,它将阻止 method2 访问底层行,反之亦然。同样,DB 在这里管理锁(所以这里不会有线程级同步)。

#3 使用 READ_COMMITTED 隔离,您一定会遇到更新丢失的情况。为了避免丢失更新,您至少需要 REPEATABLE_READ 隔离级别或使用休眠提供的悲观锁模式以编程方式控制锁。如果您想坚持使用 READ_COMMITTED(99.99% 的用例首选)并且仍然想阻止丢失更新,请使用 @Version 实现乐观锁。

#4 readonly=true 关闭 Hibernate 的一级缓存脏检查。仅此而已。

【讨论】:

    猜你喜欢
    • 2011-12-18
    • 1970-01-01
    • 2021-06-25
    • 1970-01-01
    • 2019-04-24
    • 1970-01-01
    • 2018-08-20
    • 2020-06-04
    • 2017-08-20
    相关资源
    最近更新 更多