JPA中PESSIMISTIC_READ和PESSIMISTIC_WRITE有什么区别?

74

我已经阅读了文章Java Persistence 2.0中的锁定和并发,并运行了示例应用程序。但我仍然无法理解PESSIMISTIC_READPESSIMISTIC_WRITE之间的区别。 我尝试修改代码,并且在使用 PESSIMISTIC_READ PESSIMISTIC_WRITE 的代码位置将产生相同的结果,即SQL将使用 for update 进行调用。

5个回答

81

这可能是最不技术性的答案,如果我在语义上有错误,请谅解。但是,我对先前答案中语言的复杂性感到沮丧,所以我决定发布一个简单的答案:

  • PESSIMISTIC_READ:你在事务开始时获取记录的锁,仅为了读取目的。基本上你是在说:“当我阅读它时,我不希望任何人更新该记录,但我不介意其他人也读取它”。这意味着尝试 PESSIMISTIC_READ 的人也会成功,但尝试 PESSIMISTIC_WRITE 的人将失败。

  • PESSIMISTIC_WRITE:你在事务开始时获取记录的锁,用于写入操作。你的意思是:“我将更新此记录,因此在我完成之前,没有人可以读取或写入它。” 这意味着尝试 PESSIMISTIC_READ 或 PESSIMISTIC_WRITE 的人都将失败。

“PESSIMISTIC” 部分指的是您在事务开始之前(即在对记录进行任何更改之前)获取锁,而不是在事务结束时(当您即将提交对记录的更改)。


6
谢谢!这对我帮助很大,让我确认我理解得对。因为一开始我对被接受的答案里的语言也感到困惑,我读了三四遍才能理解其要点 :) - RAM237
嗨@taleb,我想确认一些事情。我刚刚使用PESSIMISTIC_READ和PESSIMISTIC_WRITE进行了一些测试。在上面的答案中,您提到某些情况下会失败交易,但是当我尝试重现该情况时,交易将等待而不是失败。所以实际上是“将等待”而不是“将失败”,还是我误解了什么? - Irvan
如果我在之前的事务中获得了一个悲观写锁,那么我是否能够在同一事务中再次从数据库中读取它? - Ravindu Kottahachchi
@Irvan 你可能是对的。我的意思是他们无法阅读/写入,所以可能会等待而不是报错。 - undefined

62
区别在于锁定机制。 PESSIMISTIC_READ 锁表示当你拥有这样的锁时,不可能进行脏读和不可重复读。如果数据需要更改,则需要获取 PESSIMISTIC_WRITE 锁。 PESSIMISTIC_WRITE 锁保证了除了脏读和不可重复读之外,您可以更新数据而无需获取其他锁(并可能在等待独占锁时发生死锁)。
╔══════════════════════╦══════════════════════════╦══════════════════════════╗
║     LockModeType     ║     PESSIMISTIC_READ     ║    PESSIMISTIC_WRITE     ║
╠══════════════════════╬══════════════════════════╬══════════════════════════╣ 
║         type         ║       SHARED LOCK        ║      EXCLUSIVE LOCK      ║
╠══════════════════════╬══════════════════════════╬══════════════════════════╣   
║  isReadOnly without  ║                          ║                          ║
║   additional locks   ║            YES           ║            NO            ║
╠══════════════════════╬══════════════════════════╬══════════════════════════╣
║      dirty reads     ║            NO            ║            NO            ║
╠══════════════════════╬══════════════════════════╬══════════════════════════╣
║ non-repeatable reads ║            NO            ║            NO            ║
╠══════════════════════╬══════════════════════════╬══════════════════════════╣
║ how to update data   ║ obtain PESSIMISTIC_WRITE ║         ALLOWED          ║
╠══════════════════════╬══════════════════════════╬══════════════════════════╣
║                      ║       no one holds       ║      no one holds        ║
║ how to obtain lock   ║     PESSIMISTIC_WRITE    ║   PESSIMISTIC_READ   or  ║
║                      ║                          ║   PESSIMISTIC_WRITE      ║
╠══════════════════════╬══════════════════════════╬══════════════════════════╣
║                      ║                          ║   when there is a high   ║
║                      ║  you want to ensure no   ║ likelihood of deadlock or║
║      when to use     ║ dirty or non-repeatable  ║   update failure among   ║ 
║                      ║   reads are possible     ║    concurrent updating   ║
║                      ║                          ║       transactions       ║
╚══════════════════════╩══════════════════════════╩══════════════════════════╝

Resources:

JPA 2.1


1
PESSIMISTIC_READ会强制在试图读取实体数据的事务之间进行串行化吗? - Mahmoud Saleh

31

其中一个是读锁,另一个是写锁,分别用于读取或更新期间。

FTA:

  • PESSIMISTIC_READ。实体管理器在事务读取实体时立即锁定该实体。锁将保持到事务完成为止。当您想使用可重复读语义查询数据时使用此锁模式。换句话说,您希望确保数据在连续读取之间不被更新。此锁模式不会阻塞其他事务读取数据。

    PESSIMISTIC_WRITE。当事务更新实体时,实体管理器会立即锁定该实体。此锁模式在试图更新实体数据的并发事务之间强制进行序列化。当存在许多并发更新事务中的更新失败的高概率时,通常使用此锁模式。


2
谢谢,我看了描述,但还是有些困惑。当我使用PESSIMISTIC_READ和PESSIMISTIC_WRITE时,在“show sql”和运行结果中总是得到相同的结果。 - paka
很好的解释!您能否添加一些示例代码来演示吗? - Velu
@paka:JPA规范表示:“实现可以使用LockModeType.PESSIMISTIC_WRITE代替请求的LockModeType.PESSIMISTIC_READ,但反之则不行。”详情请参见此答案 - DaniEll
@Joseph,PESSIMISTIC_READ是否会强制在试图读取实体数据的事务之间进行串行化? - Mahmoud Saleh

29

PESSIMISTIC_READ 会在相关的表行记录上获取共享(读)锁,而 PESSIMISTIC_WRITE 则会获取排他(写)锁。

共享锁会阻塞其他并发的排它锁请求,但是允许其他共享锁请求继续。

排它锁会阻塞同时具有共享锁和排它锁请求。

值得一提的是,对于 Hibernate 来说,如果数据库不支持共享锁(比如 Oracle),那么共享锁请求(如 PESSIMISTIC_READ)将简单地获取一个排他锁请求(如 PESSIMISTIC_WRITE)。


PESSIMISTIC_READ会强制在试图读取实体数据的事务之间进行串行化吗? - Mahmoud Saleh
这取决于底层的数据库。例如,在Oracle或PostgreSQL上,这些锁不会获取谓词锁,因此您将无法针对范围获得串行化,只能针对单个记录进行操作。 - Vlad Mihalcea

5
规范允许JPA实现为每个数据库使用不同类型的锁。大多数数据库只有一种声明性锁,因此在大多数情况下,这两者是相同的(没有区别)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接