LazyInitializationException,对于一个 int

LazyInitializationException, for an int

带有整数字段的简单 class:

@Entity
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Table(name = "myObject")
public class MyObject 
{
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  @Column(columnDefinition = "int default 0")
  @Index(name = "refCount")
  private int refCount;

  public int getRefCount(){ return refCount; }
}

使用简单的 Utility 方法从数据库中获取对象:

Session session = SessionFactoryUtil.getCurrentSession();
Transaction tx = session.beginTransaction();

criteria.setFetchSize(1);
T object = (T) criteria.uniqueResult();

// I tried to add this line, but it made no difference
Hibernate.initialize(object);

tx.commit();
return object;

问题如下: 获取此对象后不久,我将调用 getRefCount 方法。那时我遇到以下异常:

org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:164)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:285)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
    at mypackage.MyObject_$$_javassist_1.getRefCount(MyObject_$$_javassist_1.java)

我的休眠配置文件(即 hibernate.cfg.xml)包含以下 属性:

 <property name="hibernate.current_session_context_class">thread</property>

不明白的地方: 如果这发生在一个集合上,那么我只会添加 fetch = FetchType.LAZY 注释。但是这个简单的 int 字段不是连接。为什么 int 首先会被包裹在 Proxy 中?

我尝试添加 Hibernate.initialize(object); 行,但没有任何区别。

我还尝试了 hibernate.current_session_context_class="managed" 设置。之后我不得不手动启动和停止所有会话。我在每次获取时打开它并在 finally 块中关闭它。但这也没有什么区别。

这是我的第一个 Hibernate 项目之一。我开始怀疑我是否应该在对休眠对象调用 getters 之前打开一个事务。

我没有使用 Spring,只是休眠。

编辑:实际上有第二个对象

其实还有一个父对象(我一开始觉得不重要)。此 Parent 对象包含一个 link 到 MyObject

@Entity
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Table(name = "parentObject")
public class ParentObject 
{
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  // link
  @ManyToOne(optional = false, fetch = FetchType.LAZY)
  @ElementCollection(targetClass = MyObject.class)
  @JoinColumn(name = "myObjectId")
  private MyObject myObject;

  public MyObject getMyObject(){ return myObject; }
}

发生的事情是:

  1. 一个 Parent 对象被获取
  2. parent.getMyObject() 被调用以获得一个 MyObject 实例
  3. 这个 MyObject 实例实际上是一个没有任何字段的代理。
  4. 只要我在这个 MyObject 实例上调用一个方法,我就会得到 LazyInitializationException

当我获取我的对象时,我确保存在一个会话并创建一个事务。但是在获取之后我立即关闭了交易。

我在调用 getMyObject() 或调用 getter 时没有创建事务。我想这就是问题所在。我会测试这是否有所作为。

编辑 2:

事实证明,我确实需要在事务中调用getters。但这本身还不够。

第二个问题是 Parent 对象是在已经提交的事务中获取的。结果,代理对象不再绑定到事件。我想这就是他们所说的“分离对象”。 (哈哈,我边走边学。)

我不得不通过调用 Session#update(proxy) 方法“重新附加”这个对象。现在我终于可以毫无例外地调用 getter。

// uses a transaction internally
Parent parent = MyHibernateUtil.fetch(Parent.class, ...);
MyObject object = parent.getMyObject();

...

// create a new transaction
Session session = SessionFactoryUtil.getCurrentSession();
Transaction tx = session.beginTransaction();

// reattach the object
SessionFactory.getCurrentSession().update(myObject);

int count = myObject.getRefCount();
tx.commit();

但是我从这个问题中学到的是我可能以错误的方式使用事务。我想我应该进行更长的事务,其中包含提取和对 getter 的调用。对吗?

尝试在关闭交易之前调用 getId 函数。不知道会发生什么,只是一个建议。

我想整个对象(在你的例子中是 MyObject)被代理了。您可以调用 getId 而不是 getRefCount() 吗?