交易不适用于多对多

时间:2015-09-05 15:30:01

标签: spring spring-mvc jpa

我在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));在控制器工作

2 个答案:

答案 0 :(得分:1)

@Transactional可能只在您的userService附近。这意味着,当您退出方法时,事务将被提交。

稍后,在您的控制器上,您正在尝试检索实体的懒惰属性(用户角色)。由于您不再参与交易,因此您获得LazyInitializationException

如果要检索角色,请将控制器标记为@Transactional,或检索角色eagerly

答案 1 :(得分:1)

@ cinek181992,正如你所观察到的,当System.out.println在它运行的服务中完成时,这是因为你在事务中,所以可以检索和打印非渴望的Role实体关系。当它尝试读取属性时,它会加载属性的数据,以便下次在控制器中读取它 这是因为它在控制器中失败,因为当服务返回并且所获得的数据上的System.out.println尝试读取尚未在事务中加载的实体属性时事务已经结束。

您的问题有一些解决方案 如果必须读取@ManyToOne关系(通常是),请将它们标记为EAGER。

有些时候,我更喜欢,最好不要使用服务层之外的实体,只将DTO发送到网络层。