Java 如何在(多线程)事务性Spring/JPA中删除实体
假设存在一个服务组件,使用Java 如何在(多线程)事务性Spring/JPA中删除实体,java,spring,multithreading,hibernate,jpa,Java,Spring,Multithreading,Hibernate,Jpa,假设存在一个服务组件,使用书籍实体的crudepository。假设服务的其中一个方法应该是事务性的,并且应该(除其他外)使用事务语义从数据库中删除一个实体(即,如果无法执行删除,则应回滚所有效果) 大致上 @Component public class TraService { @Autowired BookRepo repo; @Transactional public void removeLongest() { //some repo.f
书籍
实体的crudepository
。假设服务的其中一个方法应该是事务性的,并且应该(除其他外)使用事务语义从数据库中删除一个实体(即,如果无法执行删除,则应回滚所有效果)
大致上
@Component
public class TraService {
@Autowired
BookRepo repo;
@Transactional
public void removeLongest() {
//some repo.find's and business logic --> Book toDel
repo.delete(toDel);
}
}
现在,这应该可以在多线程上下文中工作,例如在SpringMVC中。为了简单起见,我启动了两个线程,每个线程都在一个任务上,该任务提供了对TraService
bean的引用。日志显示,确实创建了两个EntityManager
s并绑定到各自的线程。但是,由于第一个线程成功地执行了delete
,另一个线程抛出
org.springframework.orm.jpa.JpaOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1;
我不知道如何从中恢复(也就是说,我怀疑回滚没有完成,并且线程在调用事务方法后应该执行的代码将不会执行)。工人代码:
public void run(){
service.removeLongest();//事务性
System.out.println(“代码进展非常顺利”+Thread.currentThread());//线程上未执行异常
}
我们如何在Spring/JPA中正确处理此类事务性
delete
s?简短回答:乐观锁异常的正确行为是捕获异常并重试
详细回答:乐观锁定是一种互斥策略,假设
发件人:
多个事务可以在不相互干扰的情况下频繁完成
乐观锁定的存在主要是因为性能,通常使用一个字段来实现,该字段考虑到使用版本
计数器进行的每次修改。如果在事务期间版本
计数器发生更改,则表示正在进行并发修改,并导致引发异常
相反,悲观锁定将阻止任何可能的并发修改,更易于管理,但性能更差。感谢OCC。剩下的内容:您知道吗,如果捕获
jpaooptimisticlockingfailureexception
异常,其中最外层的事务方法被称为保证,那么整个回滚就完成了(so:ACID)?如果您的方法被注释为@transactional,则抛出该级别的任何异常都将回滚事务。