Spring Data JPA 事务锁

1.概述

在本快速教程中,咱们将讨论在Spring Data JPA中为自定义查询方法和预约义存储库的CRUD方法启用事务锁, 咱们还将查看不一样的锁类型并设置事务锁超时。html

2.锁类型

JPA定义了两种主要的锁类型,即悲观锁和乐观锁。java

2.1悲观锁

当咱们在事务中使用悲观锁并访问实体时,它将当即锁定。经过提交或回滚事务来释放锁。git

2.2乐观锁

在乐观中,事务不会当即锁定实体。相反,事务一般会保存实体的状态,并为其分配版本号。github

当咱们尝试在不一样的事务中更新实体的状态时,事务会在更新期间将保存的版本号与现有的版本号进行比较。spring

此时,若是版本号不一样,则表示没法修改实体。若是存在活动事务,那么该事务将被回滚,而且底层JPA实现将抛出OptimisticLockException数据库

除版本号方法外,咱们还可使用其余方法,如时间戳,哈希值计算或序列化校验和,具体取决于哪一种方法最适合咱们当前的开发环境。api

3.在查询方法上启用事务锁

要获取实体的锁定,咱们能够经过使用@Lock来注解目标查询方法, 并传递所需的锁定模式类型并发

锁定模式类型(Lock mode types)是锁定实体时要指定的枚举值。而后,将指定的锁定模式传递到数据库,以在实体对象上应用相应的锁定。oracle

要在Spring Data JPA存储库的自定义查询方法上指定锁定,咱们可使用@Lock注解该方法并指定所需的锁定模式类型:高并发

@Lock(LockModeType.OPTIMISTIC_FORCE_INCREMENT)
@Query("SELECT c FROM Customer c WHERE c.orgId = ?1")
public List<Customer> fetchCustomersByOrgId(Long orgId);

要强制锁定预约义的存储库方法(如findAll或findById(id)),咱们必须在存储库中声明方法并使用@Lock注解该方法:

@Lock(LockModeType.PESSIMISTIC_READ)
public Optional<Customer> findById(Long customerId);

当显式启用锁而且没有活动事务时,底层JPA实现将抛出TransactionRequiredException

若是没法授予锁而且锁冲突不会致使事务回滚,则JPA会抛出LockTimeoutException。但它不标记回滚的活动事务。

4.设置事务锁定超时

使用悲观锁时,数据库将尝试当即锁定实体。当没法当即获取锁定时,底层JPA实现会抛出LockTimeoutException。为避免此类异常,咱们能够指定锁超时时间。

在Spring Data JPA中,可使用@QueryHints指定锁定超时时间:

@Lock(LockModeType.PESSIMISTIC_READ)
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "3000")})
public Optional<Customer> findById(Long customerId);

有关在不一样范围设置锁定超时提示的更多详细信息,请参见ObjectDB文章

5.结论

在本教程中,咱们学习了不一样类型的事务锁定模式,以及如何在Spring Data JPA中启用事务锁,并简单介绍了如何设置锁定超时。

在正确的位置应用正确的事务锁,能够帮助维护高并发状况下应用程序中数据完整性。

当交易须要严格遵照ACID规则时,咱们应该使用悲观锁。当咱们须要容许多个并发读取以及在应用程序上下文中可接受的最终一致性时,应该应用乐观锁。

固然,能够在Github上找到悲观锁和乐观锁的示例代码。

原文:https://www.baeldung.com/java-jpa-transaction-locks

做者:baeldung

译者:Leesen

相关文章
相关标签/搜索