Spring Data JPA 报错 could not initialize proxy – no Session 解决方案

在使用 SpringBoot + Spring Data JPA + Spring Security 做权限管理的时候,然后当我把one-many,many-one 这些映射关系加上懒加载的时候运行的时候报错。

Could not initialize proxy - no Session  

User.java

  1. package com.liuyanzhao.forum.entity;
  2. import lombok.Data;
  3. import org.springframework.security.core.GrantedAuthority;
  4. import org.springframework.security.core.authority.SimpleGrantedAuthority;
  5. import org.springframework.security.core.userdetails.UserDetails;
  6. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  7. import org.springframework.security.crypto.password.PasswordEncoder;
  8. import javax.persistence.*;
  9. import javax.validation.constraints.Email;
  10. import javax.validation.constraints.NotEmpty;
  11. import javax.validation.constraints.Size;
  12. import java.io.Serializable;
  13. import java.util.ArrayList;
  14. import java.util.Collection;
  15. import java.util.List;
  16. /**
  17.  * @author 言曌
  18.  * @date 2018/3/19 下午9:54
  19.  */
  20. @Entity
  21. @Data
  22. public class User implements UserDetails, Serializable {
  23.     private static final long serialVersionUID = 6147345506206285446L;
  24.     @Id // 主键
  25.     @GeneratedValue(strategy = GenerationType.IDENTITY) // 自增长策略
  26.     private Long id; // 用户的唯一标识
  27.     @NotEmpty(message = "昵称不能为空")
  28.     @Size(min = 2, max = 20, message = "昵称长度必须为2-20个字符")
  29.     @Column(nullable = false, length = 20// 映射为字段,值不能为空
  30.     private String nickname;
  31.     @NotEmpty(message = "邮箱不能为空")
  32.     @Size(max = 50, message = "邮箱长度不得超过40个字符")
  33.     @Email(message = "邮箱格式不对")
  34.     @Column(nullable = false, length = 50, unique = true)
  35.     private String email;
  36.     @NotEmpty(message = "用户名不能为空")
  37.     @Size(min = 4, max = 20, message = "用户名长度必须为4-20个字符")
  38.     @Column(nullable = false, length = 20, unique = true)
  39.     private String username; // 用户账号,用户登录时的唯一标识
  40.     @NotEmpty(message = "密码不能为空")
  41.     @Size(min = 6, max = 100, message = "密码长度必须为6-100个字符")
  42.     @Column(length = 100)
  43.     private String password; // 登录时密码
  44.     @ManyToMany(cascade = CascadeType.ALL)
  45.     @JoinTable(name = "user_authority",
  46.             joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
  47.             inverseJoinColumns = {@JoinColumn(name = "authority_id", referencedColumnName = "id")}
  48.     )
  49.     private List<Authority> authorities;
  50.     protected User() { // JPA 的规范要求无参构造函数;设为 protected 防止直接使用
  51.     }
  52.     @Override
  53.     public Collection<? extends GrantedAuthority> getAuthorities() {
  54.         //  需将 List<Authority> 转成 List<SimpleGrantedAuthority>,否则前端拿不到角色列表名称
  55.         List<SimpleGrantedAuthority> simpleAuthorities = new ArrayList<>();
  56.         for (GrantedAuthority authority : this.authorities) {
  57.             simpleAuthorities.add(new SimpleGrantedAuthority(authority.getAuthority()));
  58.         }
  59.         return simpleAuthorities;
  60.     }
  61.     public void setAuthorities(List<Authority> authorities) {
  62.         this.authorities = authorities;
  63.     }
  64.     public void setEncodePassword(String password) {
  65.         PasswordEncoder encoder = new BCryptPasswordEncoder();
  66.         String encodePasswd = encoder.encode(password);
  67.         this.password = encodePasswd;
  68.     }
  69.     @Override
  70.     public boolean isAccountNonExpired() {
  71.         return true;
  72.     }
  73.     @Override
  74.     public boolean isAccountNonLocked() {
  75.         return true;
  76.     }
  77.     @Override
  78.     public boolean isCredentialsNonExpired() {
  79.         return true;
  80.     }
  81.     @Override
  82.     public boolean isEnabled() {
  83.         return true;
  84.     }
  85. }

 

Authority.java

  1. package com.liuyanzhao.forum.entity;
  2. import lombok.Data;
  3. import org.springframework.security.core.GrantedAuthority;
  4. import javax.persistence.*;
  5. import java.util.List;
  6. /**
  7.  * @author 言曌
  8.  * @date 2018/3/21 下午7:48
  9.  */
  10. @Entity
  11. @Data
  12. public class Authority implements GrantedAuthority {
  13.     private static final long serialVersionUID = 1L;
  14.     @Id // 主键
  15.     @GeneratedValue(strategy = GenerationType.IDENTITY) // 自增长策略
  16.     private Long id; // 用户的唯一标识
  17.     @Column(nullable = false// 映射为字段,值不能为空
  18.     private String name;
  19.     @ManyToMany(mappedBy = "authorities")
  20.     private List<User> userList;
  21.     protected Authority() { // JPA 的规范要求无参构造函数;设为 protected 防止直接使用
  22.     }
  23.     @Override
  24.     public String getAuthority() {
  25.         return name;
  26.     }
  27. }

 

在启动项目后报错

Spring Data JPA  报错 could not initialize proxy - no Session 解决方案

 

然后在 CSDN 上看到这样的解释

然后去网上找资料,就是说因为 hibernate(这里是 Spring Data JPA ) 跟 spring 整合以后,hibernate 的 session 就交给 spring 管理了,请求进来的时候打开 session,请求完成的时候关闭 session。当我们想要使用懒加载去获取数据的时候,这时候原先的那个 session 已经关闭了,不能再获取数据了。由此,spring专门为这种情况作了一个过滤器 org.springframework.orm.hibernate4.support.OpenSessionInViewFilter。它可以把hibernate的session的声明周期维持在视图的开启和关闭之间。这样,只要我们这个视图没有关闭,我们就可以通过 ajax 来使用懒加载获取数据。

 

在 stackoverflow 找到了解决方案

在 application.properties 里添加如下配置,开启懒加载

  1. spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true

 

  • 微信
  • 赶快加我聊天吧
  • weinxin
  • 博客/Java交流群
  • 资源分享,问题解决,技术交流。群号:590480292
  • weinxin
言曌

发表评论

:?::razz::sad::evil::!::smile::oops::grin::eek::shock::???::cool::lol::mad::twisted::roll::wink::idea::arrow::neutral::cry::mrgreen: