Объект сохраняется в БД, но никогда не извлекается - PullRequest
1 голос
/ 24 января 2011

Мы используем JBoss Seam с JPA и Hibernate в качестве поставщика сохраняемости.Мы столкнулись с очень странной проблемой.В нашем интерфейсе у нас есть дерево.Когда мы добавляем узел в дерево, он попадает в базу данных postgres (строка там, проверяется с помощью 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;
    }
…..
}

И OrganizationEntity:

@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 - это означает, что

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

не работает независимо от того, сколько раз мы его обновляем, но

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

работает нормально.

1 Ответ

1 голос
/ 24 января 2011

Возможно, у вас есть кэш 2-го уровня, который кэширует объекты, извлеченные из запроса (сам запрос помечен как cacheable = false, но hibernate все еще может обращаться к кешу при реализации объектов). Вы можете либо исключить родительский объект из кэша 2-го уровня после обновления (на каждом сервере, который может кэшировать эту сущность), либо использовать диспетчер сущностей, использованный в запросе, игнорировать кеш.

Чтобы выполнить последнее, перед выполнением запроса выполните следующие действия:

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

Это фактически отключает обращение к кешу для этого запроса и может быть проблемой производительности.

...