【问题标题】:EntityManger refresh after JPQL bulk DELETE?JPA批量删除后EntityManager刷新?
【发布时间】:2012-10-13 18:11:05
【问题描述】:

在我的 Seam/Glassfish/JPA 容器中执行以下操作后:

@ApplicationScoped
public class JpaGlossaryDataAccessObject implements IGlossaryDataAccessObject {
    // ...
    @Transactional
    public void deleteColumn(String glossaryName, String columnName) {
        final GlossaryColumn column = getColumn(glossaryName, columnName);
        entityManager.remove(column);
    }
    // ...
}

请求的列已成功从数据库中删除,我可以使用 SQL 工作台进行验证。但是,当随后调用以下方法时:

@ApplicationScoped
public class JpaGlossaryDataAccessObject implements IGlossaryDataAccessObject {
    // ...
    @Transactional
    public List<Glossary> getGlossaries(Collection<String> glossaryNames) {
        glossaryNames.retainAll(getGlossaryNames());
        return entityManager.createQuery(SELECT_ALL_NAMED_GLOSSARIES, Glossary.class).setParameter(GLOSSARY_NAMES_PARAMETER_INDEX, glossaryNames).getResultList();
    }
    // ...
}

它基本上返回包含上述列的词汇表,删除的列仍在词汇表对象中!即使它们不再存在于数据库中。怎么会这样?是否需要执行一些额外的刷新才能完成这项工作?

顺便说一下,我的 beans.xml 看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:s="urn:java:ee"
    xmlns:security="urn:java:org.jboss.seam.security" xmlns:permission="urn:java:org.jboss.seam.security.permission"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://jboss.org/schema/cdi/beans_1_0.xsd">
    <alternatives />
    <decorators />
    <interceptors>
        <class>org.jboss.seam.security.SecurityInterceptor</class>
        <class>org.jboss.seam.transaction.TransactionInterceptor</class>
    </interceptors>
    <security:IdentityImpl>
        <s:modifies />
        <security:authenticatorClass>ch.diction.webportal.security.seam.authentication.ChallengeResponseIdmAuthenticatorDecorator
        </security:authenticatorClass>
    </security:IdentityImpl>
</beans>

那么,我错过了什么?

提前致谢并致以最诚挚的问候 帕斯卡

【问题讨论】:

  • 你的事务管理器是什么?
  • 我正在使用 Seam 事务拦截器,如果这就是你的意思:org.jboss.seam.transaction.TransactionInterceptor

标签: java jpa seam entitymanager transactional


【解决方案1】:

我的第一个猜测是您在内存中缓存的数据与数据库不一致。

确保在执行批量删除后清除以下 2 个缓存。缓存中的任何/所有数据都可能与数据库不一致:

  • EntityManager 缓存(即持久化上下文):entityManager.clear();
  • EntityManagerFactory 缓存(即二级缓存):
    entityManager.getCache().evictAll();
    或者 entityManagerFactory.getCache.evictAll();

理论上(但实际上不是)可以刷新缓存中的每个对象:

HashMap props = new HashMap();
// Semantically, refresh already bypasses the second level cache, no hint required. 
// But this hint says to then store the refreshed value back in the second level cache:
props.put("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH);
em.refresh(ent, props);

但这确实很麻烦,而且没有任何好处。首先,您如何遍历缓存中存储的每个实体?其次,如果您只是通过上面显示的单个调用来驱逐它们,它们会根据需要自动重新加载到刷新状态。

您的 JDBC 驱动程序甚至可以缓存数据。这取决于您的提供商和配置。

这有什么好运气吗? =:-)

【讨论】:

  • 谢谢,确实有帮助。我已经设置了相当的机制来刷新所有缓存的实体,而不是一次摆脱整个缓存。我从中得出的底线是,除非绝对必要,否则我不会将我的实体对象保留在活动持久性上下文中持续一段时间,而是让它们分离。
【解决方案2】:

EntityManager的范围是持久化上下文,可以使用entityManager.clear()

clear() : Clear the persistence context, causing all managed entities to become detached

否则,您可以在处理后关闭EntityManager,然后每次创建一个新的,这不是开销。

如果被缓存了,可以试试entityManager.getEntityManagerFactory().getCache().evictAll();

【讨论】:

    猜你喜欢
    • 2013-05-06
    • 2013-02-11
    • 2011-12-07
    • 2017-08-17
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 2015-01-03
    • 1970-01-01
    相关资源
    最近更新 更多