在JPQL批量删除后EntityManager刷新?

时间:2012-10-13 18:11:06

标签: java jpa seam entitymanager transactional

在我的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);
    }
    // ...
}

从DB中成功删除了请求的列,我可以使用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>

那么,我错过了什么?

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

2 个答案:

答案 0 :(得分:1)

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

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

  • EntityManager缓存(即持久性上下文):entityManager.clear();
  • EntityManagerFactory缓存(即2级缓存):
      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驱动程序缓存数据。这取决于您的提供商和配置。

运气好吗? =: - )

答案 1 :(得分:0)

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

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

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

如果正在缓存,您可以尝试entityManager.getEntityManagerFactory().getCache().evictAll();