Java 如何在spring数据jpa查询中指定@lock timeout?
如何指定查询的Java 如何在spring数据jpa查询中指定@lock timeout?,java,spring,oracle,hibernate,jpa,Java,Spring,Oracle,Hibernate,Jpa,如何指定查询的@Lock超时? 我正在使用Oracle11g,我希望我可以使用类似于“从表中选择id,其中id=?1用于更新等待5”的东西 我定义的方法如下: @Lock(LockModeType.PESSIMISTIC_WRITE) Stock findById(String id); 它似乎永远锁着。 当我在LocalContainerEntityManagerFactoryBean.jpapproperties中设置javax.persistence.lock.timeout=0时,没有
@Lock
超时?
我正在使用Oracle11g,我希望我可以使用类似于“从表中选择id,其中id=?1用于更新等待5”的东西
我定义的方法如下:
@Lock(LockModeType.PESSIMISTIC_WRITE)
Stock findById(String id);
它似乎永远锁着。
当我在LocalContainerEntityManagerFactoryBean.jpapproperties
中设置javax.persistence.lock.timeout=0时,没有任何效果
要以悲观方式锁定实体,请将锁定模式设置为
悲观的读取
,悲观的写入
,或
悲观力增量
如果无法获得悲观锁,但锁定失败
不会导致事务回滚,LockTimeoutException
是
扔
持久性提供程序应使用的时间长度(以毫秒为单位)
可以使用指定等待获取数据库表上的锁
javax.persistence.lock.timeout属性。如果需要时间
获取的锁超过此属性的值
LockTimeoutException
将被抛出,但当前事务
将不会标记为回滚如果此属性设置为0,则
持久性提供程序应该抛出一个LockTimeoutException
,如果
无法立即获得锁。
如果在多个位置设置了javax.persistence.lock.timeout
,则
值将按以下顺序确定:
EntityManager
或查询方法之一的参数
@NamedQuery
注释中的设置
Persistence.createEntityManagerFactory
方法的参数
persistence.xml
部署描述符中的值
对于弹簧数据1.6或更高版本
从Spring Data JPA的1.6版开始,CRUD方法就支持@Lock
(事实上,已经有了可用的)。有关更多详细信息,请参见此
对于该版本,您只需声明以下内容:
interface WidgetRepository extends Repository<Widget, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
Widget findOne(Long id);
}
TransactionSynchronizationManager.bindResource(method, lockMode == null ? NULL : lockMode);
您可以创建一些静态锁管理器,它有一个ThreadLocal
成员变量,然后在每个存储库中使用ThreadLocal中设置的锁模式调用bindResource的每个方法周围都有一个方面。这将允许您在每个线程的基础上设置锁定模式。然后,您可以创建自己的@MethodLockMode
注释,该注释将在一个方面中包装该方法,该方面在运行该方法之前设置线程特定的锁定模式,并在运行该方法之后将其清除
资源链接:
悲观锁超时的各种示例
设置悲观锁
实体对象可以通过lock方法显式锁定:
em.lock(employee, LockModeType.PESSIMISTIC_WRITE);
第一个参数是实体对象。第二个参数是请求的锁模式
如果调用锁时没有活动事务,则会抛出TransactionRequiredException
,因为显式锁定需要活动事务
如果无法授予所请求的悲观锁,则会引发LockTimeoutException
:
- 如果另一个用户(即
由另一个EntityManager实例表示)当前持有
悲观\u写入
锁定该数据库对象
- 如果当前有另一个用户,则
悲观写入锁定请求失败
保持悲观的写入
锁定或悲观的读取
锁定
那个数据库对象
设置查询提示(作用域)
查询提示可以在以下范围内设置(从全局到本地):
对于整个持久性单元-使用persistence.xml
属性:
<properties>
<property name="javax.persistence.query.timeout" value="3000"/>
</properties>
对于EntityManager-使用createEntityManager
方法:
Map<String,Object> properties = new HashMap();
properties.put("javax.persistence.query.timeout", 4000);
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("pu", properties);
Map<String,Object> properties = new HashMap();
properties.put("javax.persistence.query.timeout", 5000);
EntityManager em = emf.createEntityManager(properties);
对于命名查询
定义-使用提示
元素:
@NamedQuery(name="Country.findAll", query="SELECT c FROM Country c",
hints={@QueryHint(name="javax.persistence.query.timeout", value="7000")})
对于特定的查询执行-使用setHint
方法(在查询执行之前):
资源链接:
您可以在Spring数据中使用:
@Lock(LockModeType.PESSIMISTIC_WRITE)
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="5000")})
Stock findById(String id)
对于SpringData1.6或更高版本,我们可以使用SpringDataJPA提供的@Lock注释
此外,还可以使用@QueryHints设置锁定超时。最初,默认CRUD方法中不支持查询提示注释,但它在fix 1.6M1之后可用。
下面是一个悲观锁的示例,悲观锁的写入模式类型为独占锁
@Lock(LockModeType.PESSIMISTIC_WRITE)
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value ="5000")})
Customer findByCustomerId(Long customerId);
javax.persistence.lock.timeout在如下所示的情况下似乎对我也不起作用:
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout",value = "15000")})
但后来我尝试了其他有效的方法。现在我不再使用@Repository和crudepository,而是使用实体管理器配置我的hbernate。使用createQuery以及锁定和设置锁定超时。此配置正在按预期工作。
我有两个事务在并行中运行,并试图在DB中锁定完全相同的行。第一个事务能够获取写锁并在释放锁之前保持锁大约10秒。同时,第二个事务尝试获取同一行上的锁,但由于javax.persistence.lock.timeout设置为15秒,所以它等待释放锁,然后获取自己的锁。因此使流序列化
@Component
public class Repository {
@PersistenceContext
private EntityManager em;
public Optional<Cache> getById(int id){
List<Cache> list = em.createQuery("select c from Cache c where c.id = ?1")
.setParameter(1, id)
.setHint("javax.persistence.lock.timeout", 15000)
.setLockMode(LockModeType.PESSIMISTIC_WRITE)
.getResultList();
return Optional.ofNullable(list.get(0));
}
public void save(Cache cache) {
cache = em.find(Cache.class, cache.getId());
em.merge(cache);
}
}
@组件
公共类存储库{
@持久上下文
私人实体管理者;
公共可选getById(int-id){
List List=em.createQuery(“从缓存c中选择c,其中c.id=?1”)
.setParameter(1,id)
.setHint(“javax.persistence.lock.timeout”,15000)
.setLockMode(LockModeType.悲观写入)
.getResultList();
返回可选的.ofNullable(list.get(0));
}
公共无效保存(缓存){
cache=em.find(cache.class,cache.getId());
合并(
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout",value = "15000")})
@Component
public class Repository {
@PersistenceContext
private EntityManager em;
public Optional<Cache> getById(int id){
List<Cache> list = em.createQuery("select c from Cache c where c.id = ?1")
.setParameter(1, id)
.setHint("javax.persistence.lock.timeout", 15000)
.setLockMode(LockModeType.PESSIMISTIC_WRITE)
.getResultList();
return Optional.ofNullable(list.get(0));
}
public void save(Cache cache) {
cache = em.find(Cache.class, cache.getId());
em.merge(cache);
}
}