Hibernate ObjectNotFoundException不一致

时间:2013-01-22 23:27:46

标签: java hibernate

我在两个实体之间有以下一对一(可选)关系:

@Entity
@Table(name = "HLTH_RQRMT")
public class Requirement
{
    ...
    @OneToOne(mappedBy = "healthRequirement", cascade = CascadeType.ALL)
    private HealthRequirementSystemIdentifier requirementSystemId;

    ...
    public HealthRequirementSystemIdentifier getRequirementSystemId()
    {
        return requirementSystemId;
    }
}

@Entity
@Table(name = "HLTH_RQRMT_SYS_IDNTFR")
public class HealthRequirementSystemIdentifier
{

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "Hlth_Rqrmt_Id", nullable = false)
    private Requirement healthRequirement;
}

从数据库加载需求后,将检查标识符:

//Load will always return a result (or exception) - works correctly.
Requirement requirement = (Requirement) getSession().load(Requirement.class, id);

//This is where the exception is thrown
if (requirement.getRequirementSystemId() == null)

当有标识符时,代码在所有环境中都能正常工作。当没有标识符时,它在单元测试和本地工作正常(通过对生产数据库进行测试确认)。 生产中没有标识符时,会抛出以下错误:

org.hibernate.ObjectNotFoundException: No row with the given identifier exists:
[Requirement#250583] at
org.hibernate.impl.SessionFactoryImpl$2.handleEntityNotFound(SessionFactoryImpl.java:419) at
org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:154) at
org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:143) at 
org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:174) at
org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190) at
Requirement_$$_javassist_66.getRequirementSystemId(Requirement_$$_javassist_66.java) at
mypackage.myclass.processResponse(MyServiceImpl.java:244)

我可以通过将属性optional=false添加到映射注释中来触发单元测试中的上述错误。

什么可能导致单元测试和生产之间的结果不同? optional属性的默认值为true,这就是它在单元测试中正常工作的原因。 如果我添加属性optional=true,它对单元测试没有影响,但它是否可能在生产中解决问题?

我知道注释@NotFound(action=NotFoundAction.IGNORE),但我更愿意在忽略之前了解问题的原因。

1 个答案:

答案 0 :(得分:2)

您应该使用getSession.get()代替getSession().load()

如果load()无法在缓存或数据库中找到对象,则会出现异常 抛出。 load()方法永远不会返回null。 get()方法返回 如果无法找到该对象,则返回null。

  

load()方法可能返回代理而不是真正的持久性   实例。代理是占位符,触发加载   第一次访问时的真实对象;我们讨论代理   在本节后面。另一方面,get()永远不会返回   代理。

在get()和load()之间选择很简单:如果你确定持久性 对象存在,不存在将被视为异常,load()是a 不错的选择。如果您不确定是否存在给定的持久实例 标识符,使用get()并测试返回值以查看它是否为null。使用load()有 进一步暗示:应用程序可以检索到的有效引用(代理) 持久化实例,无需访问数据库即可检索其持久状态。 所以, load()在找不到持久对象时可能不会抛出异常 在缓存或数据库中;当代理时,异常将被抛出 被访问。