我在Spring MVC中遇到了事务问题。我在ManyToMany中有2个实体(用户,角色)。我有服务,我想得到用户的角色:
public Set<Role> getUserRoles(long id) {
Set<Role> roles = userRepository.findById(id).getRoles();
return roles;
}
我的用户类:
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "USER_ROLE", joinColumns = {
@JoinColumn(name = "ID_USER", referencedColumnName = "ID_USER") }, inverseJoinColumns = {
@JoinColumn(name = "ID_ROLE", referencedColumnName = "ID_ROLE") })
public Set<Role> getRoles() {
return roles;
}
当我在我的控制器中使用它时:
Set<Role> roles=userService.getUserRoles(1);
for (Role r : roles) {
System.out.println(r.getName());
}
我收到了一个LazyInitializationException。服务标记为@Transactional和方法
TransactionSynchronizationManager.isActualTransactionActive()
service方法中的返回true。
public Set<Role> getUserRoles(long id) {
Set<Role> roles = userRepository.findById(id).getRoles();
for (Role r : roles) {
System.out.println(r.getName());
}
return roles;
}
我注意到,当我在服务中打印角色时,我的控制器正常工作。 谢谢你的帮助
修改
在控制器中我有代码:
for (Role r : roles) {
System.out.println(r.getName());
}
当我的服务方法是:
public Set<Role> getUserRoles(long id) {
Set<Role> roles = userRepository.findById(id).getRoles();
return roles;
}
然后是System.out.println(userService.getUserRoles(1));在控制器中抛出LazyInitializationException,但是我的服务方法是:
public Set<Role> getUserRoles(long id) {
Set<Role> roles = userRepository.findById(id).getRoles();
for (Role r : roles) {
System.out.println(r.getName());
}
return roles;
}
然后是System.out.println(userService.getUserRoles(1));在控制器工作
答案 0 :(得分:1)
@Transactional
可能只在您的userService
附近。这意味着,当您退出方法时,事务将被提交。
稍后,在您的控制器上,您正在尝试检索实体的懒惰属性(用户角色)。由于您不再参与交易,因此您获得LazyInitializationException
。
如果要检索角色,请将控制器标记为@Transactional
,或检索角色eagerly
。
答案 1 :(得分:1)
@ cinek181992,正如你所观察到的,当System.out.println在它运行的服务中完成时,这是因为你在事务中,所以可以检索和打印非渴望的Role实体关系。当它尝试读取属性时,它会加载属性的数据,以便下次在控制器中读取它 这是因为它在控制器中失败,因为当服务返回并且所获得的数据上的System.out.println尝试读取尚未在事务中加载的实体属性时事务已经结束。
您的问题有一些解决方案 如果必须读取@ManyToOne关系(通常是),请将它们标记为EAGER。
有些时候,我更喜欢,最好不要使用服务层之外的实体,只将DTO发送到网络层。