【问题标题】:Why did Spring Data JPA save method didn't validate straight away?为什么 Spring Data JPA 保存方法没有立即验证?
【发布时间】:2016-10-11 21:56:06
【问题描述】:

我在一个项目中使用带有 Spring Data 和 Bean Validation 的 Spring Boot (1.3.3.RELEASE),我发现了一个意想不到的(至少对我而言)行为。我有一个用户实体及其 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 验证应该如何工作的理解?

【问题讨论】:

    标签: java spring spring-data spring-data-jpa


    【解决方案1】:

    我认为从数据访问层触发验证既是糟糕的设计,也是一个根本的坏主意。这样做基本上意味着所有将实例交给您保存(并最终失败)并且该实例一直被破坏(处于无效状态)的代码。如果这还没有导致某些中间业务逻辑失败,那就祈祷吧!

    这种方法通常适用于非常简单的 CRUD 场景,因为基本上没有中介可以失败,例如一个字段是null 但不应该是等等。但是一旦你开始在这些错误之间添加一些逻辑就会破坏你的逻辑(例如,期望电子邮件地址的格式正确,不为空等.).

    我宁愿建议构建一个强大的域模型,从根本上防止对象进入无效状态并添加一个映射层非常靠近接收用户输入的位置,以便您基本上发现缺失通过该映射步骤抛出的异常进行验证。

    JSR-303 然后可以在接受潜在污染用户数据的层中使用。但这绝对是您不应该在域模型中使用的东西。

    【讨论】:

      【解决方案2】:

      根据您的刷新策略和身份生成器,实际插入 DB 可能(在您的情况下确实如此)稍后发生。在休眠的情况下,它会在插入/更新/删除之前验证(在您的情况下被推迟)。查看BeanValidationEventListener 的来源及其方法onPreInsert()onPreUpdate()onPreDelete()

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-06-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-09
        • 2019-03-25
        • 2021-01-16
        • 2018-09-25
        相关资源
        最近更新 更多