可序列化事务与SELECT FOR UPDATE

Dun*_*aul 12 database jpa

我正在阅读不同的事务隔离级别,并跨越SERIALIZABLE隔离级别.我也知道Postgres,Oracle和MySQL等数据库支持SELECT .. FOR UPDATE语法.

然而,当我想要锁定我希望执行更新的行(或一系列行)时,我会感到困惑.

在过去使用JPA时,我总是在查询中@Transactional使用a LockModeType.PESSIMISTIC_WRITE.这转换为在SQL中使用READ_COMMITTED隔离级别SELECT .. FOR UPDATE.

但是现在,在阅读之后SERIALIZABLE,我想知道如果我使用@Transactional(isolation=SERIALIZABLE)普通SELECT(例如em.findById来获取分离的实体),然后是UPDATE(实体的合并)会有什么不同.

行为会是一样的吗?

比方说,我有一个银行系统,我希望在两个账户之间转账.转移正在进行中,我要求不要干涉这些帐户.因此,假设我用-100借记​​一个账户并将其存入另一个账户.确保这些帐户仅可用于执行更新的交易的最佳方法是什么?

假设我正在操作JPA分离的实体,所以在更新之前,我将不得不从数据库中读取它们,例如findById().

  • 使用@Transactional(isolation=READ_COMMITTED),em.findById与LockModeType.PESSIMISTIC_WRITE(ie SELECT .. FOR UPDATE),然后em.merge(即UPDATE)?
  • 或者使用@Transactional(isolation=SERIALIZABLE),em.findById,然后是em.merge(即UPDATE)?

Jam*_*mes 5

SERIALIZABLE和使用SELECT FOR UPDATE之间的主要区别在于,使用SERIALIZABLE时,所有内容始终被锁定。与SELECT FOR UPDATE一样,您可以选择锁定的内容和时间。

因此,如果您只想锁定某些数据(即BankAccount)而不是其他数据(例如Branch,AccountTypes),那么SELECT FOR UPDATE将为您提供更好的控制,因为SERIALIZABLE会阻塞您的整个系统,因为从ACCOUNT_TYPES表中选择的每个事务。另外,某些事务可能只想检查余额,因此不需要锁定ACCOUNT表。

看到,

http://en.wikibooks.org/wiki/Java_Persistence/Locking

  • 一般情况下,“ *带有SERIALIZABLE的所有内容始终被锁定*”不是正确的。这在很大程度上取决于DBMS的实现(例如Postgres不会这样做) (12认同)
  • 在可序列化的 PostgreSQL 中,确实“例如 PostgreSQL 不会那样做”将执行所有选择语句而没有锁定,但是当在写入语句中发生并发时,最后一个事务将失败授予可序列化完整性 (2认同)