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

时间:2014-05-15 12:11:32

标签: java hibernate jpa jboss5.x

我正在使用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 + ";
    }
}

2 个答案:

答案 0 :(得分:0)

EntityManager在转到数据库之前检查当前的持久性上下文(作为一种第一级缓存)。当您致电persist()时,您正在添加该上下文。

这是find() javadoc(强调我的):

  

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

contains()

  

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

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

答案 1 :(得分:0)

Hibernate的第一级和第二级缓存按标识符存储对象。出于这个原因,缓存实际上不能用于查询。首先,Hibernate总是需要在数据库上执行查询以检索匹配实体的ID。此查询的结果(此时)只是一个id列表!只有在此Hibernate能够使用缓存并通过其ID查找对象之后。如果没有调用flush,则查询不会返回任何ID,因此甚至不会触及缓存。