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,则抛出该级别的任何异常都将回滚事务。