JPA 查询未在列表中返回更新的结果

Posted

技术标签:

【中文标题】JPA 查询未在列表中返回更新的结果【英文标题】:JPA query not returning updated results in list 【发布时间】:2017-10-25 19:28:34 【问题描述】:

我有一个在 tomcat 中运行的 webapp 的问题,我有一个抽象的 DAO 类,它有一个名为 all() 的方法,它从数据库或 JPA 缓存中返回所有实体。它似乎在初始调用时正确返回实体,但后续调用不反映从单独的 UI 调用发生的更新,这些调用将使用实体管理器 find 方法从列表中查找特定实体,更新相关字段并提交。当我稍后通过相同的 all() 方法查看该列表时,我仍然看到原始值。如果我在日志中进行另一次更新,我可以看到值从正确的值(不是原始值)变为更新后的值,并且日志显示这些更新每次都正确发生。

我正在使用 guice 进行注射。我玩过日志记录,可以看到在整个请求中使用的实体管理器上的相同哈希码,但每个请求都不同。我玩过以下persistance.xml 文件,但似乎也无济于事......

    <property name="eclipselink.cache.shared.default" value="false" />
    <shared-cache-mode>NONE</shared-cache-mode>

我不明白为什么我的 all() 不会返回更新的结果,我还尝试添加代码以在列表中查找我正在更新的特定实体,然后通过调用以下命令替换它...

entity = em.find(Class.class, id)

这似乎解决了该特定实体的问题,因此我的查询似乎正在重用旧的。

这是我的 DAO 课程中的一个 sn-p

private final Provider<EntityManager> emP;

protected EntityManager em(boolean useTransaction) throws DaoException 
    return useTransaction ? begin() : emP.get();


public List<T> all() throws DaoException 
    EntityManager em = em(false);
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<T> cq = cb.createQuery(eClass);
    Root<T> from = cq.from(eClass);
    return em.createQuery(cq.select(from)).getResultList();


public T save(T t) throws DaoException 
    return save(t, em(true));


protected T save(T t, EntityManager em) throws DaoException 
    if (Objects.isNull(t)) 
        throw new DaoException("can't save null object: " + getDaoClass(), new NullPointerException());
    

    T saved;
    if (t.getId() > 0) 
        saved = em.merge(t);
     else 
        em.persist(t);
        saved = t;
    

    autoCommit();
    return saved;


protected void autoCommit() throws DaoException 
    if (autoCommit) 
        commit();
    


public void commit() throws DaoException 
    EntityManager em = emP.get();
    if (!em.getTransaction().isActive()) 
        throw new DaoException("transaction isn't active, unable to commit");
    

    try 
        em.getTransaction().commit();
     catch (IllegalStateException e) 
        throw new DaoException("transaction not active", e);
     catch (RollbackException e) 
        throw new DaoException("commit rolled back", e);
    

所以我想知道是否有人对为什么会发生这种情况有任何见解,或者对我还可以尝试检查什么有任何建议?

【问题讨论】:

您的 emP 可能总是返回相同的 em,它从其一级缓存返回结果。不要再认为你可以在没有事务的情况下使用 JPA,并让 EM 长时间打开。你不能。总是得到一个新的 EM,开始一个事务,做你需要做的事情(读和/或写),提交。 我现在试试这个 我更改了 EntityManager em(boolean useTransaction) 方法以忽略 useTransaction 布尔值并开始事务,然后在我的 all() 方法的末尾添加了一个提交,但它仍然产生了相同的结果。另外我没有让它保持打开状态,我正在使用 guice 注入实体管理器,该实体管理器应该使用 guice UnitOfWork 为每个请求提供新的 emP 的代码?它是如何注入的? finalemP 修饰符是必不可少的吗? 开启 eclipseLink 日志,这将显示 EntityManager 下正在使用的会话。大多数容器在注入的资源上使用包装器,因此它们可以更轻松地管理生命周期,因此您看到的哈希码可能用于包装器,而不是 EntityManager 实现工作。 【参考方案1】:

所以我找到了问题的原因。引用列表时,我在我的实体中使用了 ElementCollection 注释。我删除了注释并将其替换为 JoinTable 和 OneToMany 注释,一切正常。

我遇到的问题是该实体可以很好地存储在数据库中,并且我正在按预期更新该实体,但 JPA 已经嵌入了引用它的实体列表。

所以我看到每次返回的嵌入列表不是我更新的实际实体。我的实体现在使用正确的连接表而不是嵌入对象,并且一切都按预期运行。

【讨论】:

以上是关于JPA 查询未在列表中返回更新的结果的主要内容,如果未能解决你的问题,请参考以下文章

在 Spring Data JPA 中更新和返回数据

jpa缓存导致无法查询到更新后的数据&android出现ANR的一个解决办法

JPA 查询部分字段

JPA 未在 WildFly 16 上保存到数据库

列表未在 DestinationView 中传播更新

表未在单选查询中更新