我通过在MVC控制器中将LazyInitializationException
与conversionservice
行为相结合来获得@Transactional
。
以下失败:
@RequestMapping(value = "/{userId}", method = RequestMethod.GET)
@ResponseBody
@Transactional
public JsonUser getUser(@PathVariable("userId") User user) {
// convertToJsonUser triggers lazy loading of User.adresses
return mUserPresenter.convertToJsonUser(user);
}
...以下例外情况: org.hibernate.LazyInitializationException:懒得初始化角色集合:User.adresses,无法初始化代理 - 没有会话
但没有转换服务的相同代码成功:
@RequestMapping(value = "/{userId}", method = RequestMethod.GET)
@ResponseBody
@Transactional
public JsonUser getUser(@PathVariable("userId") Long userId) {
User user = mUserRepository.findOne(userId);
// convertToJsonUser triggers lazy loading of User.adresses
return mUserPresenter.convertToJsonUser(user);
}
并且没有事务行为的相同代码成功:
@RequestMapping(value = "/{userId}", method = RequestMethod.GET)
@ResponseBody
public JsonUser getUser(@PathVariable("userId") User user) {
// changedConvertToJsonUser DOESN'T trigger lazy loading of User.adresses
return mUserPresenter.changedConvertToJsonUser(user);
}
在@Transactional
注释要打开的主要事务之前,转换似乎发生在自己的事务中。因此,转换管理器加载的User
是因为这个原因,没有绑定到主事务,延迟加载失败。
提前谢谢!!!
答案 0 :(得分:0)
控制器不是放置@Transactional注释的理想场所。最好将它们添加到服务方法中。这可能会导致问题,因为您可能有一个控制器的代理对象,它与事务管理器中的代理混淆,您无法预测执行的顺序。所以我的建议是:尝试添加一个服务层..即使是非常简单的将@Transactional注释放在那里并再次测试代码。
答案 1 :(得分:0)
...转换服务本身就是加载实体的方式......
不,不是。这就像名称所示:转换。如果你加载实体,那么这是你的选择,而不是Spring的。
如果不建议在控制器层中打开事务,那么为什么Spring开发人员已经开发了转换服务功能?
ConversionService中的服务表示我们在控制器层中不。
转换似乎发生在自己的事务中,然后由@Transactional注释打开主事务
在这种情况下,@Transactional
没有打开任何交易,因为它不起作用。
交易通常适用于服务层。你可以有类似的东西:
MyUserService implements UserService {
@Override
@Transactional(readonly = true)
public User getUserById(int id) {
但那不是你的问题。您的问题是User
对象未完全初始化。您需要convertToJsonUser
上的交易。
作为旁注:开发Spring的人更喜欢直接使用id并在控制器中加载实体,而不是之前。