缓存中存在javax.persistence.NoResultException对象

缓存中存在javax.persistence.NoResultException对象,java,hibernate,jpa,jboss5.x,Java,Hibernate,Jpa,Jboss5.x,我正在使用JBoss5和Hibernate 在单个会话中,我创建新的实体对象,而不是执行EntityManager.persist()。 之后(在执行flush()之前),我可以使用方法EntityManager.find()通过PK找到它,并且我看到该对象存在于缓存中(EntityManager.contains(o)返回true),但我无法通过执行namedQuery或query加载它 为什么? ================================================

我正在使用JBoss5和Hibernate

在单个会话中,我创建新的实体对象,而不是执行
EntityManager.persist()
。 之后(在执行
flush()
之前),我可以使用方法
EntityManager.find()
通过PK找到它,并且我看到该对象存在于缓存中(
EntityManager.contains(o)
返回true),但我无法通过执行namedQuery或query加载它

为什么?

========================================================================================= 我还创建了一个简单的JPA测试(没有JBoss),它可以正常工作

em.getTransaction().begin();

printAll( Participants.class, em );// prints the whole table

Participants part = new Participants();
part.setCode( "PPPPPPPPPPPP" );
em.persist( part );
printAll( Participants.class, em );  
// FIND new 
Participants p = (Participants)em.createNamedQuery("Participants.findByParticipantCode" ).setParameter( "participantCode", "PPPPPPPPPPPP" ).getSingleResult(); 

System.out.println( "NEW PARTICIPANT: " + p.toString() ); // Prints new object

em.getTransaction().rollback();

@Entity
@Table(name = "PARTICIPANTS")
@NamedQuery(name = "Participants.findByParticipantCode", query = "SELECT p FROM Participants p WHERE p.code = :participantCode ")
public class Participants implements Serializable {

    /**
     * 
     */
    @Id
    @GeneratedValue(generator="VID")
    @SequenceGenerator(name="VID",sequenceName="VID")
    @Column(name = "PARTICIPANT_ID", nullable = false)
    private Long participantId;

        @Column(name = "PARTICIPANT_CODE", nullable = false)
        private String code;

    public Long getParticipantId() {
        return participantId;
    }

    public void setParticipantId(Long participantId) {
        this.participantId = participantId;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }


    @Override
    public String toString() {
        return "ParticId: " + this.participantId + "; code: " + this.code + ";
    }
}
在转到数据库之前检查当前持久性上下文(作为一种一级缓存)。当您调用
persist()
时,您正在添加到该上下文中

下面是
find()
javadoc(我的重点):

按主键查找。搜索指定类和主键的实体如果实体实例包含在持久性上下文中,则从该上下文返回。

包含()

检查实例是否是属于当前持久性上下文的托管实体实例


相反,命名查询必须访问数据库,此时数据库对缓存实体一无所知。正如您所注意到的,您需要通过调用
flush()

将缓存与数据库同步。Hibernate的第一级和第二级缓存根据对象的标识符存储对象。由于这个原因,缓存在一般情况下不能真正用于查询。首先,Hibernate总是需要在数据库上执行查询以检索匹配实体的ID。这个查询的结果(此时)只是一个ID列表!只有在此之后,Hibernate才能使用缓存并通过对象的ID查找对象。如果不调用刷新,您的查询将不返回ID,因此缓存甚至不会被触动。

请发布代码的相关部分,而不是描述代码。这将非常困难,因为我的代码包含多个文件,并且包含大量未使用的详细信息,但是我试着在原则上这样做,这更好:)讨论一个人对自己代码的假设通常是毫无意义的。真相就在代码本身。我已经浏览了代码,在我看来,您正在查询两个不同的东西:当您在第一次查询中使用
doc.getDocId
时,您使用
dh.docHistId
。这可能会导致不同的SQL语句。你检查过你的参数了吗?两个查询都应该使用第二个lvl缓存,因此我无法想象两个等价的查询会返回不同的结果。关于第二个(工作)示例,我的理论是“某物”(序列生成器或
printAll
方法)刷新上下文,从而在数据库中创建实体。在调用
createNamedQuery
之前中断代码,并检查该值是否出现在数据库中。将所有调试放在一边:您在jboss案例中看到的是预期行为。JPA提供程序具有内部管理的上下文,其中可能包含“未完成”的实体。除非您
commit()
/
flush()
,否则您的查询不需要使用这些实体,因为它们没有被数据库检查过;em.contains(dh);//返回trueI还尝试使用相同的数据库进行测试,但没有Jboss,我使用hibernate 4.3.4创建简单的JPA项目,并尝试在使用事务之前创建对象、执行持久化和执行查询。。。在这种情况下,查询返回newobject@user不确定您的jpa项目,您是否可以编辑您的问题以包括persist、query、commit序列?我的问题包含该序列,我创建新对象并修改exesting对象,在进行查询后,如果没有抛出exeception,我仅在所有逻辑的末尾执行commit。持续->合并->查询。。。。提交(刷新)@user请发布您的代码,然后。您是否在方法执行期间检查了数据库状态?可能是您的示例项目在最终提交之前导致了刷新。是否有方法执行查询并从缓存中获取数据?否,查询始终在数据库上执行。您所描述的是JPA/Hibernate的正常行为。
em.getTransaction().begin();

printAll( Participants.class, em );// prints the whole table

Participants part = new Participants();
part.setCode( "PPPPPPPPPPPP" );
em.persist( part );
printAll( Participants.class, em );  
// FIND new 
Participants p = (Participants)em.createNamedQuery("Participants.findByParticipantCode" ).setParameter( "participantCode", "PPPPPPPPPPPP" ).getSingleResult(); 

System.out.println( "NEW PARTICIPANT: " + p.toString() ); // Prints new object

em.getTransaction().rollback();

@Entity
@Table(name = "PARTICIPANTS")
@NamedQuery(name = "Participants.findByParticipantCode", query = "SELECT p FROM Participants p WHERE p.code = :participantCode ")
public class Participants implements Serializable {

    /**
     * 
     */
    @Id
    @GeneratedValue(generator="VID")
    @SequenceGenerator(name="VID",sequenceName="VID")
    @Column(name = "PARTICIPANT_ID", nullable = false)
    private Long participantId;

        @Column(name = "PARTICIPANT_CODE", nullable = false)
        private String code;

    public Long getParticipantId() {
        return participantId;
    }

    public void setParticipantId(Long participantId) {
        this.participantId = participantId;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }


    @Override
    public String toString() {
        return "ParticId: " + this.participantId + "; code: " + this.code + ";
    }
}