繁体   English   中英

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

[英]JPA (Hibernate) - Session/Transaction and lazy loading

我有一个Java EE项目,而MySQL数据库是通过ORM管理的。 我与Hibernate一起工作很多,以了解我在做什么错,我认为我了解会话/事务,但是我不知道如何解决我的案例/体系结构。

我有一个项目和一个人与联接表处于双向n:m关系。 该项目是映射所有者。 现在,我要删除连接到项目的人员。

所以我想,我可以这样做:

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;
    }
}

在这里,我进行交易并仅获取人员对象,但没有相应的项目。 并且迭代器将尝试获取它们,但是不能,因为我的事务/会话已关闭。 这是因为我的体系结构:

我有: IPersonService-> IPersonImplementation-> IPersonDao-> IPersonDaoImplementation ,只有IPersonDaoImplementation中的方法打开和关闭事务。 因此,在我的ServicePersonImplementation中,我不能做一些与数据库相关的事情(我不想在我的@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,在org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java.org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383)上没有会话关闭。 375)at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:368)at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:111)at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java :186),位于com.testdomain.testproject.dao.impl.PersonDaoImplHibernate.removePerson(PersonDa com.testdomain.testproject.service.impl.PersonServiceImpl.removePerson(PersonServiceImpl.java:88)处的com.testdomain.testproject.service.PersonTest.testRemovePerson(PersonTest.java:180)处的oImplHibernate.java:71) .sun.reflect上的.NativeMethodAccessorImpl.invoke0(本机方法).java.lang.reflect.Method.invoke(Method上的.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)在sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) .java:597)org.junit.runners.model.FrameworkMethod $ 1.runReflectiveCall(FrameworkMethod.java:44)org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)org.junit org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)处的.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)在org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java :79),位于org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4Cla ssRunner.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 .org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)的org.junit.runners.ParentRunner.run(ParentRunner.java:236)的.ParentRunner $ 2.evaluate(ParentRunner.java:184)在org.eclipse的org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)的org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46) org.eclipse.jdt.internal上的.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.RemoteTestRunne org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)上的r.run(RemoteTestRunner.java:390)未能删除Person:无法延迟初始化角色集合:com.testdomain。 testproject.domain.Person.projects,没有会话或会话被关闭

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

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

在JPA,你不需要做任何事情还不止这些,但是我相信在直休眠您可能需要saveOrUpdate然后对每个项目进行更改以及删除的人。

因此,您的代码可能看起来像这样:

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中进行过测试)

您确实有两个选择。 第一个是在您的服务/ DAO实现中执行此操作。

projectDao.removePersonFrom(Person personToRemove, Project projectToRemoveFrom);

personDao.removeProjectFrom(Project projectToRemove, Person personToRemoveFrom);

我通常有一个与视图相关联的Model类,有时我会在其中使用某些事务性方法(我使用Spring)来完成此类工作。

- 编辑 -

在dao内部,您可以创建会话/事务,然后可以执行失败的代码。 您发布的代码应该可以正常工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM