2016-11-10 41 views
1

我正在Hibernate 4.3.8上使用Web應用程序,它看起來像persist()方法不會更新PersistentContext(高速緩存級別1)。下面是我的配置和單管理持久性的操作:Hibernate persist()不更新PersistentContext中的模型

Hibernate配置

<persistence-unit name="PersistenceUnit" transaction-type="RESOURCE_LOCAL"> 
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> 
    <properties> 
     <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/> 
     <property name="hibernate.connection.driver_class" value="org.postgresql.Driver"/> 
     <property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/irm"/> 
     <property name="hibernate.connection.username" value="nrossi"/> 
     <property name="hibernate.connection.password" value="nicolas"/> 
     <property name="hibernate.connection.pool_size" value="5"/> 
     <property name="hibernate.show_sql" value="true"/> 
     <property name="hibernate.format_sql" value="true"/> 
     <property name="hibernate.max_fetch_depth" value="5"/> 
     <property name="hibernate.hbm2ddl.auto" value="update"/> 
    </properties> 
</persistence-unit> 

持久性管理

public class PersistenceManager 
{ 
    private static final Logger log = LogManager.getLogger(); 
    private static final EntityManagerFactory emf; 
    private static final ThreadLocal<EntityManager> threadLocal; 

    static 
    { 
     emf = Persistence.createEntityManagerFactory("PersistenceUnit"); 
     threadLocal = new ThreadLocal<EntityManager>(); 
    } 

    public static EntityManager getEntityManager() 
    { 
     EntityManager em = threadLocal.get(); 

     if (em == null) 
     { 
      em = emf.createEntityManager(); 
      threadLocal.set(em); 
     } 
     return em; 
    } 

    public static <T>T get(Class<T> clazz, Object id) 
    { 
     return getEntityManager().find(clazz, id); 
    } 

    public static void save(Object object) 
    { 
     EntityManager em = getEntityManager(); 
     EntityTransaction et = em.getTransaction(); 
     et.begin(); 
     try 
     { 
      em.persist(object); 
      et.commit(); 
     } 
     catch (Exception e) 
     { 
      et.rollback(); 
      throw new RuntimeException("Error saving object", e); 
     } 
    } 
} 

我更新模型調用PersistenceManager.save(model)並更新記錄在數據庫上,但在此之後,當我調用PersistenceManager.get(model.id)時,它將使用舊值從內存返回模型。它看起來像persist方法沒有更新PersistenceCache。

順便說一下,如果我在新線程(即隱身窗口)上調用PersistenceManager.get(model.id),它將返回更新的模型。

我試着在提交之後添加一個刷新調用em.refresh(model)並且它正在工作,但我不確定這是否是更新上下文的正確方法。

更新信息 我編寫了一個簡單的JSP頁面來重現行爲。如果我更新的實體描述,並等待5' 和刷新頁面,則返回舊值:

<%@page import="com.identicum.framework.persistence.PersistenceManager"%> 
<%@page import="com.identicum.irm.core.model.Entity"%> 
<% 
    Entity entity = PersistenceManager.get(Entity.class, 1L); 
    String value = request.getParameter("entityName"); 
    if(value != null) 
    { 
     entity.setDescription(value); 
     PersistenceManager.save(entity); 
    } 
%> 
<html> 
<body> 

Entity description: <b><%= entity.getDescription() %></b> 

<br> 
<br> 

<form method="post"> 

    Enter new entity description <br> 
    <input type="text" name="entityName"/> 

    <input type="submit" /> 

</form> 


</body> 
</html> 

**新信息**

我的PersistenceManager這是suggestion的副本。我的應用程序是一個應用程序管理的EntityManager。我必須在每個請求的生命週期中訪問同一個EntityManager。這就是這種方法的原因。有沒有其他的方式來實現這一點?

+0

後的所有相關代碼,包括你在哪裏加載和更新這些實體。 –

+0

有其處理每個請求並運行下面的命令一個servlet: 1)爲了獲得模型:'PersistenceManager.get(Entity.class,ID);'和 2)更新模型: 實體實體= PersistenceManager.get(Entity.class,id); entity.setName(「B」); PersistenceManager.save(entity); PersistenceManager代碼是第一個問題。 – chupetoide

+0

嗨艾倫,我簡化了代碼,並寫了一個簡單的jsp來重現行爲。你可以在這裏找到它(https://dl.dropboxusercontent.com/u/9319179/test.jsp)。我發現問題在幾分鐘後開始。我運行jsp並向實體發佈新描述。然後等待5分鐘,我再次運行jsp(不帶參數),然後再次看到第一個描述。 – chupetoide

回答

0

首先persist()用於新實體(數據庫中沒有記錄)。 如果你想改變一個對象,你必須使用merge()。

但是,你的問題是,你可能是在一個多線程環境。 所以你不能使用ThreadLocal。每個線程都有他自己的PersistenceManager。

您使用的是什麼應用程序服務器或Web容器?

+0

這是一個Tomcat應用服務器。但問題是它看起來像新線程從PersistentContext獲取舊模型。我不確定問題是否在每個線程上都有自己的PersistenceManager。在這種情況下,我可能會遇到「性能問題」,但不是「緩存問題」。你同意嗎? – chupetoide

+0

我不認爲你會遇到性能問題。在Java EE服務器中,PersistenceContext綁定到事務。使用merge(),在更新之前不必讀取實體。 –

+0

我知道,但即使當我使用合併而不是持續時返回對象時,問題仍然是緩存 – chupetoide

0

我終於修好了,改變了我得到的方式並關閉了EntityManager。現在我從每個請求開始時(在我的Rest Dispatcher上)從EntityManagerFactory獲取EntityManager,並在最後關閉它。這樣每個請求都有自己的PersistentContext。

PersistenceMangaer.java幾乎相同。主要區別在於我刪除了EntityManagerFactory對ApplicationServiceContext的引用,我在課程外部調用setEntityManager()。這裏有一個例子:

PersistenceManager.setEntityManager(PersistenceFactory.createEntityManager); 
FooService.createObject1(); 
FooService.createObject2(); 
PersistenceManager.closeEntityManager(); 

這些鏈接,其中有利於發現問題:

Best practice to get EntityManagerFactory

Should JPA Entity Manager be closed?

http://www.objectdb.com/java/jpa/start/connection