2012-05-29 83 views
4

下面的代碼工作, 但是,如果我刪除flush()和clear()調用, 然後第二次調用showTable()不顯示更新名稱「joan」,但「約翰」。JPA createQuery和清除/清除

什麼是正確的方式來實現這一點,而不調用flush()和clear()?

import java.util.List; 

import javax.persistence.EntityManager; 
import javax.persistence.PersistenceContext; 
import javax.persistence.Query; 

import org.junit.Test; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.test.context.ContextConfiguration; 
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests; 
import org.springframework.test.context.transaction.TransactionConfiguration; 
import org.springframework.transaction.annotation.Propagation; 
import org.springframework.transaction.annotation.Transactional; 

import com.example.Customer; 

@ContextConfiguration(locations = {"classpath:spring/test/spring-test.xml"}) 
@TransactionConfiguration(transactionManager = "txManager") 
public class Test extends AbstractTransactionalJUnit4SpringContextTests { 
    private final Logger log = LoggerFactory.getLogger(getClass()); 

    @PersistenceContext 
    private EntityManager entityManager; 

    @Test 
    @Transactional(propagation = Propagation.REQUIRES_NEW) 
    public void test() throws Exception { 
     Customer customer = new Customer(); 
     customer.setName("john"); 

     entityManager.persist(customer); 
     entityManager.flush(); 
     entityManager.clear(); 

     showTable(); 

     final Query query = entityManager.createQuery("update Customer c set c.name='joan'"); 
     int updateCount = query.executeUpdate(); 
     log.debug("Update count: " + updateCount); 
     entityManager.flush(); 
     entityManager.clear(); 

     showTable(); 
    } 

    public void showTable() { 
     final Query query = entityManager.createQuery("select c FROM Customer c"); 
     List<Customer> list = query.getResultList(); 
     for (Customer customer: list) { 
      log.info("customer name: " + customer.getName()); 
     } 
    } 
} 
+0

你需要_both_清空/清除呼叫,或只有一個特定的對? – jtahlborn

+0

看看這個:http://stackoverflow.com/q/4415211/738746 –

回答

5

第一個測試不應該需要刷新或清除,因爲實體管理器必須檢測查詢結果可以通過尚未保存未決的改變而受到影響。因此,在執行查詢之前,您不必flush(),甚至不需要clear()。

然而,第二個測試是不同的。您正在執行更新查詢,並且查詢完全繞過第一級緩存。他們在數據庫後面進行更改。這就是爲什麼你需要清除的原因:如果你不這樣做,選擇查詢將查找已存在於緩存中的客戶,並且將返回已緩存(但已過時)的實體。

+1

正確,第一次沖洗/清除是不需要的。然而,問題是關於什麼是更新查詢而不需要刷新/清除的正確方法,這非常容易出錯。也許有可能以某種方式禁用「第一級緩存」?或以其他方式重寫更新查詢(迭代對象和更新/合併)? –

+1

這種DML更新查詢應該很少使用。您通常通過查找它們(使用'em.find()'或select查詢)來更新實體,並修改它們的狀態。 JPA自動將更改刷新到數據庫。您的查詢將數據庫中所有客戶的名稱設置爲相同的值,這與典型用例非常相似。如果一個真正的用例需要這樣的查詢,那麼你會做你在你的問題中做的事情:在大規模更新後清除緩存。 –