1

我对 Hibernate 和 LazyInitializationException 有疑问。我搜索并找到了很多答案,但我不能用它们来解决我的问题,因为我不得不说,我是 Hibernate 的新手。

我运行 JUnit 测试,以防出现以下错误:

@Test
public void testAddPerson() {
    Set<Person> persons = service.getAllPersons();

    // create new person
    Person person = new Person();
    person.setEmail("john@doe.com");
    Project testProject = serviceProj.findProjectById(1);

    HashSet<Project> lister = new HashSet<Project>();
    lister.add(testProject);
    person.setProjects(lister);
    service.addPerson(person);

    testProject.getPersons().add(person);
    ...
}

最后显示的行:

testProject.getPersons().add(person);

抛出此错误:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.doe.john.domain.Project.persons, no session or session was closed

Person 和 Project 是双向的 n:m:

人.java

@ManyToMany(mappedBy="persons")
private Set<Project> projects = new HashSet<Project>();

项目.java

@ManyToMany
@JoinTable(name = "Project_Person",
    joinColumns = {@JoinColumn(name="project_id", referencedColumnName="id")},
    inverseJoinColumns = {@JoinColumn(name="person_id", referencedColumnName="id")}
)
private Set<Person> persons = new HashSet<Person>();

所以有什么问题?

4

4 回答 4

1

问题是默认情况下,集合是延迟加载的。这意味着它实际上不会从数据库中加载,直到它被访问。为了加载它,您将需要一个活动的会话/事务。

简单的方法是将其更改为 FethType.EAGER,以确保立即填充集合。

- 更新 -

我最近遇到了同样的问题,我最终修改了我的实际服务来处理这种事情。在 ProjectService 类中声明一个 addPerson 方法。

public void addPersonTo(Project project, Person person)
{
  project = em.merge(project); //EntityManager, not sure what you are using but you get the idea hopefully
  project.addPerson(person);
}
于 2010-10-12T12:36:59.773 回答
1

将您的代码放入事务中 - 这将为您解决问题

于 2010-10-12T14:03:05.963 回答
0

你能试一下吗

person.getProjects().Add(testProject)

代替

HashSet<Project> lister = new HashSet<Project>();
lister.add(testProject);
person.setProjects(lister);

你应该这样做,否则你会吹走一个休眠管理的集合。

于 2010-10-12T12:38:54.950 回答
0

从休眠参考:

默认情况下,Hibernate3 对集合使用惰性选择获取,对单值关联使用惰性代理获取。这些默认值对于大多数应用程序中的大多数关联都是有意义的。

如果设置 hibernate.default_batch_fetch_size,Hibernate 将使用批量获取优化来进行延迟获取。这种优化也可以在更细粒度的级别上启用。

请注意,在打开的 Hibernate 会话的上下文之外访问惰性关联将导致异常。例如:

s = sessions.openSession();
Transaction tx = s.beginTransaction();

User u = (User) s.createQuery("from User u where u.name=:userName")
.setString("userName", userName).uniqueResult();
Map permissions = u.getPermissions();

tx.commit();
s.close();

Integer accessLevel = (Integer) permissions.get("accounts");  // Error!

由于 Session 关闭时权限集合未初始化,因此该集合将无法加载其状态。Hibernate 不支持分离对象的延迟初始化。这可以通过将从集合中读取的代码移动到事务提交之前来解决。

或者,您可以通过为关联映射指定lazy="false" 来使用非惰性集合或关联。但是,延迟初始化旨在用于几乎所有的集合和关联。如果您在对象模型中定义了太多非惰性关联,Hibernate 将在每个事务中将整个数据库提取到内存中。

另一方面,您可以使用本质上非惰性的联接获取,而不是在特定事务中选择获取。我们现在将解释如何自定义获取策略。在 Hibernate3 中,选择获取策略的机制对于单值关联和集合是相同的。

所以你必须在访问集合后关闭会话!

代替 :

service.addPerson(person);

testProject.getPersons().add(person);

我认为你应该有:

testProject.getPersons().add(person);
service.addPerson(person);
于 2010-10-12T12:43:19.357 回答