为什么对我的JPA实体所做的更改不会持久保存到数据库中? [英] Why do changes to my JPA entity not get persisted to the database?

查看:130
本文介绍了为什么对我的JPA实体所做的更改不会持久保存到数据库中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Spring Boot应用程序中,我有一个实体Task,其状态在执行期间会更改:

In a Spring Boot Applicaion, I have an entity Task with a status that changes during execution:

@Entity
public class Task {

  public enum State {
    PENDING,
    RUNNING,
    DONE
  }

  @Id @GeneratedValue
  private long id;
  private String name;
  private State state = State.PENDING;

  // Setters omitted

  public void setState(State state) {
    this.state = state; // THIS SHOULD BE WRITTEN TO THE DATABASE
  }

  public void start() { 
    this.setState(State.RUNNING);

    // do useful stuff
    try { Thread.sleep(2000); } catch(InterruptedException e) {}
    this.setState(State.DONE);
  }
} 

如果状态更改,则对象应保存在数据库中.我正在使用这个Spring Data接口作为存储库:

If state changes, the object should be saved in the database. I'm using this Spring Data interface as repository:

 public interface TaskRepository extends CrudRepository<Task,Long> {}

然后使用此代码创建并启动Task:

And this code to create and start a Task:

Task t1 = new Task("Task 1");
Task persisted = taskRepository.save(t1);
persisted.start();

据我了解,persisted现在已附加到持久性会话,并且如果对象发生更改,则此更改应存储在数据库中.但这没有发生,重新加载时状态为PENDING.

From my understanding persisted is now attached to a persistence session and if the object changes this changes should be stored in the database. But this is not happening, when reloading it the state is PENDING.

有什么想法我在这里做错了吗?

Any ideas what I'm doing wrong here?

推荐答案

tl; dr

将实例附加到持久性上下文并不意味着对象状态的每次更改都将直接持久化.更改检测仅在持久性上下文的生命周期内发生在某些事件上.

tl;dr

Attaching an instance to a persistence context does not mean every change of the state of the object gets persisted directly. Change detection only occurs on certain events during the lifecycle of persistence context.

您似乎误解了变更检测的工作方式. JPA的一个非常核心的概念是所谓的持久性上下文.它基本上是工作单元模式的实现.您可以通过两种方式向其中添加实体:通过从数据库中加载它们(执行查询或发出EntityManager.find(…)),或者通过将它们主动添加到持久性上下文中.这就是对save(…)方法的调用有效地执行的操作.

You seem to misunderstood the way change detection works. A very central concept of JPA is the so called persistence context. It is basically an implementation of the unit-of-work pattern. You can add entities to it in two ways: by loading them from the database (executing a query or issuing an EntityManager.find(…)) or by actively adding them to the persistence context. This is what the call to the save(…) method effectively does.

此处要意识到的重要一点是,将实体添加到持久性上下文中"不必等于存储在数据库中".持久性提供者可以自由地推迟数据库交互,只要它认为合理即可.提供程序通常这样做是为了能够对数据进行批量修改操作.但是,在许多情况下,初始的save(…)(转换为EntityManager.persist(…))将直接执行,例如如果您使用的是自动ID增量.

An important point to realize here is that "adding an entity to the persistence context" does not have to be equal to "stored in the database". The persistence provider is free to postpone the database interaction as long as it thinks is reasonable. Providers usually do that to be able to batch up modifying operations on the data. In a lot of cases however, an initial save(…) (which translates to an EntityManager.persist(…)) will be executed directly, e.g. if you're using auto id increment.

也就是说,现在该实体已成为托管实体.这意味着,持久性上下文会意识到这一点,并将在需要发生事件的情况下透明地持久保存对实体所做的更改.最重要的两个是以下几个:

That said, now the entity has become a managed entity. That means, the persistence context is aware of it and will persist the changes made to the entity transparent, if events occur that need that to take place. The two most important ones are the following ones:

  1. 持久性上下文已关闭.在Spring环境中,持久性上下文的生命周期通常绑定到事务.在您的特定示例中,存储库具有默认事务(因此具有持久性上下文)边界.如果您需要实体进行管理,则需要延长事务生命周期(通常通过引入具有@Transactional批注的服务层).在Web应用程序中,我们经常看到视图模式下的打开实体管理器",它基本上是一个请求绑定的生命周期.

  1. The persistence context gets closed. In Spring environments the lifecycle of the persistence context is usually bound to a transaction. In your particular example, the repositories have a default transaction (and thus persistence context) boundary. If you need the entity to stay managed around it, you need to extend the transaction lifecycle (usually by introducing a service layer that has @Transactional annotations). In web applications we often see the Open Entity Manager In View Pattern, which is basically a request-bound lifecycle.

持久性上下文已刷新.这可以手动进行(通过调用EntityManager.flush()或透明地进行.例如,如果持久性提供程序需要发出查询,则通常会刷新持久性上下文以确保查询可以找到当前未决的更改.假设您加载了一个用户,将其地址更改到一个新位置,然后发出查询以按用户的地址查找用户.提供程序将足够聪明,可以先刷新地址更改,然后再执行查询.

The persistence context is flushed. This can either happen manually (by calling EntityManager.flush() or transparently. E.g. if the persistence provider needs to issue a query, it will usually flush the persistence context to make sure, currently pending changes can be found by the query. Imagine you loaded a user, changed his address to a new place and then issue a query to find users by their addresses. The provider will be smart enough to flush the address change first and execute the query afterwards.

这篇关于为什么对我的JPA实体所做的更改不会持久保存到数据库中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆