您现在的位置是:首页 >其他 >Spring Data Jpa pessimistic locking网站首页其他
Spring Data Jpa pessimistic locking
我们可以保留两种类型的锁:独占锁和共享锁。当其他人持有共享锁时,我们可以读取但不能写入数据。为了修改或删除保留数据,我们需要有排它锁。
我们可以使用“SELECT … FOR UPDATE”语句获取独占锁。
锁定模式
JPA 规范定义了我们将要讨论的三种悲观锁模式:
PESSIMISTIC_READ
允许我们获得共享锁并防止数据被更新或删除。PESSIMISTIC_WRITE
允许我们获得独占锁并防止数据被读取、更新或删除。PESSIMISTIC_FORCE_INCREMENT
的工作方式与PESSIMISTIC_WRITE
类似,它还会增加版本化实体的版本属性。
它们都是LockModeType类的静态成员,允许事务获取数据库锁。它们都被保留,直到事务提交或回滚。
值得注意的是,我们一次只能获得一把锁。如果不可能,则抛出PersistenceException 。
PESSIMISTIC_READ
每当我们只想读取数据而不遇到脏读时,我们可以使用 PESSIMISTIC_READ
(共享锁)。不过,我们将无法进行任何更新或删除。
有时我们使用的数据库不支持PESSIMISTIC_READ锁,所以我们可以获取PESSIMISTIC_WRITE 锁。
PESSIMISTIC_WRITE
任何需要获取数据锁并对其进行更改的事务都应该获取PESSIMISTIC_WRITE
锁。根据JPA规范,持有 PESSIMISTIC_WRITE锁将阻止其他事务读取、更新或删除数据。
请注意,一些数据库系统实现了 多版本并发控制,允许读者获取已经被阻塞的数据。
PESSIMISTIC_FORCE_INCREMENT
此锁的工作方式与PESSIMISTIC_WRITE类似,但引入它是为了与版本化实体协作——具有用@Version注释的属性的实体。
版本化实体的任何更新都可以在获得PESSIMISTIC_FORCE_INCREMENT锁之前进行。获取该锁会导致更新版本列。
由持久性提供者决定它是否支持未版本化实体的PESSIMISTIC_FORCE_INCREMENT 。如果没有,它会抛出 PersistenceException。
异常情况
最好知道在使用悲观锁定时可能会发生哪种异常。JPA规范提供了不同类型的异常:
PessimisticLockException
表示获取锁或共享锁转排他锁失败,导致事务级回滚。
LockTimeoutException
表示获取锁或将共享锁转换为独占锁超时并导致语句级回滚。
PersistenceException
表示发生持久性问题。PersistenceException及其子类型,除了 NoResultException、NonUniqueResultException、LockTimeoutException 和 QueryTimeoutException,标记要回滚的活动事务。
锁定范围
锁定范围参数定义了如何处理被锁定实体的锁定关系。可以仅在查询中定义的单个实体上获得锁定,或者另外阻止其关系。
要配置范围,我们可以使用PessimisticLockScope
枚举。它包含两个值:NORMAL
和EXTENDED
。
我们可以通过将PessimisticLockScope值 作为 参数传递给EntityManager、Query、TypedQuery或NamedQuery的正确方法的参数’jakarta.persistence’来设置范围:
PessimisticLockScope.NORMAL
PessimisticLockScope.NORMAL是 默认范围。有了这个锁定范围,我们就锁定了实体本身。当与联合继承一起使用时,它还会锁定祖先。
让我们看一下包含两个实体的示例代码:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Person {
@Id
private Long id;
private String name;
private String lastName;
// getters and setters
}
@Entity
public class Employee extends Person {
private BigDecimal salary;
// getters and setters
}
当我们想要获得对Employee 的锁定时,我们可以观察跨越这两个实体的SQL查询:
SELECT t0.ID, t0.DTYPE, t0.LASTNAME, t0.NAME, t1.ID, t1.SALARY
FROM PERSON t0, EMPLOYEE t1
WHERE ((t0.ID = ?) AND ((t1.ID = t0.ID) AND (t0.DTYPE = ?))) FOR UPDATE
PessimisticLockScope.EXTENDED
EXTENDED范围涵盖与NORMAL相同的功能。此外,它还能够阻止连接表中的相关实体。
简而言之,它适用于使用@ElementCollection或@OneToOne、@OneToMany等注释的实体以及@JoinTable。
让我们看一下带有@ElementCollection注解的示例代码:
@Entity
public class Customer {
@Id
private Long customerId;
private String name;
private String lastName;
@ElementCollection
@CollectionTable(name = "customer_address")
private List<Address> addressList;
// getters and setters
}
@Embeddable
public class Address {
private String country;
private String city;
// getters and setters
}
让我们在搜索Customer实体时分析一些查询:
SELECT CUSTOMERID, LASTNAME, NAME
FROM CUSTOMER WHERE (CUSTOMERID = ?) FOR UPDATE
SELECT CITY, COUNTRY, Customer_CUSTOMERID
FROM customer_address
WHERE (Customer_CUSTOMERID = ?) FOR UPDATE
我们可以看到有两个FOR UPDATE查询锁定了客户表中的一行以及连接表中的一行。
另一个需要注意的有趣事实是,并非所有持久性提供程序都支持锁定作用域。