【问题标题】:One Transaction for Hibernate Validation and Spring controllerHibernate Validation 和 Spring 控制器的一项事务
【发布时间】:2013-05-15 13:54:12
【问题描述】:

我正在尝试为 Rest API 实现注册控制器。我已经阅读了很多关于在哪里放置@Transactional 的信息。 (不是在 DAO 级别,而是在服务上可能是精心编排的)。在我的用例中,我不仅想要服务,还想要使用相同事务的休眠验证。

这是控制器的代码:

@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 注释。当我将此注释放在调用数据库的方法上时,一切正常,但有两个事务是启动的。我怀疑当我将它放在 register Method 中时,会在 @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,如何将整个请求封装到一个事务中?

谢谢你:)

【问题讨论】:

  • 你在使用 JSR 330 验证吗?
  • JSR 330:Java 的依赖注入:我使用 Spring 进行依赖注入。 @Autowire 在这种情况下工作正常。我不确定你的意思是不是 JSR 303: Bean Validation: 这里我使用的是 Hibernate-Validator 4.3.1 implementation
  • 回答这个附带问题。 Hibernate Validator 是 Bean Validation (JSR 330) 规范的参考实现。

标签: java spring-mvc hibernate-validator transactional hibernate-4.x


【解决方案1】:

您的解决方法可以通过使用单个验证器并将其注入控制器来改进。你试过了吗:

@Autowired
private Validator validator;

这样您就可以跳过为每个请求创建验证器的开销。 您还应该小心竞争条件。当您检查数据库是否存在给定电子邮件时,另一个请求可以创建此记录,这样您在插入数据时仍然会遇到异常。

【讨论】:

  • 变通方法改进工作正常。哦,我还没有考虑过特定​​的比赛条件。我的想法是:在一个事务中结合验证和控制器执行将解决所有问题,如“丢失更新”或至少会引发异常/回滚。在这种情况下,检查未使用的电子邮件不会产生读/写冲突。也许我应该在另一个问题中问如何做到这一点并做更多的阅读。谢谢:)
猜你喜欢
  • 2018-01-26
  • 2011-06-13
  • 1970-01-01
  • 2013-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多