[英]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 UserDetailsService:
@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.