【问题标题】:JPA @Entity not managed after creation?创建后未管理 JPA @Entity?
【发布时间】:2019-09-09 15:10:00
【问题描述】:

我有一个简单的控制器方法,在其中创建一个新对象Car,然后将其名称设置为Audi

@GetMapping(value = "/resource")
public ResponseEntity visit() {
    Car car = carRepo.save(new Car("VolksWagen")); // Car should be managed now?
    car.setName("Audi"); // <-- has no effect on database state

    return ResponseEntity.ok().build();
}

在数据库中,它永远不会变成Audi,而是保持VolksWagen

为什么会这样?对于持久化上下文,新创建的Car 不应该处于托管 状态吗?

注意:如果我添加 @Transactional 注释,它会起作用。我认为如果启用 OSIV 就足够了。我对 OSIV 和 @Transactional 有什么误解?

【问题讨论】:

  • OSIV 让 session 保持打开状态,以便在呈现视图时能够延迟加载关联。但它不会让 transaction 处于打开状态。更改已经提交,并且以后的更改将不会保留,因为以后的更改会被刷新或提交(并且因为更改不应该首先发生)
  • OSIV 无论如何都是一个肮脏的黑客,因为事务提交后加载的数据可能与事务内部加载的数据不一致。我会避免它。 vladmihalcea.com/the-open-session-in-view-anti-pattern
  • @JBNizet 我的应用程序实际上只是一个 API,所以没有必要使用 OSIV。我以某种方式设法在脑海中将 OSIV 与 @Transactional 混为一谈,但现在我明白它们是完全不同的东西。谢谢!

标签: jpa spring-data-jpa transactional open-session-in-view


【解决方案1】:

Open Session In View (OSIV) 使 session 保持打开状态,以便在呈现视图时能够延迟加载关联。但它不会让 transaction 处于打开状态。

更改已经提交,以后的更改将不会被保留,因为后来的更改会被刷新或提交(并且因为更改不应该首先发生)

无论如何,OSIV 都是一个肮脏的黑客,因为在事务提交后加载的数据可能与在事务内部加载的数据不一致。我会避免它。有关更多原因,请参阅https://vladmihalcea.com/the-open-session-in-view-anti-pattern

【讨论】:

    【解决方案2】:

    carRepo.save 是持久化还是合并?如果您正在使用合并,请获取合并的结果!

    “Persist 获取一个实体实例,将其添加到上下文中并管理该实例(即将跟踪实体的未来更新)。

    Merge 创建实体的新实例,从提供的实体复制状态,并管理新副本。您传入的实例将不会被管理(您所做的任何更改都不会成为事务的一部分 - 除非您再次调用合并)。” 如this answer中所述

    【讨论】:

    • 我忘了提到,存储库是CrudRepository 的扩展。因此,save()在这种情况下,在创建新实体时,应在内部调用persist()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-14
    • 1970-01-01
    • 2018-03-11
    • 1970-01-01
    • 2018-04-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多