4

我想实现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; 
} 

我写了定制contraint注解,这验证了参数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启动此方法的事务之前执行hibernate验证。

我开发了以下功能解决方法,但我不满意。这个代码不使用@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验证与@Valid和@Transactional在一起,怎么可能将整个请求封装到一个事务中?

谢谢:)

+0

您使用的是JSR 330验证吗? –

+0

JSR 330:Java的依赖注入:我使用Spring进行依赖注入。 @Autowire在这种情况下工作正常。我不确定你的意思是JSR 303:Bean验证:这里我使用Hibernate-Validator 4.3.1实现 – Sebastian

+0

回答这个问题。 Hibernate Validator是Bean Validation(JSR 330)规范的参考实现。 – Hardy

回答

1

你的解决方法可以通过使用一个单一的验证,并注入其INTP控制器得到改进。您是否尝试过:

@Autowired 
private Validator validator; 

这样您可以跳过在每个请求上创建验证器的开销。 你也应该注意比赛条件。在检查数据库时,是否存在给定的电子邮件,另一个请求可以创建此记录,以便在插入数据时仍然会发生异常。

+0

解决方法改进工作正常。哦,我没有想过这种特殊的竞争条件。我的想法是:在一个事务中合并验证和控制器执行将解决所有问题,如“丢失更新”或至少会抛出异常/回滚。在这种情况下检查未使用的电子邮件不会产生读/写冲突。也许我应该问一下如何在另一个问题上做这件事,并做更多的阅读。谢谢 :) – Sebastian