Hibernate无法初始化代理 - 没有会话。

15

我的代码检索与用户相关的所有信息:

SessionFactory sessionFactory = HibernateUtilities.configureSessionFactory();
Session session = sessionFactory.openSession();
UserDetails ud = null;
Set<Address> userAddress = null;

try {
    session.beginTransaction();
    ud = (UserDetails) session.get(UserDetails.class, 1);
    userAddress = ud.getAddresses();
    session.getTransaction().commit();
} catch (HibernateException e) {
    e.printStackTrace();
    session.getTransaction().rollback();
} finally {
    session.close();
}

System.out.println(ud.getName());

for(Address addr: userAddress){
    System.out.println("State " + addr.getState());
}

ud.getAddresses()仅返回用户Address集合。

我的问题是:尽管会话已关闭,为什么ud对象仍然具有其值(例如名称)?getAddresses()UserDetails类的实例变量。但是,为什么我无法检索其值,而我可以检索UserDetails类的常规实例变量?

ud.getAddresses()是一个@EmbeddedCollection


“@EmbeddedCollection” - 你是指 @ElementCollection 吗? - Kalle Richter
3个回答

20

我在JPA / Hibernate中遇到了同样的问题,解决此问题有两种方法:

1/ 默认情况下关闭LAZY,如下所示:

@Entity
@Proxy(lazy = false)
public class Project {
...
}  

当然,由于性能问题,不推荐使用这种方法,所以您可以尝试第二种方法。

2/ 您可以在方法的开头加上 @Transactional,它可以帮助您保留会话,或者换一种理解,将会话的责任传递给 Hibernate,如下所示:

@Test
@Transactional
public void testSaveGroup() {
    Department g = new Department();
    g.setName("XDG");
    assertNull(g.getId());
    this.groupRepo.save(g);
    assertNotNull(g.getId());
    System.out.println(g.getId());
    Project dummyPrj = new Project(123L, "KSTA", new Date(), "NEW", "Helm AG", g);
    this.projectRepo.save(dummyPrj);
    // verify
    List<Department> lst = this.groupRepo.findAll();
    Project savedPrj = this.projectRepo.getOne(123L);
    Assert.assertEquals("XDG", savedPrj.getGroup().getName());
}

我的回答有点晚,但希望能帮助到其他人 :)


17
userAddress = ud.getAddresses();
session.getTransaction().commit();
for(Address addr: userAddress) {

在Hibernate文档中,关于处理延迟加载关联的部分明确指出这种访问方式是错误的。您只能在会话仍然打开的情况下与延迟关联对象交互。该文档的这一部分还提供了访问对象的延迟关联成员的替代方法,我们更喜欢在应用程序中使用JOIN模式来指定所使用的条件。


1
从外观上看,当我调用ud.getAddresses()时,它实际上正在查询数据库? - KyelJmD

4

所有类的原始属性都会立即加载,除非您使用了字节码增强,否则它们不能延迟加载。只有真正的关联,例如您的集合,才能进行延迟加载。


另一个类怎么样?这被认为是一种延迟初始化吗? - KyelJmD
如果涉及到MTO,那就是“是”的;而如果是涉及到OTO,那就是“可能的”。 - Stanislav Bashkyrtsev
即使会话已关闭,我是否可以在UD内访问其他实体,比如说我有一个一对多的关系? - KyelJmD
几个选项:1.立即加载关联 2.打开另一个会话并通过merge()saveOrUpdate()重新附加对象 3.不要关闭会话(这个非常棘手) - Stanislav Bashkyrtsev
你如何加载关联? - KyelJmD
1
使用fetch="join"或在HQL中使用joins。或者使用lazy="false"。 - Stanislav Bashkyrtsev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接