1. Overview
1.概述
In this quick tutorial, we’ll discuss enabling transaction locks in Spring Data JPA for custom query methods and predefined repository CRUD methods.
在这个快速教程中,我们将讨论在Spring Data JPA中为自定义查询方法和预定义存储库CRUD方法启用事务锁。
We’ll also learn about different lock types and setting transaction lock timeouts.
我们还将学习不同的锁类型和设置事务锁超时。
2. Lock Types
2.锁的类型
JPA has two main lock types defined, Pessimistic Locking and Optimistic Locking.
JPA有两种主要的锁类型定义,即悲观锁和乐观锁。
2.1. Pessimistic Locking
2.1.悲观的锁定
When we use Pessimistic Locking in a transaction, and access an entity, it’ll be locked immediately. The transaction releases the lock either by committing or rolling back the transaction.
当我们在事务中使用Pessimistic Locking,并访问一个实体时,它将被立即锁定。事务会通过提交或回滚事务来释放锁。
2.2. Optimistic Locking
2.2.乐观的锁定
In Optimistic Locking, the transaction doesn’t lock the entity immediately. Instead, the transaction commonly saves the entity’s state with a version number assigned to it.
在Optimistic Locking中,事务不会立即锁定实体。相反,事务通常会以分配给实体的版本号来保存其状态。
When we try to update the entity’s state in a different transaction, the transaction compares the saved version number with the existing version number during the update.
当我们试图在不同的事务中更新实体的状态时,事务会在更新时将保存的版本号与现有的版本号进行比较。
At this point, if the version number differs, it means that we can’t modify the entity. If there’s an active transaction, then that transaction will be rolled back and the underlying JPA implementation will throw an OptimisticLockException.
在这一点上,如果版本号不一样,就意味着我们不能修改实体。如果有一个活动的事务,那么该事务将被回滚,底层JPA实现将抛出一个OptimisticLockException。。
Depending on what’s most suitable for our current development context, we can also use other approaches, such as timestamps, hash value computation, or serialized checksum.
根据什么最适合我们当前的开发环境,我们也可以使用其他方法,如时间戳、哈希值计算或序列化校验。
3. Enabling Transaction Locks on Query Methods
3.在查询方法上启用事务锁
To acquire a lock on an entity, we can annotate the target query method with a Lock annotation by passing the required lock mode type.
为了获取实体上的锁,我们可以通过传递所需的锁模式类型,用锁注解来注解目标查询方法。
Lock mode types are enum values to be specified while locking an entity. The specified lock mode is then propagated to the database to apply the corresponding lock on the entity object.
锁模式类型是在锁定一个实体时要指定的枚举值。然后,指定的锁模式将被传播到数据库中,以便在实体对象上应用相应的锁。
To specify a lock on a custom query method of a Spring Data JPA repository, we can annotate the method with @Lock and specify the required lock mode type:
要在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);
To enforce the lock on predefined repository methods, such as findAll or findById(id), we have to declare the method within the repository and annotate the method with the Lock annotation:
为了对预定义的版本库方法实施锁定,例如findAll或findById(id),我们必须在版本库中声明该方法,并给该方法加上Lock注解。
@Lock(LockModeType.PESSIMISTIC_READ)
public Optional<Customer> findById(Long customerId);
When the lock is explicitly enabled, and there’s no active transaction, the underlying JPA implementation will throw a TransactionRequiredException.
当锁被明确启用,并且没有活动的事务,底层JPA实现将抛出一个TransactionRequiredException。
If the lock can’t be granted, and the locking conflict doesn’t result in a transaction rollback, JPA throws a LockTimeoutException, but it doesn’t mark the active transaction for rollback.
如果锁不能被授予,并且锁冲突没有导致事务回滚,JPA会抛出一个LockTimeoutException,但它不会对活动事务进行回滚标记。
4. Setting Transaction Lock Timeouts
4.设置事务锁定超时
When using Pessimistic Locking, the database will try to lock the entity immediately. The underlying JPA implementation throws a LockTimeoutException when the lock can’t be obtained immediately. To avoid such exceptions, we can specify the lock timeout value.
当使用Pessimistic Locking时,数据库将尝试立即锁定该实体。当不能立即获得锁时,底层JPA实现会抛出一个LockTimeoutException。为了避免这种异常,我们可以指定锁的超时值。
In Spring Data JPA, the lock timeout can be specified using the QueryHints annotation by placing a QueryHint on query methods:
在Spring Data JPA中,可以使用QueryHints注解,在查询方法上放置QueryHint来指定锁定超时。
@Lock(LockModeType.PESSIMISTIC_READ)
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "3000")})
public Optional<Customer> findById(Long customerId);
We can find further details on setting the lock timeout hint at different scopes in this ObjectDB article.
我们可以在这篇ObjectDB文章中找到关于在不同作用域设置锁定超时提示的进一步细节。
5. Conclusion
5.总结
In this article, we explored the different types of transaction lock modes. Then we learned how to enable transaction locks in Spring Data JPA. We also covered setting lock timeouts.
在这篇文章中,我们探讨了不同类型的事务锁模式。然后我们学习了如何在Spring Data JPA中启用事务锁。我们还介绍了设置锁的超时。
Applying the right transaction locks at the right places can help to maintain data integrity in high-volume concurrent usage applications.
在正确的地方应用正确的事务锁,可以帮助保持大批量并发使用应用程序的数据完整性。
When the transaction needs to strictly adhere to ACID rules, we should use Pessimistic Locking. Optimistic Locking should be applied when we need to allow multiple concurrent reads and when eventual consistency is acceptable within the application context.
当事务需要严格遵守ACID规则时,我们应该使用悲观锁。当我们需要允许多个并发读取,并且最终的一致性在应用环境中是可以接受的时候,就应该应用乐观锁。
As always, the sample code for both Pessimistic Locking and Optimistic Locking can be found over on Github.
一如既往,悲观锁定和乐观锁定的示例代码都可以在Github上找到over。