在测试中添加了@Transactional以避免org.hibernate.LazyInitializationException no Session错误.为什么需要它? [英] Added @Transactional into a test to avoid org.hibernate.LazyInitializationException no Session error. Why is it needed?

查看:102
本文介绍了在测试中添加了@Transactional以避免org.hibernate.LazyInitializationException no Session错误.为什么需要它?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用@Transactional注释了一种测试方法,以避免:


org.hibernate.LazyInitializationException: could not initialize proxy [com....OrderEntity#6def569a-ebf2-473e-b1b1-8b67e62fd17d] - no Session

    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:169)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:309)
    at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:45)
    at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95)
    at com...orders.OrderEntity$HibernateProxy$wwLGAOuY.getDescription(Unknown Source)

我不知道为什么需要它,并且想知道我的应用程序配置是否正确.

import lombok.Getter;
import lombok.Setter;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
import java.util.UUID;

@Entity
@Table(name = "orders")
@Getter
@Setter
public class OrderEntity {

    @Id
    @GeneratedValue
    private UUID uid;
    private Date created;
    private Date updated;
    private String description;

}

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.UUID;

@Repository
public interface OrderRepository extends JpaRepository<OrderEntity, UUID> {

    List<OrderEntity> findByDescription(String description);
}

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;

@Service
@Transactional
public class OrderService
{

    private OrderRepository repository;

    @Autowired
    public OrderService(OrderRepository repository) {
        this.repository = repository;
    }

    public List<OrderEntity> findAll() {
        return repository.findAll();
    }

    public OrderEntity save(OrderEntity order) {
        return repository.save(order);
    }

    public OrderEntity getOne(UUID uid) {
        return repository.getOne(uid);
    }
}

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

import static org.junit.Assert.assertEquals;

@RunWith(SpringRunner.class)
@SpringBootTest
public class OrderServiceTest {

    @Autowired
    private OrderService service;

    @Test
    @Transactional
    public void testSave() {

        OrderEntity order = new OrderEntity();
        order.setDescription("Order description");

        OrderEntity saved = service.save(order);
        System.out.println(saved.getDescription());

        OrderEntity persisted = service.getOne(saved.getUid());
        // throws LazyInitializationException without @Transactional
        System.out.println(persisted.getDescription()); 

        assertEquals(persisted.getDescription(), order.getDescription());
    }
}

我什至添加了@EnableTransactionManagement,但没有区别:

import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
public class PersistenceJPAConfig {
}

getOnefindOne之间的区别在于,即使数据库中没有实际的行,第一个也总是返回一个惰性代理.惰性代理需要打开的EntityManager才能进行操作.但是,由于您的测试方法不在单个事务中运行,因此getOne方法结束后,EntityManager将立即关闭.

如果没有打开EntityManager,则对该对象的调用将失败,因为它无法再从数据库中检索值.

要解决此问题,请使用findOne而不是getOne,或者使您的测试方法具有事务性.但是后者会对您的测试用例产生其他影响(它会从findOne调用中返回相同的对象,因为它还会重用单个EntityManager).

I annotated a test method with @Transactional to avoid:


org.hibernate.LazyInitializationException: could not initialize proxy [com....OrderEntity#6def569a-ebf2-473e-b1b1-8b67e62fd17d] - no Session

    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:169)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:309)
    at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:45)
    at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95)
    at com...orders.OrderEntity$HibernateProxy$wwLGAOuY.getDescription(Unknown Source)

I do not know why it is needed and wonder whether my application configuration is correct.

import lombok.Getter;
import lombok.Setter;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
import java.util.UUID;

@Entity
@Table(name = "orders")
@Getter
@Setter
public class OrderEntity {

    @Id
    @GeneratedValue
    private UUID uid;
    private Date created;
    private Date updated;
    private String description;

}

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.UUID;

@Repository
public interface OrderRepository extends JpaRepository<OrderEntity, UUID> {

    List<OrderEntity> findByDescription(String description);
}

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;

@Service
@Transactional
public class OrderService
{

    private OrderRepository repository;

    @Autowired
    public OrderService(OrderRepository repository) {
        this.repository = repository;
    }

    public List<OrderEntity> findAll() {
        return repository.findAll();
    }

    public OrderEntity save(OrderEntity order) {
        return repository.save(order);
    }

    public OrderEntity getOne(UUID uid) {
        return repository.getOne(uid);
    }
}

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

import static org.junit.Assert.assertEquals;

@RunWith(SpringRunner.class)
@SpringBootTest
public class OrderServiceTest {

    @Autowired
    private OrderService service;

    @Test
    @Transactional
    public void testSave() {

        OrderEntity order = new OrderEntity();
        order.setDescription("Order description");

        OrderEntity saved = service.save(order);
        System.out.println(saved.getDescription());

        OrderEntity persisted = service.getOne(saved.getUid());
        // throws LazyInitializationException without @Transactional
        System.out.println(persisted.getDescription()); 

        assertEquals(persisted.getDescription(), order.getDescription());
    }
}

I even added @EnableTransactionManagement but it makes no difference:

import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
public class PersistenceJPAConfig {
}

解决方案

The difference between getOne and findOne is that the first always returns a lazy proxy, even if there is no actual row in the database. The lazy proxy needs an open EntityManager to operate on. However as your test method doesn't run in a single transaction the EntityManager will be closed as soon as the getOnemethod ends.

Without an open EntityManager calls on the object will fail as it cannot retrieve the values from the database anymore.

To solve use findOne instead of getOne OR make your test method transactional. The latter however has some other effects on your test-case (it will return the same object from the findOne call as it will also reuse a single EntityManager).

这篇关于在测试中添加了@Transactional以避免org.hibernate.LazyInitializationException no Session错误.为什么需要它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆