java - 由于在 @Transactional 方法中使用带有 Hibernate、Spring 和 CrudRepository 接口(interface)的 JPA 关闭 session 导致延迟加载异常

标签 java spring hibernate jpa persistence

由于以下异常,我目前遇到延迟加载无法处理双向实体关系的问题:

    org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: sample.Person.sent, no session or session was closed
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:394)
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:386)
at org.hibernate.collection.internal.AbstractPersistentCollection.readElementExistence(AbstractPersistentCollection.java:161)
at org.hibernate.collection.internal.PersistentBag.contains(PersistentBag.java:256)
at sample.EmailTest.testTest(EmailTest.java:47)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80)
at org.testng.internal.MethodInvocationHelper$1.runTestMethod(MethodInvocationHelper.java:169)
at org.springframework.test.context.testng.AbstractTestNGSpringContextTests.run(AbstractTestNGSpringContextTests.java:158)

我有以下示例实体类:

电子邮件

@Entity
public class Email {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

private String subject;

@ManyToOne(fetch = FetchType.EAGER)
private Person sender;

@ManyToMany(fetch = FetchType.EAGER)
private List<Person> recipients;

... setters/getters/constructors/equals/hashcode

@Entity
public class Person {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

@Column(unique = true)
private String name;

@OneToMany(mappedBy = "sender")
private List<Email> sent;

@ManyToMany(mappedBy = "recipients")
private List<Email> received;

... setters/getters/constructors/equals/hashcode

以下存储库:

电子邮件存储库

import org.springframework.data.repository.CrudRepository;

public interface EmailRepository extends CrudRepository<Email, Long> {
}

个人资料库

import org.springframework.data.repository.CrudRepository;

public interface PersonRepository extends CrudRepository<Person, Long> {
}

持久性.xml:

<persistence-unit name="unit_test">
    <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
        <property name="hibernate.connection.url" value="jdbc:hsqldb:mem:spring" />
        <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" />
        <property name="hibernate.connection.username" value="sa" />
        <property name="hibernate.connection.password" value="" />

        <property name="hibernate.hbm2ddl.auto" value="create-drop" />
        <property name="hibernate.show_sql" value="true" />
        <property name="hibernate.format_sql" value="true" />
        <property name="hibernate.use_sql_comments" value="true" />
        <property name="hibernate.cache.use_second_level_cache" value="false"/>
        <property name="hibernate.cache.use_query_cache" value="false"/>
    </properties>
</persistence-unit>

Spring application_context.xml

<jpa:repositories base-package="sample" />

<jdbc:embedded-database id="dataSource" type="HSQL" />

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="generateDdl" value="true" />
            <property name="database" value="HSQL" />
        </bean>
    </property>
    <property name="persistenceUnitName" value="unit_test" />
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />

这是产生异常的测试代码:

@ContextConfiguration(locations={"/application_context.xml"})
public class EmailTest extends AbstractTestNGSpringContextTests{

    @Autowired
    private EmailRepository emailRespository;

    @Autowired
    private PersonRepository personRepository;

    private Long fredId;

    @BeforeMethod
    public void setUp() {
        Person john = new Person("John");
        john = personRepository.save(john);
        Person fred = new Person("Fred");
        fred = personRepository.save(fred);
        Person julio = new Person("Julio");
        julio = personRepository.save(julio);

        Email mail = new Email("subject", john, Lists.newArrayList(john, fred, julio));
        emailRespository.save(mail);

        fredId = fred.getId();
    }

    @Test
    @Transactional
    public void testTest() throws Exception{
        Person fred = personRepository.findOne(fredId);
        List<Email> sent = fred.getSent();
        List<Email> received = fred.getReceived();

        sent.contains(null);
        received.contains(null);

        int i = 0;
    }
}

保存和查找似乎工作正常,但是延迟加载的集合不起作用,似乎是因为 session 已关闭,即使该方法是@Transactional。显然我遗漏了一些东西,因为我看到了其他几乎相同的样本。

编辑:添加 fetch = FetchType.EAGER 到 Email 实体,没有变化。

最佳答案

我不确定是什么关闭了 Hibernate session ,但您可以尝试将 fetch=FetchType.EAGER 添加到以下映射中:

@ManyToOne
private Person sender;

@ManyToMany
private List<Person> recipients;

关于java - 由于在 @Transactional 方法中使用带有 Hibernate、Spring 和 CrudRepository 接口(interface)的 JPA 关闭 session 导致延迟加载异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14074896/

相关文章:

java - 从 html 到 servlet

java - 如何将结果集对象与字符串进行比较?

spring - 如何从 CXF 端点调用 Spring Integration 应用程序

java - 您可以将 Controller 列表参数与 Hibernate 标准结合起来吗?

java - Spring/Hibernate - 在 Java 中不使用 @Entity 从存储过程中获取结果

java - 从三个 Android 位置提供者给出最佳位置估计的方法

java - 由于 Intent 中的 NullPointerException,Android 图库应用程序在安装后无法启动

java - Hibernate 关系加载

java - 无法配置 Spring MVC 应用程序

java - 当一列是派生值时,使用复合键关联两个表