首页 文章

如何删除(多线程)事务Spring / JPA中的实体

提问于
浏览
1

假设有一个服务组件,使用 CrudRepositoryBook 实体 . 假设服务的一个方法应该是事务性的,并且应该(除其他外)用事务语义从数据库中删除一个实体(即,如果删除不可能执行,则应该回滚所有效果) .

大致,

@Component
public class TraService {
    @Autowired
    BookRepo repo;

    @Transactional
    public void removeLongest() {
        //some repo.find's and business logic --> Book toDel
        repo.delete(toDel);
    }
}

现在这应该在多线程环境中工作,例如在Spring MVC中 . 为简单起见,我启动了两个线程,每个线程都在一个提供了对 TraService bean的引用的任务上 . 日志显示,确实创建了两个 EntityManager 并绑定到相应的线程 . 但是,当第一个线程成功使用 delete 时,另一个线程抛出

org.springframework.orm.jpa.JpaOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1;

从中我不知道如何恢复(即我怀疑回滚未完成,并且调用事务方法后线程应该执行的代码将不会被执行) . Worker 代码:

public void run() {
   service.removeLongest();  //transactional
   System.out.println("Code progressing really well " + Thread.currentThread());  //not executed on thread with exception
}

我们如何在Spring / JPA中正确处理这样的事务 delete

1 回答

  • 2

    Short answer: 乐观锁定异常的正确行为是 Catch the exception and Retry .

    Long answer: 乐观锁定是一种假设的互斥策略

    来自:https://en.wikipedia.org/wiki/Optimistic_concurrency_control

    多个交易可以经常完成而不会相互干扰

    乐观锁定主要是因为性能而存在,并且通常使用一个字段来实现,该字段考虑了使用 version 计数器的每个修改 . 如果在事务期间 version 计数器发生更改,则表示正在进行并发修改并导致引发异常 .

    悲观锁定将阻止任何可能的并发修改,更容易管理,但性能更差 .

相关问题