Java 在使用Spring数据JPA查找实体时,如何启用LockModeType.悲观_写入?
如何实现此代码的等效性:Java 在使用Spring数据JPA查找实体时,如何启用LockModeType.悲观_写入?,java,spring,jpa,spring-data,spring-data-jpa,Java,Spring,Jpa,Spring Data,Spring Data Jpa,如何实现此代码的等效性: tx.begin(); Widget w = em.find(Widget.class, 1L, LockModeType.PESSIMISTIC_WRITE); w.decrementBy(4); em.flush(); tx.commit(); 。。。但是使用Spring和Spring数据JPA注释 我现有代码的基础是: @Service @Transactional(readOnly = true) public class WidgetServiceImpl
tx.begin();
Widget w = em.find(Widget.class, 1L, LockModeType.PESSIMISTIC_WRITE);
w.decrementBy(4);
em.flush();
tx.commit();
。。。但是使用Spring和Spring数据JPA注释
我现有代码的基础是:
@Service
@Transactional(readOnly = true)
public class WidgetServiceImpl implements WidgetService
{
/** The spring-data widget repository which extends CrudRepository<Widget, Long>. */
@Autowired
private WidgetRepository repo;
@Transactional(readOnly = false)
public void updateWidgetStock(Long id, int count)
{
Widget w = this.repo.findOne(id);
w.decrementBy(4);
this.repo.save(w);
}
}
@服务
@事务(只读=真)
公共类WidgetServiceImpl实现WidgetService
{
/**扩展Crudepository的spring数据小部件存储库*/
@自动连线
私人回购;
@事务(只读=假)
public void updateWidgetStock(长id,整数计数)
{
Widget w=this.repo.findOne(id);
w、 递减(4);
本次回购保存(w);
}
}
但是我不知道如何指定updateWidgetStock
方法中的所有内容都应该使用悲观锁集来完成
有一个Spring数据JPA注释org.springframework.Data.JPA.repository.Lock
,它允许您设置LockModeType
,但我不知道将它放在updateWidgetStock
方法上是否有效。它听起来更像是WidgetRepository上的注释,因为Javadoc说:
org.springframework.data.jpa.repository@目标(值=方法)
@保留期(值=运行时)
@记录的
公共@接口锁
注释,用于指定执行查询时要使用的LockModeType。在对查询方法使用查询时,或者从方法名称派生查询时,将对其进行计算 。。。所以这似乎没有什么帮助
如何使我的
updateWidgetStock()
方法使用LockModeType.悲观写入
set执行?如果您能够使用Spring数据1.6或更高版本,请忽略此答案并参考Oliver的答案。
Spring数据悲观@Lock
注释仅适用于查询(如您所指出的)。据我所知,没有任何注释会影响整个事务。您可以创建一个findByOnePessimistic
方法,该方法使用悲观锁调用findByOne
,也可以更改findByOne
以始终获得悲观锁
如果您想实现自己的解决方案,您可能可以。在发动机罩下,@Lock
注释由lockmodepopulatingmethodinterceptor
处理,它执行以下操作:
TransactionSynchronizationManager.bindResource(method, lockMode == null ? NULL : lockMode);
interface WidgetRepository extends Repository<Widget, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
Widget findOne(Long id);
}
您可以创建一些静态锁管理器,它有一个
ThreadLocal
成员变量,然后在调用bindResource
的每个存储库中的每个方法周围包装一个方面,并在ThreadLocal
中设置锁模式。这将允许您在每个线程的基础上设置锁定模式。然后,您可以创建自己的@MethodLockMode
注释,该注释将在一个方面中包装该方法,该方面在运行该方法之前设置线程特定的锁定模式,并在运行该方法之后将其清除。@lock
从Spring Data JPA的1.6版开始,CRUD方法就支持它(事实上,已经有可用的). 有关更多详细信息,请参见此
对于该版本,您只需声明以下内容:
TransactionSynchronizationManager.bindResource(method, lockMode == null ? NULL : lockMode);
interface WidgetRepository extends Repository<Widget, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
Widget findOne(Long id);
}
接口WidgetRepository扩展存储库{
@锁(锁模式类型。悲观写入)
小部件findOne(长id);
}
这将导致备份存储库代理的CRUD实现部分将配置的
LockModeType
应用于EntityManager
上的find(…)
调用。如果您不想覆盖标准的findOne()
方法,您可以通过使用select。。。对于更新
查询,如下所示:
/**
* Repository for Wallet.
*/
public interface WalletRepository extends CrudRepository<Wallet, Long>, JpaSpecificationExecutor<Wallet> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select w from Wallet w where w.id = :id")
Wallet findOneForUpdate(@Param("id") Long id);
}
}这两个问题的答案可能都很有帮助:如果查询在事务结束前都没有保留(因此包含以下任何更新),那么在查询上设置悲观锁有什么意义?在查询中获得的悲观锁应该保留到事务结束。后两段描述了如何创建一个事务,其中所有查询都获得了悲观锁。如果我当时理解正确,我只需使
findOne
使用悲观锁即可实现我想要的效果-该锁应保持到事务结束(将在myupdateWidgetStock()的末尾结束)
方法。对吗?请注意,从即将发布的Spring Data JPA的1.6版本开始,CRUD方法将支持使用@Lock
。有关详细信息,请参阅此。在我的测试中,此@Lock已经可以与Spring Data JPA 1.4.1一起使用……但无论如何,问题是,我如何传递锁类型?我不想总是使用悲观锁,很多都是f senarios大部分是读的。但是当我知道我在写,并且会有争用时,我想使用一个悲观锁。我可以创建findOneLock(String,LockModeType)吗?啊,好的,请参见1.4.1。当我将其添加到重写的findOne时,它会工作,但当我将其添加到我自己的findByXxx时,它不会工作。主要问题仍然是,我如何在某些时间使用锁,但不是在所有时间都使用锁。与此相关的小问题。如果我注释方法“findOnePessimstic(…”,会考虑注释吗对于调用findOne(…)的默认实现,这将允许保持findOne的乐观锁定行为,并提供悲观锁定,而不需要@Query。您应该知道,在尝试使用spring data rest的情况下,您会遇到麻烦,因为spring data rest在执行以下操作时会执行只读事务:“select for update”是非法的-并且这些调用完全是findOne…如果@Lock放在方法名派生或查询(非本机)上,那么此时会考虑@Lock。如果根据业务逻辑,我需要相同名称的派生方法同时为悲观/无锁,该怎么办?如何克服它?不幸的是,这不会刷新entityManager
缓存。您必须手动执行entityManager.refresh(wallet)