JPA(Hibernate) - 会话/事务和延迟加载

Tim*_*Tim 2 java hibernate lazy-loading

我有一个Java EE项目,MySQL数据库是用ORM管理的.我在Hibernate上做了很多工作来了解我做错了什么,我认为我理解会话/事务,但我不知道如何在我的案例/架构中解决这个问题.

我有一个项目和一个人与一个连接表的双向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);
Run Code Online (Sandbox Code Playgroud)

但是我在这一行中收到错误:

Iterator<Project> iterator = projects.iterator();
Run Code Online (Sandbox Code Playgroud)

但它似乎与以下有关:

Person person = findPersonById(personId);
Run Code Online (Sandbox Code Playgroud)

和:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我创建一个事务,只获取person对象,但没有相应的项目.并且迭代器将尝试获取它们,但不能,因为我的事务/会话已关闭.这是因为我的架构:

我有: IPersonService - > IPersonImplementation - > IPersonDao - > 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();
}
Run Code Online (Sandbox Code Playgroud)

跟踪错误:

错误:org.hibernate.LazyInitializationException - 无法懒惰地初始化角色集合:com.testdomain.testproject.domain.Person.projects,没有关闭会话或会话org.hibernate.LazyInitializationException:懒得初始化角色集合: com.testdomain.testproject.domain.Person.projects,org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383)org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java)中没有关闭会话或会话. 375)org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:368)org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:111)位于com.testdomain.testproject.service.impl的com.testdomain.testproject.dao.impl.PersonDaoImplHibernate.removePerson(PersonDaoImplHibernate.java:71)上的org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:186) .PersonServiceImpl.removePerson(PersonServiceImpl.java:88)位于sun.reflect.NativeMethodAccessorImpl.invoke的sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)中的com.testdomain.testproject.service.PersonTest.testRemovePerson(PersonTest.java:180). (NativeMethodAccessorImpl.java:39)位于org.junit.runners.model.FrameworkMethod $ 1的java.lang.reflect.Method.invoke(Method.java:597)的sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) .runReflectiveCall(FrameworkMethod.java:44)位于org.junit.internal.runners.model.ReflectiveCallable.在org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)运行(ReflectiveCallable.java:15)org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)at org .unit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)at 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的org.junit.runners.ParentRunner.access $ 000(ParentRunner.java:42)org.junit.runners.ParentRunner $ 2.evaluate(ParentRunner.java:184).org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run上的org.junit.runners.ParentRunner.run(ParentRunner.java:236)中的internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) 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)atg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)at org .eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)删除Person失败:懒得初始化角色集合:com.testdomain.testproject.domain.Person.projects,没有会话或会话关门了没有会话或会话被关闭

Oph*_*ian 6

你真正想做的是将所有Person删除代码推送到PersonDao的remove()方法中.在该方法中,您需要执行以下操作:

  • 开始交易
  • 按id查找Person实例
  • 获取其项目集并将其从所有项目中删除
  • 删除Person实例本身
  • 提交事务

在JPA中,你不应该做更多的事情,但是我相信直接的Hibernate,你可能需要saveOrUpdate对每个项目进行更改以及删除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());
  }
}
Run Code Online (Sandbox Code Playgroud)

(注意:这大致更接近伪代码,并且未在实际IDE中进行测试)