我正在尝试为Rest API实现注册控制器。我已经了解了@Transactional的位置。 (不是在DAO级别,但在服务可能是精心策划的)。在我的用例中,我不仅需要服务,还需要使用hibernate验证来使用相同的事务。
这是控制器的代码:
@Autowired
private UserService userService;
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
@Transactional
public DefaultResponse register(@Valid RegisterIO registerIO, BindingResult errors) {
DefaultResponse result = new DefaultResponse();
if (errors.hasErrors()) {
result.addErrors(errors);
} else {
userService.register(registerIO);
}
return result;
}
我编写了一个自定义约束注释,它验证了参数registerIO的属性。这两个验证器和userService.register(registerIO);访问数据库(检查电子邮件地址是否已被使用)。
因此我希望两种方法都使用相同的Hibernate会话和事务。
此方法导致以下异常:
org.hibernate.HibernateException: No Session found for current thread
org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:941)
问题是@Transactional注释。当我将这个注释放在方法中时,调用数据库的一切都可以找到,但是两个事务都是startet。我怀疑当我将它放在寄存器方法时,在@Transactional启动此方法的事务之前执行休眠验证。
我开发了以下功能性解决方法,但我对它不满意。此代码不使用@Valid注释,而是单独调用验证器:
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
@Transactional
public DefaultResponse register( RegisterIO registerIO, BindingResult errors) {
DefaultResponse result = new DefaultResponse();
ValidatorFactory vf = Validation.buildDefaultValidatorFactory();
Validator validator = vf.getValidator();
Set<ConstraintViolation<RegisterIO>> valResult = validator.validate(registerIO);
我试着总结一下我的问题: 将Spring MVC和Hibernate-Validation与@Valid和@Transactional一起使用,如何将整个请求封装到一个事务中?
谢谢:)
答案 0 :(得分:1)
通过使用单个Validator并将其注入控制器中,可以改善您的解决方法。你试过了吗?
@Autowired
private Validator validator;
这样就省去了在每个请求上创建验证器的开销。 你也应该小心竞争条件。当您检查数据库是否存在给定的电子邮件时,另一个请求可以创建此记录,以便在插入数据时仍然会出现异常。