2014-04-09 56 views
0

我知道多個原因可以觸發OptimistickLockException,但是當前的測試用例要求兩個事務同時寫入相同的數據以觸發異常。更喜歡通過並行事務創建讀/寫違規問題。這是我做過什麼:如何通過並行事務生成OptimistickLockException?

  1. 在測試類,創建一個私有字段來保存交易和一些事務性的方法:

    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)製作parallel transactions和(2)再現OptimistickLockException

回答

1

要重現樂觀鎖定異常,請嘗試從本身不是事務性的方法運行代碼。例如,調用一個讀取和修改實體的方法,並返回一個分離的副本。

然後調用相同的方法修改相同的實體,並返回一個新的分離副本。與數據庫相比,現在的第一個副本是陳舊的。嘗試將第一個陳舊副本合併到一個會話中,它會拋出樂觀鎖定異常。

。這是一個版本實體一些示例代碼:

@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 ... 
}