【问题标题】:Entity is saved in DB, but never gets fetched实体保存在数据库中,但永远不会被获取
【发布时间】:2011-01-24 11:10:33
【问题描述】:

我们将 JBoss Seam 与 JPA 和 Hibernate 一起用作持久性提供程序。我们遇到了一个非常奇怪的问题。 在我们的 UI 中,我们有一棵树。当我们向树中添加一个节点时,该节点会到达 postgres DB(行在那里,用 pgadmin 检查)。但是树没有改变。与子节点一起获取节点的命名查询(下面的OrganizationEntity.FIND_BY_ISDELETED_MAIN)似乎无法正常工作。新创建的对象应该出现在OrganizationEntity.childOrganizations 下 - 但它没有。 FetchType.EAGER 无济于事,会话刷新也无济于事。

最可笑的是,大约半小时后,查询开始返回正确的结果!怎么会这样? hibernate 中是否有任何缓存需要清除或调整?

提前致谢!

用户界面树:

<rich:tree id="OrgTrees" switchType="ajax" ignoreDupResponses="true">
            <rich:recursiveTreeNodesAdaptor
                roots="#{organizationServiceBean.getOrgTree()}" var="item"
                nodes="#{item.childOrganizations}"> 
                <rich:treeNode>
                    <a4j:commandLink value="#{item.fname}" ajaxSingle="true"
                        reRender="organizationViewForm,OrgTree"
                        onclick="this.disabled=true; if(g_flagChanges){if(confirm('Save changes?')){ updateCheck()} else{this.disabled=false;}}"
                        oncomplete="this.disabled=false; g_flagChanges=false;">
                        <f:setPropertyActionListener
                            target="#{organizationBean4.selectedOrganization}"
                            value="#{item}" />
                        <a4j:support event="onclick" />
                    </a4j:commandLink>

                </rich:treeNode>
            </rich:recursiveTreeNodesAdaptor>
</rich:tree>

OrganizationServiceBean 如下所示:

@Stateless
@Scope(ScopeType.EVENT)
@Name("organizationServiceBean")
public class OrganizationServiceBeanImpl implements OrganizationServiceBean, Serializable {
...
    public List<OrganizationEntity> getOrgTree() {
        return organizationService.findByIsDeletedMain(0);
    }

}

organizationService 如下:

@Stateless
@AutoCreate
@Scope(ScopeType.STATELESS)
@Name("organizationService")
public class OrganizationServiceImpl extends
        GenericServiceImpl<OrganizationEntity> implements OrganizationService {
……
    public List<OrganizationEntity> findByIsDeletedMain(int isDeleted) {
        //entityManager.flush();
        List<OrganizationEntity> lOrg = findByCriteria(isDeleted, OrganizationEntity.FIND_BY_ISDELETED_MAIN);
        log.info("search finished...");
        return lOrg;
    }
….
    @SuppressWarnings("unchecked")
    private List<OrganizationEntity> findByCriteria(Object searchKey,
            String namedQuery) {

        final Query query = entityManager.createNamedQuery(namedQuery);
        query.setParameter("searchKey", searchKey);
        List<OrganizationEntity> organizations = null;
        try {
            organizations = (List<OrganizationEntity>) query.getResultList();
        } catch (Exception e) {
            LOGGER.error(e.getMessage());
        } 
        return organizations;
    }
…..
}

和组织实体:

@Entity
@Table(name = "organization", uniqueConstraints = { @UniqueConstraint(columnNames = "fname") })
@NamedQueries( {
….

        @NamedQuery(name = OrganizationEntity.FIND_BY_ISDELETED_MAIN, query = "select org from OrganizationEntity org where org.isdeleted = :searchKey and org.parentOrganization is null order by org.id", hints={@QueryHint(name="org.hibernate.cacheable",value="false")}),
….})
@Name("organizationEntity")
public class OrganizationEntity extends AbstractEntity {

    private static final long serialVersionUID = -9085028098941577562L;

    ….
    public static final String FIND_BY_ISDELETED_MAIN = "OrganizationEntity.findByIsDeleted";
    ….
    // bi-directional many-to-one association to Organization
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "parent_id")
    private OrganizationEntity parentOrganization;

    // bi-directional many-to-one association to Organization
    @OneToMany(mappedBy = "parentOrganization", cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
    @Where(clause="isdeleted = 0")
    private List<OrganizationEntity> childOrganizations;
}

编辑

如果我们从 url 中删除对话 ID,该功能就可以正常工作 - 这意味着

http://localhost:8080/h2p2/admin/admin.seam?cid=7

无论我们刷新多少次都不起作用,但是

http://localhost:8080/h2p2/admin/admin.seam

工作正常。

【问题讨论】:

  • 你检查过事务处理和缓存吗?
  • 只是为了确定您的问题是:您为一个(子)组织设置了 isDeleted 标志,并且它保留在父组织中。 - 这是正确的吗?
  • 我是否理解正确,您直接从 jsf 页面调用 EJB 而无需面对支持 bean?
  • @Ralph:我们将子组织添加到父组织,但看不到子组织。但是,如果我们添加根组织(其 parent_id == null),它会正确显示
  • @Osw:是的。那是因为我们使用了 seam,它允许从 jsf 中消除 backing beans

标签: java hibernate postgresql jpa seam


【解决方案1】:

您可能有一个二级缓存来缓存从查询中检索到的对象(查询本身被标记为 cacheable=false 但hibernate 在实现对象时仍然可以查询缓存)。您可以在更新后(在每个可能缓存了该实体的服务器上)从二级缓存中逐出父对象,或者让查询中使用的实体管理器忽略缓存。

要执行后者,请在发出查询之前执行以下操作:

entityManager.setProperty("javax.persistence.cache.retrieveMode", CacheRetreiveMode.BYPASS);

这实际上禁用了查询该查询的缓存,并且可能是性能问题。

【讨论】:

  • 我不确定这是否有效,因为关系是由更改的对象维护的。
  • 这个不错,可惜没用……还有其他禁用二级缓存的方法吗?
  • @denik:如果您完全停用二级缓存,您是否检查过问题是否消失?
  • @Ralph:不,完全禁用二级缓存不会影响问题...
  • 我发现接缝对话 ID 会导致问题 - 请参阅我的编辑
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多