SPRING - JPAREPOSITORY - PESSIMISTIC_WRITE 不工作 - ORACLE 12c
SPRING - JPA REPOSITORY - PESSIMISTIC_WRITE NOT WORKING - ORACLE12c
Spring-webmvc 4.1.6 / Spring-data-jpa 1.7.2 / Oracle 12c
我的应用程序 运行在 Netbeans 中以调试模式在本地主机上运行。我使用 jetty-maven-plugin 作为服务器,并尝试测试一个用@Transactional 注释的服务方法。
服务方式。
@Transactional("primaryTransactionManager")
@Override
public JsonResponseEntity<Dinero> Cancel_Deposit(Dinero dinero, EnumComportamientosDIN comportamiento_key, Boolean fromserver) {
dateUtils = new DateRangeUtils();
List<Dinerod> detalles = dinero.getDinerods();
for (Dinerod detalle : detalles) {
Dinero origen_depo = dineroRepository.findOneByAplica(detalle.getAplica(), detalle.getAplicaid());
BigDecimal saldo_actual = origen_depo.getSaldo();
BigDecimal importe_debitado = detalle.getImporte();
saldo_actual = saldo_actual.add(importe_debitado);
origen_depo.setSaldo(saldo_actual);
dineroRepository.save(origen_depo);
}
}
JPA 存储库
@Lock(LockModeType.PESSIMISTIC_WRITE)
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "30000")})
@Query("SELECT x FROM Dinero x WHERE x.mov = :aplica AND x.movid = :aplicaid")
Dinero findOneByAplica(@Param("aplica") String aplica, @Param("aplicaid") String aplicaid);
不知道是不是我的测试方法有误,就是下面这样:
因为应用程序在本地主机上 运行ning;从同一网络上的另一台计算机,我模拟它是另一个人使用相同的应用程序。所以我运行同时在两台不同的电脑上用同样的方法,试图模拟交易崩溃。我尝试用 PESSIMISTIC_WRITE.
解决的同一个问题
但是当我运行同时从两台不同的电脑上提交web表单时,数据库中记录的独占锁定没有完成。
PESSIMISTIC_WRITE会发生什么
是什么让我头疼
我确信它工作正常。
只需启用SQL 日志记录,并检查执行的语句。它将包含 FOR UPDATE 子句,这意味着它工作得很好。
如果此功能不起作用,我自己为 Hibernate 编写的大量测试将会失败,因此我怀疑 Hibernate 是否会发布不支持此功能的版本。
您不需要 运行 使用 2 台计算机来运行它。你可以为它写一个集成测试,比如 this one.
我找到了问题的解决方案。正如你所说的 Vlad Mihalcea,在日志中我可以看到查询包含 FOR UPDATE 子句,但我也注意到执行了 2 个查询,第一个没有 FOR UPDATE 子句,它是存储在实体管理器一级缓存。第二个查询是带有 FOR UPDATE 的查询。
因此,当 2 个事务同时到达时,它们会在缓存中留下相同的实体并对其值进行脏读。
日志:
Hibernate: select dinero0_.ID as ID1_74_, dinero0_.IDCONCEPTO as IDCONCEPTO36_74_, dinero0_.ESTATUS as ESTATUS11_74_, dinero0_.FECHAEMISION as FECHAEMISION14_74_, dinero0_.MOV as MOV20_74_, dinero0_.MOVID as MOVID21_74_, dinero0_.SALDO as SALDO31_74_, from DINERO dinero0_ where dinero0_.MOV=? and dinero0_.MOVID=?
Hibernate: select ID from DINERO where ID =? for update wait 30
解决方案:
@PersistenceContext(unitName = "XUnitName")
private EntityManager em;
@Transactional("primaryTransactionManager")
@Override
public JsonResponseEntity<Dinero> Cancel_Deposit(Dinero dinero, EnumComportamientosDIN comportamiento_key, Boolean fromserver) {
dateUtils = new DateRangeUtils();
List<Dinerod> detalles = dinero.getDinerods();
for (Dinerod detalle : detalles) {
Dinero origen_depo = dineroRepository.findOneByAplica(detalle.getAplica(), detalle.getAplicaid());
em.refresh(origen_depo);
BigDecimal saldo_actual = origen_depo.getSaldo();
BigDecimal importe_debitado = detalle.getImporte();
saldo_actual = saldo_actual.add(importe_debitado);
origen_depo.setSaldo(saldo_actual);
dineroRepository.save(origen_depo);
}
}
我知道明确刷新是因为实体管理器执行了 2 个查询,一个没有 FOR UPDATE,另一个有 FOR UPDATE。
但我想知道为什么实体管理器不执行带有 FOR UPDATE 子句的单个查询。
Spring-webmvc 4.1.6 / Spring-data-jpa 1.7.2 / Oracle 12c
我的应用程序 运行在 Netbeans 中以调试模式在本地主机上运行。我使用 jetty-maven-plugin 作为服务器,并尝试测试一个用@Transactional 注释的服务方法。
服务方式。
@Transactional("primaryTransactionManager")
@Override
public JsonResponseEntity<Dinero> Cancel_Deposit(Dinero dinero, EnumComportamientosDIN comportamiento_key, Boolean fromserver) {
dateUtils = new DateRangeUtils();
List<Dinerod> detalles = dinero.getDinerods();
for (Dinerod detalle : detalles) {
Dinero origen_depo = dineroRepository.findOneByAplica(detalle.getAplica(), detalle.getAplicaid());
BigDecimal saldo_actual = origen_depo.getSaldo();
BigDecimal importe_debitado = detalle.getImporte();
saldo_actual = saldo_actual.add(importe_debitado);
origen_depo.setSaldo(saldo_actual);
dineroRepository.save(origen_depo);
}
}
JPA 存储库
@Lock(LockModeType.PESSIMISTIC_WRITE)
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "30000")})
@Query("SELECT x FROM Dinero x WHERE x.mov = :aplica AND x.movid = :aplicaid")
Dinero findOneByAplica(@Param("aplica") String aplica, @Param("aplicaid") String aplicaid);
不知道是不是我的测试方法有误,就是下面这样: 因为应用程序在本地主机上 运行ning;从同一网络上的另一台计算机,我模拟它是另一个人使用相同的应用程序。所以我运行同时在两台不同的电脑上用同样的方法,试图模拟交易崩溃。我尝试用 PESSIMISTIC_WRITE.
解决的同一个问题但是当我运行同时从两台不同的电脑上提交web表单时,数据库中记录的独占锁定没有完成。
PESSIMISTIC_WRITE会发生什么
是什么让我头疼
我确信它工作正常。
只需启用SQL 日志记录,并检查执行的语句。它将包含 FOR UPDATE 子句,这意味着它工作得很好。
如果此功能不起作用,我自己为 Hibernate 编写的大量测试将会失败,因此我怀疑 Hibernate 是否会发布不支持此功能的版本。
您不需要 运行 使用 2 台计算机来运行它。你可以为它写一个集成测试,比如 this one.
我找到了问题的解决方案。正如你所说的 Vlad Mihalcea,在日志中我可以看到查询包含 FOR UPDATE 子句,但我也注意到执行了 2 个查询,第一个没有 FOR UPDATE 子句,它是存储在实体管理器一级缓存。第二个查询是带有 FOR UPDATE 的查询。
因此,当 2 个事务同时到达时,它们会在缓存中留下相同的实体并对其值进行脏读。
日志:
Hibernate: select dinero0_.ID as ID1_74_, dinero0_.IDCONCEPTO as IDCONCEPTO36_74_, dinero0_.ESTATUS as ESTATUS11_74_, dinero0_.FECHAEMISION as FECHAEMISION14_74_, dinero0_.MOV as MOV20_74_, dinero0_.MOVID as MOVID21_74_, dinero0_.SALDO as SALDO31_74_, from DINERO dinero0_ where dinero0_.MOV=? and dinero0_.MOVID=?
Hibernate: select ID from DINERO where ID =? for update wait 30
解决方案:
@PersistenceContext(unitName = "XUnitName")
private EntityManager em;
@Transactional("primaryTransactionManager")
@Override
public JsonResponseEntity<Dinero> Cancel_Deposit(Dinero dinero, EnumComportamientosDIN comportamiento_key, Boolean fromserver) {
dateUtils = new DateRangeUtils();
List<Dinerod> detalles = dinero.getDinerods();
for (Dinerod detalle : detalles) {
Dinero origen_depo = dineroRepository.findOneByAplica(detalle.getAplica(), detalle.getAplicaid());
em.refresh(origen_depo);
BigDecimal saldo_actual = origen_depo.getSaldo();
BigDecimal importe_debitado = detalle.getImporte();
saldo_actual = saldo_actual.add(importe_debitado);
origen_depo.setSaldo(saldo_actual);
dineroRepository.save(origen_depo);
}
}
我知道明确刷新是因为实体管理器执行了 2 个查询,一个没有 FOR UPDATE,另一个有 FOR UPDATE。
但我想知道为什么实体管理器不执行带有 FOR UPDATE 子句的单个查询。