懒加载异常:无法初始化代理 - 没有会话。

20

我使用 spring-boot(v2.0.0.RELEASE)spring-data-jpa,在MySQL上编写了一个CRUD演示程序。然而,在运行时出现了异常。以下是源代码:

源代码

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

异常细节

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)

我尝试了另一种方法 userRepository.findOne(1),它可以成功运行。


尝试在您的测试方法中添加 @Transactional... - Cepr0
1
@Cepr0 在单元测试方法中添加 @Transactional,它可以成功运行,你能否提供更多关于为什么它可以无异常运行的细节? - Shuai Junlan
4个回答

31
您可以在测试方法中添加@Transactional注解,以避免出现此异常。 getOne方法返回实体的“引用”(代理),该实体的属性可以进行延迟加载。请参见代码 - 它使用EntityManagergetReference方法。从其javadoc:

获取一个可能被延迟获取状态的实例。

在Spring中,EntityManager的实现是org.hibernate.internal.SessionImpl - 因此,没有Session,Spring无法获取此方法。
要创建会话,您只需创建一个事务即可...

但是如果我的测试使用了@Transactional注释,这是否意味着该测试仅适用于事务查询? - MiguelMunoz
1
@MiguelMunoz JpaRepository 中的每个方法都是 transactional - Cepr0
在我的情况下,将 @Transactional 添加到服务本身有所帮助。 - Katia Savina

4

你的测试应该像这样:

@RunWith(SpringRunner.class)    


@SpringBootTest
@Transactional    

public class QuestionTesting {   

    @Test    
    public void test() {    

    }    
}    

1
请尝试对答案中的所有代码使用代码块格式。https://stackoverflow.com/editing-help#code - Kin

3

只需在应用程序属性中添加spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true


1
您的答案如果能提供更多支持信息会更好。请点击[编辑]以添加更多细节,如引用或文献,以便他人确认您的答案是否正确。您可以在帮助中心找到更多关于如何撰写良好答案的信息。 - Community
以下是一些不建议这样做的建议... https://thorben-janssen.com/lazyinitializationexception/ 和 https://vladmihalcea.com/the-hibernate-enable_lazy_load_no_trans-anti-pattern/ - 更多讨论请参见此答案:https://dev59.com/w-k6XIcBkEYKwwoYC_f6#38690930 - Chris Buckett

-2
在服务类中,请使用注解@PersistenceContext添加一个实体管理器的setter方法。具体来说,请使用以下代码:
 @PersistenceContext(type = PersistenceContextType.EXTENDED)

通过这种方式,您可以访问延迟属性。


1
如果您包含您正在注释的内容,那么您的示例将更有帮助。我应该将其应用于类吗?“服务类”是什么意思? - MiguelMunoz
服务类是带有@Service注释的类。我假设您了解Spring容器和Spring类。 - KayV
问题没有服务类。 - Florens

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接