java 在SpringJPA中更新数据库条目的正确方法是什么?

3lxsmp7m  于 2022-12-21  发布在  Java
关注(0)|答案(2)|浏览(182)

有两种方法- a)从数据库获取对象,在java代码中设置值,然后使用'保存()'进行更新。b)运行自定义更新查询
我希望得到一个明确的答案是什么是标准的做法,为什么一个会比另一个更可取?
我试着查找过去关于这个主题的问题,但无法找到一个结论性的答案,哪个更好,为什么?在a)中,我可以看到额外的查询作为一个缺点,但它感觉相当方便和可读。在b)的情况下,它似乎更好,因为它将运行一个单一的查询。
我读到过一种中间的方法,即使用getOne功能获取条目的代理/引用,这样“get”查询就不会在第一种方法中直接执行,但是,它需要扩展一个不太通用的存储库,共识似乎是避免它。

ijnw1ujt

ijnw1ujt1#

你可以使用第一种方法询问db“我的记录是否存在于db中?”-如果不存在,就向我抛出错误。例如,

repository.findById(id).orElseThrow(() -> new NotFoundException("blabla bla not found"));

在任何情况下,如果没有得到id,你只能在你的实体有id的repository.save(entity)中,如果它的id在db中,那么你的实体将被更新。
UPD:你可以直接使用@query + @Modify来更新实体,但是为什么呢?你已经有了保存/更新Jpa的方法。如果你有一个包含很多字段的实体,并且你不总是更新类似的字段,那么写一个查询会很不舒服,但是你可以使用mupstruct(例如)+ jpa,一切都会好的:)更干净的代码

uqxowvwt

uqxowvwt2#

这两个选项都存在,因为它们都有其用途,甚至还有第三个选项,这是第一个选项的变体。

JPA方式

JPA方式是JPA默认的工作方式,它接近您的选项a):
1.启动事务,该事务还启动持久性上下文。
1.加载一个或多个实体。
1.以你想要的方式改变实体。2这将在你的持久性上下文中把实体标记为 dirty
1.提交事务,这将刷新持久性上下文中的更改。
这是您的变体a),没有调用save,这对于JPA来说是不必要的。

DDD/Spring Data 方式

Spring Data是围绕存储库的概念构建的,这个概念来自于领域驱动设计。存储库类似于集合,你可以在其中放入实体。精确地说,但这是另一回事,您可以通过调用savesaveAll将实体放入存储库,在大多数Spring Data模块中,需要调用此函数来保存实体。只有具有脏检查机制的JPA在技术上不需要在相同的持久性上下文中加载实体,但是将其排除在外会在与实体交互的业务代码之间创建一个不可见的依赖关系。和使用的持久化技术(JPA)。在Spring Data团队看来,您应该始终调用save

绕过JPA

第三种选择是直接执行insert或update语句。这实际上是在比JPA更低的抽象层上操作的。您现在必须手动确保数据库中的状态在内存实体中正确表示,这很容易与JPA的一级缓存和脏检查冲突。您还必须手动维护乐观锁定所需的约束。并且JPA不会触发任何生命周期事件。
但它也有好处:它更快,甚至可能更快。您保存了数据库往返的时间。如果您只更新几个字段,您可能会节省推送到数据库的数据。而且您可以轻松地用一条语句更新多行。

选择什么

在项目的某个阶段,您选择(Spring Data)JPA,大概是因为它的特性为您提供了一些好处,因此我将默认使用 * JPA方式 * 或 * DDD/Spring Data方式 *。
但是,如果您有性能问题,值得记住的是,您可以降低到 Bypassing JPA 的较低抽象级别。
如果您经常使用这种方法,那么您可能需要首先考虑JPA是否是正确的选择,或者像MyBatis、Jooq或Spring Data JDBC这样的其他方法是否是更好的选择。

相关问题