【问题标题】:Hibernate persist() does not update model in PersistentContextHibernate persist() 不会更新 PersistentContext 中的模型
【发布时间】:2016-11-10 16:55:34
【问题描述】:

我在 Web 应用程序上使用 Hibernate 4.3.8,看起来 persist() 方法不会更新 PersistentContext(缓存级别 1)。这是我的配置和管理持久操作的单例:

休眠配置

<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。这就是这种方法的原因。还有其他方法可以实现吗?

【问题讨论】:

  • 发布所有相关代码,包括加载和更新这些实体的位置。
  • 有一个 servlet 处理每个请求并运行以下命令:1) 获取模型:PersistenceManager.get(Entity.class, id); 和 2) 更新模型:Entity entity = PersistenceManager.get(Entity.class , ID); entity.setName("B"); PersistenceManager.save(实体); PersistenceManager 代码在第一个问题上。
  • 嗨艾伦,我简化了代码并编写了一个简单的jsp来重现该行为。你可以找到它here。我发现问题在几分钟后开始。我运行 jsp 并向实体发布新的描述。然后我等待 5 分钟,然后我再次运行 jsp(不带参数),我再次看到第一个描述。

标签: java hibernate jpa


【解决方案1】:

首先,persist() 用于新实体(数据库中没有记录)。 如果你想改变一个对象,你必须使用merge()。

但是您的问题是您可能处于多线程环境中。 所以你不能使用 ThreadLocal。每个线程都有自己的 PersistenceManager。

您使用的是什么应用服务器或 Web 容器?

【讨论】:

  • 这是一个 Tomcat 应用服务器。但问题是看起来新线程正在从 PersistentContext 获取旧模型。我不确定问题是否在每个线程上都有自己的 PersistenceManager。在这种情况下,我可能会遇到“性能问题”,但不会遇到“缓存问题”。你同意吗?
  • 我认为您不会遇到性能问题。在 Java EE 服务器中,PersistenceContext 绑定到事务。并且使用 merge() 您不必在更新之前读取实体。
  • 我知道,但是即使我使用合并而不是持久化,问题仍然是返回对象时的缓存
【解决方案2】:

我终于修复了它,改变了获取和关闭 EntityManager 的方式。现在,我在每个请求开始时(在我的 Rest Dispatcher 上)从 EntityManagerFactory 获取 EntityManager,并在最后关闭它。这样每个请求都有自己的 PersistentContext。

PersistenceMangaer.java 几乎相同。主要区别在于我删除了对ApplicationServiceContext 的EntityManagerFactory 引用,并在类外调用了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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-26
    • 2012-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-19
    • 1970-01-01
    • 2015-04-21
    相关资源
    最近更新 更多