java - 并行事务如何产生OptimistickLockException?

标签 java spring jakarta-ee jpa ejb

我知道多种原因可以触发OptimistickLockException,但当前的测试用例要求两个事务同时写入相同的数据才能触发异常。更像是通过并行事务创建读/写违规问题。这就是我所做的:

  1. 在测试类中,创建一个私有(private)字段来保存事务和一些事务方法:

    private List<Transaction> transactions = new ArrayList<Transaction>();
    
    // This method only generate transactions and assign
    // them to the member field
    @Transactional 
    public void retrieveTransactions(){
        transactions = generateTransactions(); // generateTransactions() is transactional
    }
    
    // Following two methods just write those
    // transactions into same summery, only the first one sleeps
    // during the process to make sure the second transaction
    // can occur in a parallel way
    @Transactional
    public void processTransactionsOne(){
        for(Transaction transaction:transactions){
            logger.info("====Transaction One=====");
            transaction.writeToSameSummary(); // writeToSameSummary() is transactional
            try {Thread.sleep(10000); } // sleep for 10 seconds before commit
            catch(InterruptedException ex) {}
        }
    }
    @Transactional
    public void processTransactionsTwo(){
        for(Transaction transaction:transactions){
            logger.info("====Transaction Two=====");
            transaction.writeToSameSummary(); // writeToSameSummary() is transactional
        }
    }
    
  2. applicationContext.xml中,我将上述三个方法设置为调度程序,retrieveTransactions每60秒运行一次,processTransactionsOneprocessTransactionsTwo 每 10 秒运行一次

    <task:scheduled ref="testBeanName" method="retrieveTransactions" cron="*/60 * * * * *"/>
    <task:scheduled ref="testBeanName" method="processTransactionsOne" cron="*/10 * * * * *"/>
    <task:scheduled ref="testBeanName" method="processTransactionsTwo" cron="*/10 * * * * *"/>
    

但是,我永远无法重现 OptimistickLockException 和显示的日志

====Transaction One=====
====Transaction One=====
====Transaction One=====
......
====Transaction Two=====
====Transaction Two=====
====Transaction Two=====

因此事务是同步运行的,而不是并行运行的。那么我如何(1)进行并行事务和(2)重现OptimistickLockException

最佳答案

要重现乐观锁定异常,请尝试从本身不是事务性的方法运行代码。例如,调用读取和修改实体的方法,并返回分离的副本。

然后调用相同的方法来修改相同的实体,并返回一个新的分离副本。与数据库相比,第一个副本现在已经过时了。尝试将第一个过时的副本合并到 session 中,它将抛出乐观锁定异常。

这是版本化实体的一些示例代码:

@Entity
public class MyEntity {
   ...
   @Version
   private Long version;
}

这是读取并返回分离实体的服务示例:

@Repository
public class SomeRepository {
    @PersistenceContext
    EntityManager em;

    @Transactional
    public MyEntity readAndModify(Long key) {
        MyEntity myEntity = em.find( key, MyEntity.class);
        myEntity.setSomeField(...); // this will trigger update via dirty checking
        return myEntity;
    }
}

测试中的这段代码可以触发乐观锁定异常:

public someNonTransactionalTest() {
    //read and modify entity, get detached copy
    MyEntity detachedCopy1 = someRepository.readAndModify(1L); 

    //read and modify entity, get another detached copy - copy 1 is stale now
    MyEntity detachedCopy2 = someRepository.readAndModify(1L); 

    // try to merge the stale copy to a session, the optimistic locking exception is thrown
    detachedCopy1 = entityManager.merge(detachedCopy1);

    ... assertions ...
} 

关于java - 并行事务如何产生OptimistickLockException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22966928/

相关文章:

session - 如何在用户单击返回时显示自定义 session 过期页面?

java - 升级到 gradle 4.x 后 - 无法解决 JEE 项目的警告

java - Eclipse Mars 与 WAS Liberty 服务器 8.5.5.6 集成无法识别某些 Java EE 6 安装的功能

java - JPA2 刷新缓存中的 CacheConcurrencyStrategy.READ_ONLY

java - AnnotationException 引用的属性不是 (One|Many)ToOne

java - apache qpid 与 spring boot 的集成

spring - 如何使用@ResponseBody 返回一个 map<string, string>?

java - JAVA中的GridBagLayout问题

java - 上传文件大小超过限制时如何取消表单提交?

java - java中如何重写一个方法然后调用父类(super class)方法