我有一个Java EE项目,MySQL数据库是用ORM管理的。我在Hibernate上做了很多工作来了解我做错了什么,我认为我理解会话/事务,但我不知道如何在我的案例/架构中解决这个问题。
我有一个Project和一个Person,它与一个连接表是双向的n:m关系。该项目是地图所有者。现在我想删除一个连接到Project的Person。
所以我想,我可以这样做:
Person person = findPersonById(personId);
Set<Project> projects = person.getProjects();
Iterator<Project> iterator = projects.iterator();
while (iterator.hasNext()) {
Project project = iterator.next();
if (project.getPersons().contains(person)) {
project.getPersons().remove(person);
projectDao.updateProject(project);
}
}
personDao.removePerson(personId);
但我在这一行中收到错误:
Iterator<Project> iterator = projects.iterator();
但它似乎与:
有关Person person = findPersonById(personId);
和
public Person findPersonById(int personId) {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session sess = sessionFactory.getCurrentSession();
Transaction tx = sess.beginTransaction();
try {
Person person = (Person)sess.createQuery("from Person where id = "+personId).list().get(0);
tx.commit();
return person;
}
catch (IndexOutOfBoundsException ex) {
return null;
}
}
这里我创建一个事务并且只获取person对象,但是没有相应的项目。并且迭代器将尝试获取它们,但不能,因为我的事务/会话已关闭。 这是因为我的架构:
我有: IPersonService - &gt; IPersonImplementation - &gt; IPersonDao - &gt; IPersonDaoImplementation 并且只有IPersonDaoImplementation中的方法才能打开和关闭事务。所以在我的ServicePersonImplementation中我不能做几个与DB相关的东西(我不想在我的@ManyToMany注释中使用FetchType.EAGER,因为这会加载到很多不需要的东西)。因为一旦它从我的DaoImplementation返回,我就无法对返回的人执行其他操作(在我的情况下,获取与此人合并的所有项目)。
那么在我的情况下我能做些什么呢?
最诚挚的问候蒂姆。
更新: PersonDaoImpl,删除方法:
public void removePerson(int personId){
Person p = findPersonById(personId);
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session sess = sessionFactory.getCurrentSession();
Transaction tx = sess.beginTransaction();
sess.delete(p);
sess.flush();
tx.commit();
}
跟踪错误:
错误:org.hibernate.LazyInitializationException - 无法懒惰地初始化角色集合:com.testdomain.testproject.domain.Person.projects,没有关闭会话或会话 org.hibernate.LazyInitializationException:无法懒惰地初始化角色集合:com.testdomain.testproject.domain.Person.projects,没有会话或会话被关闭 at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383) at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375) 在org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:368) 在org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:111) 在org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:186) 在com.testdomain.testproject.dao.impl.PersonDaoImplHibernate.removePerson(PersonDaoImplHibernate.java:71) 在com.testdomain.testproject.service.impl.PersonServiceImpl.removePerson(PersonServiceImpl.java:88) 在com.testdomain.testproject.service.PersonTest.testRemovePerson(PersonTest.java:180) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 在java.lang.reflect.Method.invoke(Method.java:597) 在org.junit.runners.model.FrameworkMethod $ 1.runReflectiveCall(FrameworkMethod.java:44) 在org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 在org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) 在org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) 在org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79) 在org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71) 在org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49) 在org.junit.runners.ParentRunner $ 3.run(ParentRunner.java:193) 在org.junit.runners.ParentRunner $ 1.schedule(ParentRunner.java:52) 在org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) 在org.junit.runners.ParentRunner.access $ 000(ParentRunner.java:42) 在org.junit.runners.ParentRunner $ 2.evaluate(ParentRunner.java:184) 在org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) 在org.junit.runners.ParentRunner.run(ParentRunner.java:236) 在org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46) 在org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 在org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 在org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 在org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 在org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 删除Person失败:懒得初始化角色集合:com.testdomain.testproject.domain.Person.projects,没有关闭会话或会话
答案 0 :(得分:6)
您真正想要做的是将所有Person删除代码推送到PersonDao的remove()方法中。在该方法中,您需要执行以下操作:
在JPA中,你不应该做更多的事情,但我相信你可能需要saveOrUpdate
直接Hibernate,然后对每个项目进行更改以及删除Person。
所以你的代码看起来像这样:
public void removePerson(int personId) {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session sess = sessionFactory.getCurrentSession();
Transaction tx = sess.beginTransaction();
try {
Person person = (Person)sess.createQuery("from Person where id = "+personId).list().get(0);
Set<Project> projects = person.getProjects();
for (Project project : projects) {
if (project.getPersons().contains(person)) {
project.getPersons().remove(person);
sess.saveOrUpdate(project);
}
}
sess.delete(person);
tx.commit();
} catch (Exception e) {
System.err.println("Failed deleting Person: "+e.getMessage());
}
}
(注意:这大致更接近伪代码,并且尚未在实际的IDE中进行测试)
答案 1 :(得分:1)
你真的有两种选择。第一个是在服务/ DAO实现中执行此操作。
projectDao.removePersonFrom(Person personToRemove, Project projectToRemoveFrom);
personDao.removeProjectFrom(Project projectToRemove, Person personToRemoveFrom);
我通常有一个与视图相关联的Model类,有时候我会在事务中使用某些方法(我使用Spring)来做这种事情。
- 编辑 -
在daos中创建会话/事务,然后您可以执行失败的代码。您发布的代码应该可以正常工作。