缓存中存在javax.persistence.NoResultException对象
我正在使用JBoss5和Hibernate 在单个会话中,我创建新的实体对象,而不是执行缓存中存在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加载它 为什么? ================================================
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 + ";
}
}