19

I use spring-data-jpa with spring-boot(v2.0.0.RELEASE), I just wrote a CRUD demo on MySQL, but an exception occurs during runtime, source code as follows:

Source code

User.java

@Entity
public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    private Integer id;
    private String username;
    private String password;

    ...getter&setter
} 

UserRepository.java

public interface UserRepository extends JpaRepository<User, Integer> {

}

UserServiceTest.java

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

    @Autowired
    private UserRepository userRepository;

    @Test
    public void getUserById() throws Exception{
        userRepository.getOne(1);
    }

}

application.yml

spring:
  datasource:
    username: ***
    password: ***
    driver-class-name: com.mysql.jdbc.Driver
    url: ********
  thymeleaf:
    cache: false
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update

Exception details

org.hibernate.LazyInitializationException: could not initialize proxy - no Session

at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:155)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:268)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:73)
at cn.shuaijunlan.sdnsecuritysystem.domain.po.User_$$_jvstc90_0.getUsername(User_$$_jvstc90_0.java)
at cn.shuaijunlan.sdnsecuritysystem.service.UserServiceTest.getUserById(UserServiceTest.java:33)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)

I try to another method userRepository.findOne(1), it can run successfully.

Coen Damen
  • 2,009
  • 5
  • 29
  • 51
Shuai Junlan
  • 535
  • 1
  • 6
  • 22

4 Answers4

31

You can add @Transactional annotation to your test method to avoid this exception.

Method getOne return the 'reference' (proxy) of the entity which properties can be lazy loaded. See it code - it uses getReference method of EntityManager. From it javadoc:

Get an instance, whose state may be lazily fetched.

In Spring the implementation of EntityManager is org.hibernate.internal.SessionImpl - so without the Session the Spring can not get this method.

To have a session you can just create a transaction...

Cepr0
  • 28,144
  • 8
  • 75
  • 101
  • But if my test uses the @Transactional annotation, doesn't that mean the test is only valid for transactional queries? – MiguelMunoz Oct 24 '20 at 00:11
  • 1
    @MiguelMunoz every method in JpaRepository is [transactional](https://github.com/spring-projects/spring-data-jpa/blob/master/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java) – Cepr0 Oct 24 '20 at 09:47
  • In my case, adding `@Transactional` to the service itself helped – Katia Savina Apr 14 '21 at 14:20
4

Your test should be like this:

@RunWith(SpringRunner.class)    


@SpringBootTest
@Transactional    

public class QuestionTesting {   

    @Test    
    public void test() {    

    }    
}    
Ryan Schaefer
  • 3,047
  • 1
  • 26
  • 46
mukesh kumar
  • 41
  • 1
  • 2
  • 1
    Please try to use code block formatting on all the code in your answer. https://stackoverflow.com/editing-help#code – Kin Aug 14 '19 at 20:21
2

just add in application properties spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true

  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Sep 28 '21 at 06:41
  • A couple of recommendations not to do this... https://thorben-janssen.com/lazyinitializationexception/ and https://vladmihalcea.com/the-hibernate-enable_lazy_load_no_trans-anti-pattern/ - more discussion on this answer: https://stackoverflow.com/a/38690930/444738 – Chris Buckett Oct 15 '21 at 08:36
-2

In the service class please add a setter for entity manager by using the annoattion @PersistenceContext. To be specific, use

 @PersistenceContext(type = PersistenceContextType.EXTENDED)

In this way, you can access lazy property.

KayV
  • 12,987
  • 11
  • 98
  • 148
  • 1
    Your example would be more helpful if you included whatever it is you're annotating. Do I apply this to the class? And what do you mean by "the service class"? – MiguelMunoz Oct 24 '20 at 00:14
  • Service class is the class having the @Service annotation. I assume you knoe spring containers and spring classes. – KayV Oct 24 '20 at 01:06
  • The question does not have a service class. – Florens Dec 30 '21 at 10:07