我正在使用JBoss 5和Hibernate。
在单个会话中,我创建新的Entity对象而不是执行EntityManager.persist()
。
之后(在执行flush()
之前)我可以通过PK使用方法EntityManager.find()
找到它,我看到该对象存在于缓存中(EntityManager.contains(o)
返回true),但我无法加载它执行namedQuery或query ..
为什么?
/* I have a Entity "DocumentsHistory" and "Documents" they are related (DocumentsHistory contains docId refers to Documents.docId (PK) and Documents contains lastDhId refers to DocumentsHistory.docHistId) */
// I'm working with example of Documents - doc
// I need to create new example of DocumentsHistory and than later in the same transaction select it
// Creation of new DocumentsHistory
DocumentsHistory dh = new DocumentsHistory();
dh.setDocId(doc.getDocId); // Link with current example of Documents
dh.setType("REFF"); // set String value
dh.setRefId( id ); // set Long value
em.persit(dh); // persist new object
doc.setLastDhId(dh.docHistId);
em.merge(doc); // persist existing object
//... than later in the same transaction I'm trying to execute named Query
DocumentsHistory dh = (DocumentsHistory) em.createNamedQuery("DocumentsHistory.findByDocIdType")
.setParameter("docId", doc.getDocId())
.setParameter("type", "REFF")
.getSingleResult();
// and it throws NoResultException
// but:
em.find( DocumentsHistory.class, doc.getLastDhId() ); // returns object
=============================================== ========================================== 我还创建了一个简单的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 + ";
}
}
答案 0 :(得分:0)
EntityManager在转到数据库之前检查当前的持久性上下文(作为一种第一级缓存)。当您致电persist()
时,您正在添加该上下文。
这是find()
javadoc(强调我的):
按主键查找。搜索指定类和主键的实体。 如果实体实例包含在持久性上下文中,则从那里返回。
和contains()
:
检查实例是否是属于当前持久性上下文的托管实体实例。
相反,您的命名查询必须访问数据库,此时此数据库对您的缓存实体一无所知。如您所知,您需要通过调用flush()
来将缓存与数据库同步。
答案 1 :(得分:0)
Hibernate的第一级和第二级缓存按标识符存储对象。出于这个原因,缓存实际上不能用于查询。首先,Hibernate总是需要在数据库上执行查询以检索匹配实体的ID。此查询的结果(此时)只是一个id列表!只有在此Hibernate能够使用缓存并通过其ID查找对象之后。如果没有调用flush,则查询不会返回任何ID,因此甚至不会触及缓存。