我试图在Java应用程序中实现一个Hibernate持久层,但我遇到了一些麻烦。每次尝试访问简单的单向关联时,我都会遇到“无代理”错误。我没有以非常正确的方式实现Hibernate——我使用的是会话控制的线程方法,他们确实建议您不要将其用于生产。但是,他们在教程中使用它。我仍在努力让基础知识发挥作用,所以我认为遵循这些教程会很好。但是,我不能让简单的关联工作。我有一个类,看起来像这样:
public class Foo {
private Long id;
private String name;
private Bar bar;
// Static Handler Methods - I'll flesh these out further down in the question.
public static List getAllFoo();
// Convenience methods
public String getBarName() {
return bar.getName();
}
// Accessor methods
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Bar getBar() {
return bar;
}
public void setBar(Bar bar) {
this.bar = bar;
}
}
foo的bar类实现为简单的单向关联。它在.hbm.xml中,如下所示:
<many-to-one name="bar" column="bar_id" not-null="true" />
我在foo内部的静态方法中创建foo,如下所示:
public static List getAllFoo() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction t = session.beginTransaction();
List foos = session.createCriteria(Foo.class).list();
t.commit();
return foos;
}
Hibernate实例配置为使用1的连接池,并使用线程方法进行会话处理,如下所示:
<property name="connection.pool_size">1</property>
<property name="current_session_context_class">thread</property>
每次尝试使用
getBarName()
对其中一个创建的对象执行函数。这是代理错误,如下所示:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:132)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:174)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
at Bar_$$_javassist_7.getName(Bar_$$_javassist_7.java)
at Foo.getBarName(Bar.java:126)
因此,长话短说,这是我开始的,也是我第一次遇到的错误。从那以后,我花了几天时间阅读了Hibernate的文档和文章,试图弄清楚如何让它工作。
我学到的是,休眠对象需要连接到一个会话。也就是说,它们是由创建的会话。当我创建我的对象时,在
getAllFoo()
这是那些对象所涉及的会话。在该会话中,BAR代理存在并有意义。但是,当我打电话的时候
t.commit()
-因为我正在使用会话处理的线程方法-我正在结束该会话。结果是当我去打电话的时候
bar.getName()
稍后,Bar现在是一个孤立的代理。它是已关闭会话的代理。
我找到了两个可能的解决方案:
1)不要关闭初始会话。不打电话就把它打开
T.()
在里面
GETALOFFULL()
.
这很管用——不过,我想我用不上。我将同时装载数千个这样的物体。他们需要在用户有思考时间的情况下长时间保持开放-但我需要能够自由地访问这些关联。将来,数据库锁可能会出现并发问题。
2)在调用关联之前将对象重新附加到新会话。
这不管用。也许我做错了-我找到的文件不清楚。我试图开始一个新的会话并调用
session.load(this, this.id)
在我进入协会之前。这样地:
public Bar getBar() {
Bar tmp = null;
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction t = session.beginTransaction();
session.load(this, this.id);
tmp = bar;
t.commit();
return tmp;
}
然后我修改了
GETBARNAMEY()
打电话
getBar()
而不是访问栏。这导致了一个新错误:
org.hibernate.PersistentObjectException: attempted to load into an instance that was already associated with the session: [Foo#1]
我想,即使在阅读了数天的教程、文章和Hibernate文档之后,我仍然不能完全理解这个结构。所以我要求StackOverflow对这个做一些说明。
首先,如果你能弄清楚,我现在拥有的代码中发生了什么?
会话是打开的还是关闭的?为什么它在第一个方法中有代理错误,但是声明会话仍然打开,对象仍然附加在第二个方法中?
第二,处理会话的正确方法是什么——我如何真正做到这一点?
我想使用的方式是按请求进行会话——这似乎是最流行的,并且适用于我的情况。但是,这实际上是如何通过关联和延迟加载实现的呢?
是的,我知道我不应该使用线程方法——但是我还有一整批与jta vs thread vs managed相关的问题,这个问题已经太长了。