Добавлен @Transactional в тест, чтобы избежать org.hibernate.LazyInitializationException no Session error.Зачем это нужно? - PullRequest
0 голосов
/ 07 мая 2019

Я пометил метод тестирования с помощью @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 {
}

1 Ответ

3 голосов
/ 08 мая 2019

Разница между getOne и findOne заключается в том, что первый всегда возвращает ленивый прокси, даже если в базе данных нет фактической строки. Ленивому прокси нужно открыть EntityManager для работы. Однако, поскольку ваш тестовый метод не выполняется в одной транзакции, EntityManager будет закрыт, как только закончится метод getOne.

Без открытия EntityManager вызовы объекта не будут выполнены, поскольку он больше не сможет получать значения из базы данных.

Чтобы решить, используйте findOne вместо getOne ИЛИ сделайте свой метод тестирования транзакционным. Последний, однако, имеет некоторые другие эффекты в вашем тестовом примере (он возвратит тот же объект из вызова findOne, так как он также будет повторно использовать один EntityManager).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...