休眠:未能初始化懒洋洋角色的集合,没有会话或会话关闭
我的代码:休眠:未能初始化懒洋洋角色的集合,没有会话或会话关闭
@Test
public void testAddRoleAndAddUser() {
Role r = roleDao.findByProperty("name", "admin");
if(r == null) {
r = new Role();
r.setName("admin");
r.setDescription("Just administrator.");
roleDao.save(r);
}
User u = dao.get(1l);
Set<Role> roles = u.getRoleSet();
logger.debug("Roles is null: " + (roles == null));
roles.add(r);
dao.save(u);
}
13:39:41,041 ERROR: org.hibernate.LazyInitializationException failed to lazily initialize a collection of role: xxx.entity.core.User.roleSet, no session or session was closed org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: xxx.entity.core.User.roleSet, no session or session was closed at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380) at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372) at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:365) at org.hibernate.collection.PersistentSet.add(PersistentSet.java:212) at sg.com.junglemedia.test.dao.impl.hibernate.UserDaoTest.testAddRoleAndAddUser(UserDaoTest.java:40) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) at org.junit.runners.ParentRunner.run(ParentRunner.java:236) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
谁能帮助?
您很可能会关闭RoleDao中的会话。如果关闭会话,然后尝试访问延迟加载对象上的字段,则会得到此异常。您可能应该在测试中打开和关闭会话/事务。
下面的代码可能会导致类似的错误:
using (var session = SessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
movie = session.Get<Movie>(movieId);
tx.Commit();
}
Assert.That(movie.Actors.Count == 1);
你可以简单地解决这个问题:
using (var session = SessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
movie = session.Get<Movie>(movieId);
Assert.That(movie.Actors.Count == 1);
tx.Commit();
}
在你的实体类,当你从用户声明映射到角色,尝试指定fetchType到EAGER。有些事情是这样的:
@OneToMany(fetch=FetchType.EAGER)
public Collection<Role> getRoleSet(){
...
}
UPDATE: 最新评论这个答案的获得让我重温这一点。从我回答开始,只有我开始使用Hibernate的时候已经有一段时间了。拉斐尔和穆库斯说的是合理的。如果你有一个很大的集合,你不应该使用预先抓取。它共同选择映射到您的条目的所有数据并加载到内存中。另一种方法是每次需要处理相关的集合时,仍然使用延迟获取并打开一个Hibernate会话,即每次需要调用getRoleSet方法时。这样,每次调用此方法时,Hibernate都会对数据库执行select查询,并且不会将收集数据保留在内存中。你可以参考我的帖子在这里的详细信息:http://khuevu.github.io/2013/01/20/understand-hibernate.html
这就是说,它可以取决于您的实际使用情况。如果您的收集数据很小并且您经常需要查询数据,那么最好使用预先抓取。我认为,就你的具体情况而言,角色集合可能非常小,适合使用预先抓取。
我面临一个类似的问题,通过映射具有多对多的集合(并且未指定获取类型)。我得到了LazyInitializationException,但是当我更改为提取类型Eager时,它正常工作。在提取类型Lazy中是否有任何错误? – vvekselva 2012-08-24 08:52:15
@vvekselva,你可以参考这个问题:http://*.com/questions/2990799/difference-between-fetchtype-lazy-and-eager-in-java-persistence – 2012-08-26 01:46:28
这不是一个解决方案,而是一个解决方法 – Rafael 2013-12-13 12:50:15
您试图加载延迟加载的集合,但休眠会话已关闭或不可用。 解决此问题的最佳解决方案,将延迟加载的对象更改为eget fetch = FetchType.EAGER加载。这个问题将解决。
这不是一个解决方案,而是一个解决方法 – Marc 2013-06-12 15:54:02
你有不同的选择来处理这个问题。它看起来像它带我们回到老好普通的SQL天:)
阅读:http://www.javacodegeeks.com/2012/07/four-solutions-to-lazyinitializationexc_05.html
你可以尝试@Transactional注释添加到您的bean或方法(如果方法中所有变量的地方声明) 。
进入这个确切的错误,并意识到我需要一个@Transactional注释(对于我的Spring测试环境),如上所述。 – 8bitme 2014-10-13 12:12:28
我遇到同样的问题,所以只是从我调用DAO方法的地方添加@Transactional注释。它只是工作。我认为问题是Hibernate不允许从数据库中检索子对象,除非在调用时特别需要所有必需的对象。
我有这个问题,特别是当实体被Jaxb + Jax-rs控制时。我用预取策略,但我也觉得这有效地提供两个实体:
- 与映射为
EAGER
所有集合 大多数或所有集合
- 简化实体修剪出全面爆发的实体
常见字段和映射在@MappedSuperclass
并且由两个实体实现扩展。
当然,如果你总是需要加载的集合,那么没有理由不去EAGER
加载它们。在我的情况下,我想要一个精简版本的实体显示在网格中。
对我来说,它的工作方式,我用eclipselink以及。只需调用应该加载的集合的size(),然后再将其用作页面的参数。
for (Entity e : entityListKeeper.getEntityList()) {
e.getListLazyLoadedEntity().size();
}
这里entityListKeeper具有实体的名单有LazyLoadedEntity的名单。 如果刚therelation实体LazyLoadedEntity的名单,然后解决方法是:在“hibernate.properties”因为我已经删除了 “hibernate.enable_lazy_load_no_trans =真”发生
getListLazyLoadedEntity().size();
在我的情况异常文件...
我做了一个复制和粘贴错字...
什么'保存(你)'做?你如何管理'Session'?你打开/关闭它在哪里? – 2010-08-19 08:21:02