Java Spring中带有JPA实体的LazyInitializationException
我想在我的JPA实体上从急切抓取切换到懒惰抓取,但随后我得到了一个错误。我已经尝试了很多解决方案,并且已经搜索了一段时间,寻找一个有效的解决方案-在谷歌上找不到任何有效的解决方案。。。我也不希望实体加入fetch 错误:org.hibernate.LazyInitializationException:未能延迟初始化角色集合:package.User.wallet,无法初始化代理-无会话 网络控制器文件:Java Spring中带有JPA实体的LazyInitializationException,java,spring,Java,Spring,我想在我的JPA实体上从急切抓取切换到懒惰抓取,但随后我得到了一个错误。我已经尝试了很多解决方案,并且已经搜索了一段时间,寻找一个有效的解决方案-在谷歌上找不到任何有效的解决方案。。。我也不希望实体加入fetch 错误:org.hibernate.LazyInitializationException:未能延迟初始化角色集合:package.User.wallet,无法初始化代理-无会话 网络控制器文件: @Controller public class AppController {
@Controller
public class AppController {
@GetMapping("app/")
public ModelAndView app() {
ModelAndView mv = new ModelAndView();
mv.setViewName("app/index");
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
List<Wallet> wallets = user.getWallets(); // error on this line
mv.addObject("wallets", wallets);
return mv;
}
}
@控制器
公共类AppController{
@GetMapping(“app/”)
公共模型和视图应用程序(){
ModelAndView mv=新ModelAndView();
mv.setViewName(“应用程序/索引”);
User User=(User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
List wallets=user.getWallets();//此行出错
mv.addObject(“钱包”,钱包);
返回mv;
}
}
用户文件:
@Entity
public class User {
@Id
@GeneratedValue
@Type(type="uuid-char")
private UUID id;
@Column(nullable = false)
private String email;
@Column(nullable = false)
private String firstName;
@Column(nullable = false)
private String lastName;
@Column(nullable = false)
private String password;
// FetchType.EAGER solves the error, but I can't have EAGER due to performance issues.
@OneToMany(mappedBy="user", fetch = FetchType.LAZY)
@Fetch(value = FetchMode.SUBSELECT)
private List<Wallet> wallets;
// ** getters and setters **
}
@Repository
public interface UserRepo extends JpaRepository<User, UUID> {
Optional<User> findByEmail(String email);
}
@实体
公共类用户{
@身份证
@生成值
@类型(Type=“uuid char”)
私有UUID;
@列(nullable=false)
私人字符串电子邮件;
@列(nullable=false)
私有字符串名;
@列(nullable=false)
私有字符串lastName;
@列(nullable=false)
私有字符串密码;
//FetchType.EAGER解决了错误,但由于性能问题,我无法使用EAGER。
@OneToMany(mappedBy=“user”,fetch=FetchType.LAZY)
@Fetch(值=FetchMode.SUBSELECT)
私人清单钱包;
//**接球手和接球手**
}
@存储库
公共接口UserRepo扩展了JpaRepository{
可选findByEmail(字符串电子邮件);
}
钱包文件:
@Entity
public class Wallet {
@Id
@GeneratedValue
@Type(type="uuid-char")
private UUID id;
@ManyToOne
@JoinColumn(name="user_id", nullable=false)
private User user;
@OneToOne
@JoinColumn(name="currency_id", nullable=false)
private Currency currency;
@Column(nullable = false)
private double balance;
// ** getters and setters **
}
@Repository
public interface WalletRepo extends JpaRepository<Wallet, UUID> {
Optional<Wallet> findByUserAndCurrency(User user, Currency currency);
}
@实体
公务舱钱包{
@身份证
@生成值
@类型(Type=“uuid char”)
私有UUID;
@许多酮
@JoinColumn(name=“user\u id”,nullable=false)
私人用户;
@奥内托内
@JoinColumn(name=“currency\u id”,nullable=false)
私人货币;
@列(nullable=false)
私人双平衡;
//**接球手和接球手**
}
@存储库
公共接口WalletRepo扩展了JpaRepository{
可选findByUserAndCurrency(用户、货币);
}
感谢您阅读所有这些内容,我将非常感谢您的回复。您问题的根源: 默认情况下,hibernate延迟加载集合(关系),这意味着当您在代码中使用集合时,hibernate会从数据库中获取集合,现在的问题是您正在控制器中获取集合(JPA会话关闭的地方)。这是导致异常的代码行(正在加载注释集合的位置): 并添加到您的钱包实体中:
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="user_id", nullable=false)
private User user;
尝试将
@Transactional
添加到控制器中问题的根源:
默认情况下,hibernate延迟加载集合(关系),这意味着当您在代码中使用集合时,hibernate会从数据库中获取集合,现在的问题是您正在控制器中获取集合(JPA会话关闭的地方)。这是导致异常的代码行(正在加载注释集合的位置):
并添加到您的钱包实体中:
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="user_id", nullable=false)
private User user;
尝试将
@Transactional
添加到您的控制器中您必须在AppController
类上方添加org.springframework.transaction.annotation.Transactional
,然后延迟加载将起作用
例如:
import org.springframework.transaction.annotation.Transactional;
@控制器
@交易的
公共类AppController{
@GetMapping(“app/”)
公共模型和视图应用程序(){
ModelAndView mv=新ModelAndView();
mv.setViewName(“应用程序/索引”);
User User=(User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
List wallets=user.getWallets();//此行出错
mv.addObject(“钱包”,钱包);
返回mv;
}
}
如果它不起作用,您可能没有启用事务管理(这通常由Spring Boot自动配置配置)。请尝试添加@EnableTransactionManagement
,例如,在主应用程序类上方,使用@SpringBootApplication
注释
你也可以试试下面这句话:
Hibernate.initialize(user.getWallets());
您必须在AppController
类上方添加org.springframework.transaction.annotation.Transactional
,然后延迟加载将起作用
例如:
import org.springframework.transaction.annotation.Transactional;
@控制器
@交易的
公共类AppController{
@GetMapping(“app/”)
公共模型和视图应用程序(){
ModelAndView mv=新ModelAndView();
mv.setViewName(“应用程序/索引”);
User User=(User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
List wallets=user.getWallets();//此行出错
mv.addObject(“钱包”,钱包);
返回mv;
}
}
如果它不起作用,您可能没有启用事务管理(这通常由Spring Boot自动配置配置)。请尝试添加@EnableTransactionManagement
,例如,在主应用程序类上方,使用@SpringBootApplication
注释
你也可以试试下面这句话:
Hibernate.initialize(user.getWallets());
这是由于SecurityContextHolder.getContext().getAuthentication().getPrincipal()中的用户对象
已关闭连接,即使在控制器类中注释了@Transaction
我必须像这样更改控制器类:
@GetMapping("app/")
public ModelAndView app() {
ModelAndView mv = new ModelAndView();
mv.setViewName("app/index");
UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
User user = userRepo.findByUsername(userDetails.getUsername()).orElse(null);
List<Wallet> wallets = user.getWallets(); // no error anymore
mv.addObject("wallets", wallets);
return mv;
}
@GetMapping(“app/”)
公共模型和视图应用程序(){
ModelAndView mv=新ModelAndView();
mv.setViewName(“应用程序/索引”);
用户详细信息用户详细信息
@Override
public String toString() {
return "User [id=" + id + ", email=" + email+ ", firstName=" + firstName+ ", lastName=" + lastName + ", password=" + password+ "]";
}
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="user_id", nullable=false)
private User user;
@GetMapping("app/")
public ModelAndView app() {
ModelAndView mv = new ModelAndView();
mv.setViewName("app/index");
UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
User user = userRepo.findByUsername(userDetails.getUsername()).orElse(null);
List<Wallet> wallets = user.getWallets(); // no error anymore
mv.addObject("wallets", wallets);
return mv;
}