繁体   English   中英

Spring Boot和fetchType = Lazy

[英]Spring Boot and fetchType=Lazy

我的Spring Boot应用程序中的延迟初始化有问题。 我有一个具有惰性字段Role的实体,我在My Spring Security( UserDetailsService )方法中有LazyInitializationException ,但在控制器中它没问题。 你能解释一下Spring Boot如何使用fetch = FetchType.LAZY吗? 为什么它不起作用Spring Security UserDetailsService并在控制器方法中工作? 我没有找到任何关于此的指南。 谢谢!

春季靴子:

@SpringBootApplication
public class App {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(App.class, args);
    }
}

实体:

@Entity
@Table(name = "users")
@Getter
@Setter
@NoArgsConstructor
public class Users {
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "Users_Role", joinColumns = @JoinColumn(name = "User_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"))
    private Set<Role> roles = new HashSet<Role>();
}

我的服务:

@Transactional(readOnly = true)//does not matter
 public Users getUserByLogin(String login) {
        return usersRepository.findOneByLogin(login);
    }

    @Transactional(readOnly = true)
    public Users getUserByLoginWithRoles(String login) {
        Users oneByLogin = usersRepository.findOneByLogin(login);
        logger.debug("User was initialize with Roles: " + oneByLogin.getRoles().size()); // force initialize of roles and it works!
        return oneByLogin;
    }

   @Transactional(readOnly = true)//does not matter
    public Users testGetUser() {
        Users oneByLogin = usersRepository.getOne(1L);
        return oneByLogin;
    }

    @Transactional(readOnly = true)//does not matter
    public Users testFindUser() {
        Users oneByLogin = usersRepository.findOne(1L);
        return oneByLogin;
    }

我有Spring Security UserDetailsS​​ervice:

@Service
    public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private Services services;

    @Override
    public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException {
        Users user;
        Users userFetchedViaGet = services.testGetUser();
        Users userFetchedViaCustomMethod = services.getUserByLogin(login);
        Users userFetchedViaFind = services.testFindUser();
        Users userFetchedWithRoles = services.getUserByLoginWithRoles(login);
        try {
            userFetchedViaGet.getRoles().add(new Role("test"));
        } catch (Exception e) {
            e.printStackTrace();//LazyInitializationException: failed to lazily initialize a collection of role: , could not initialize proxy - no Session
        }
        try {
            userFetchedViaCustomMethod.getRoles().add(new Role("test"));
        } catch (Exception e) {
            e.printStackTrace();//LazyInitializationException: failed to lazily initialize a collection of role: , could not initialize proxy - no Session
        }
        try {
            userFetchedViaFind.getRoles().add(new Role("test")); //LazyInitializationException: failed to lazily initialize a collection of role: , could not initialize proxy - no Session
        } catch (Exception e) {
            e.printStackTrace();
        }
        //some code
        }
    }

和我的控制器(所有方法都有效!但是必须发生重复,因为没有会话和Lazy fetch类型):

@RequestMapping(value = "/test", method = RequestMethod.GET)
    public String test() {      
        Users userFetchedViaGet = services.testGetUser();
        Users userFetchedViaCustomMethod = services.getUserByLogin("ADMIN");
        Users userFetchedViaFind = services.testFindUser();
        Users userFetchedWithRoles = services.getUserByLoginWithRoles("ADMIN");
        try {
            userFetchedViaGet.getRoles().add(new Role("test"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            userFetchedViaCustomMethod.getRoles().add(new Role("test"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            userFetchedViaFind.getRoles().add(new Role("test"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        //some code
    }

你需要一个包装整个事物的事务 - 在你的外观上 - 使用test()方法来实现它,但这不是一个好的做法。

要做的就是让你的服务在事务中包装api方法,并返回一个完全加载的对象 - 包含所有子节点。 这个对象可以是一个简单的bean,它是从Users类构建的,是从对象构建的hashmap,甚至是你想从其余调用返回的字符串。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM