我知道多种原因可以触发OptimistickLockException
,但当前的测试用例要求两个事务同时写入相同的数据才能触发异常。更像是通过并行事务创建读/写违规问题。这就是我所做的:
在测试类中,创建一个私有(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 } }
在
applicationContext.xml
中,我将上述三个方法设置为调度程序,retrieveTransactions
每60秒运行一次,processTransactionsOne
和processTransactionsTwo
每 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/