我在项目中使用Spring Boot(1.3.3.RELEASE)和Spring Data和Bean Validation,我发现了一个意外的(至少对我而言)行为。我有一个User实体及其UserRepository(扩展JpaRepository的接口)。当我这样打电话时:
userRepository.save(user);
logger.info("User saved with id", user.getId());
在新用户和无效用户上,调用记录器并显示用户已收到ID。即使没有任何内容被持久化,并且在记录之后最后抛出了ConstraintViolationException。
但如果我改为:
userRepository.saveAndFlush(user);
logger.info("User saved with id", user.getId());
立即抛出ConstraintViolationException,永远不会到达记录器行。
第二种行为,即在记录器之前抛出异常,是我认为在调用userRepository.save()方法时必须发生的行为。
有什么问题?关于我的项目的一些事情?或者我对bean验证应该如何工作的理解?
答案 0 :(得分:3)
我认为从数据访问层内触发验证既是糟糕的设计,也是一个根本不好的想法。这样做基本上意味着所有代码都会让你在实例中保存(并最终失败)并且该实例一直被破坏(处于无效状态)。如果这还没有导致某些中间业务逻辑失败,那么手指就会越过!
这种方法通常适用于非常简单的CRUD场景,因为基本上没有中介可能会失败,例如一个字段是null
但不应该是等等。但是一旦你开始在这些错误之间添加一些逻辑就会破坏你的逻辑(例如,期望电子邮件地址具有正确格式的东西,不是等等。)。
我建议建立一个强大的域模型,从根本上防止对象进入无效状态,并在接收用户输入的位置附近添加映射层 very ,这样你基本上通过从映射步骤抛出的异常来发现缺少的验证。
然后可以在接受可能受污染的用户数据的图层中使用JSR-303。但它肯定是你不应该在你的领域模型中使用的东西。
答案 1 :(得分:1)
根据您的刷新策略和Identity Generator,实际插入DB可能会(稍后会发生)插入。在Hibernate的情况下,它会在插入/更新/删除之前进行验证(在您的情况下会被推迟)。查看BeanValidationEventListener
及其方法onPreInsert()
,onPreUpdate()
和onPreDelete()
的来源。