Hibernate有一些方法,它们以某种方式获取对象并将其放入数据库中。它们之间的区别是什么,什么时候使用哪个,为什么没有一种智能方法知道什么时候使用什么?

到目前为止,我已经确定的方法是:

save () (更新) saveOrUpdate () saveOrUpdateCopy () 合并() persist ()


以下是我对这些方法的理解。这些主要是基于API的,尽管我在实践中没有使用所有这些。

saveOrUpdate 根据某些检查调用save或update。例如,如果不存在标识符,则调用save。否则调用update。

保存 持久化一个实体。如果标识符不存在,将分配标识符。如果有,它本质上是在进行更新。返回生成的实体ID。

更新 尝试使用现有标识符持久化实体。如果不存在标识符,则抛出异常。

saveOrUpdateCopy 这已弃用,不应再使用。取而代之的是……

合并 现在我的知识开始动摇了。这里重要的是瞬态实体、分离实体和持久实体之间的区别。有关对象状态的更多信息,请查看这里。使用save & update,你处理的是持久对象。它们被链接到一个会话,因此Hibernate知道发生了什么变化。但是当你有一个瞬态对象时,就不涉及会话了。在这些情况下,您需要使用合并进行更新,使用持久化进行保存。

坚持 如上所述,这用于瞬态对象。它不返回生成的ID。


See the Hibernate Forum for a explanation of the subtle differences between persist and save. It looks like the difference is the time the INSERT statement is ultimately executed. Since save does return the identifier, the INSERT statement has to be executed instantly regardless of the state of the transaction (which generally is a bad thing). Persist won't execute any statements outside of the currently running transaction just to assign the identifier. Save/Persist both work on transient instances, ie instances which have no identifier assigned yet and as such are not saved in the DB. Update and Merge both work on detached instances, ie instances which have a corresponding entry in the DB but which are currently not attached to (or managed by) a Session. The difference between them are what happens to the instance which is passed to the function. update tries to reattach the instance, that means that there must be no other instance of the persistent entity attached to the Session right now, otherwise an exception is thrown. merge, however, just copies all values to a persistent instance in the Session (which will be loaded if it is not currently loaded). The input object is not changed. So merge is more general than update, but may use more resources.


请注意,如果对已分离对象调用更新,无论是否更改对象,数据库中总是会完成更新。如果不是你想要的,你应该使用Session.lock()和LockMode.None。

只有当对象在当前会话范围之外被更改时(当处于分离模式时),才应该调用update。


实际上,hibernate save()和persist()方法之间的区别取决于我们使用的生成器类。

If our generator class is assigned, then there is no difference between save() and persist() methods. Because generator ‘assigned’ means, as a programmer we need to give the primary key value to save in the database right [ Hope you know this generators concept ] In case of other than assigned generator class, suppose if our generator class name is Increment means hibernate it self will assign the primary key id value into the database right [ other than assigned generator, hibernate only used to take care the primary key id value remember ], so in this case if we call save() or persist() method then it will insert the record into the database normally But hear thing is, save() method can return that primary key id value which is generated by hibernate and we can see it by

long s = session.save(k);

在同样的情况下,persist()将永远不会向客户端返回任何值。


以下答案没有一个是正确的。 所有这些方法看似相似,但实际上做的事情完全不同。 很难给出简短的评论。最好提供关于这些方法的完整文档链接: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html


这个链接很好地解释了:

http://www.stevideter.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/

我们都有一些偶尔遇到的问题,当我们再次看到它们时,我们知道我们已经解决了这个问题,但不记得是如何解决的。

在Hibernate中使用Session.saveOrUpdate()时抛出的NonUniqueObjectException就是我的一个。我将为一个复杂的应用程序添加新功能。我所有的单元测试都运行正常。然后在测试UI时,试图保存一个对象,我开始得到一个异常,消息是“具有相同标识符值的不同对象已经与会话关联”。下面是一些来自Java Persistence with Hibernate的示例代码。

            Session session = sessionFactory1.openSession();
            Transaction tx = session.beginTransaction();
            Item item = (Item) session.get(Item.class, new Long(1234));
            tx.commit();
            session.close(); // end of first session, item is detached

            item.getId(); // The database identity is "1234"
            item.setDescription("my new description");
            Session session2 = sessionFactory.openSession();
            Transaction tx2 = session2.beginTransaction();
            Item item2 = (Item) session2.get(Item.class, new Long(1234));
            session2.update(item); // Throws NonUniqueObjectException
            tx2.commit();
            session2.close();

要理解此异常的原因,重要的是要理解分离对象以及在分离对象上调用saveOrUpdate()(或仅仅是update())时会发生什么。

当我们关闭一个单独的Hibernate Session时,我们正在使用的持久对象被分离。这意味着数据仍然在应用程序的内存中,但Hibernate不再负责跟踪对象的更改。

如果我们随后修改分离对象并想要更新它,则必须重新附加该对象。在重新连接过程中,Hibernate将检查是否有相同对象的其他副本。如果它找到了,它必须告诉我们它不再知道“真正的”副本是什么了。也许对我们期望保存的其他副本做了其他更改,但Hibernate不知道这些更改,因为它当时没有管理它们。

Hibernate不是保存可能的坏数据,而是通过NonUniqueObjectException告诉我们问题。

那么我们该怎么办呢?在Hibernate 3中,我们有merge()(在Hibernate 2中,使用saveOrUpdateCopy())。此方法将强制Hibernate将其他分离实例中的任何更改复制到您想要保存的实例上,从而在保存之前将所有更改合并到内存中。

        Session session = sessionFactory1.openSession();
        Transaction tx = session.beginTransaction();
        Item item = (Item) session.get(Item.class, new Long(1234));
        tx.commit();
        session.close(); // end of first session, item is detached

        item.getId(); // The database identity is "1234"
        item.setDescription("my new description");
        Session session2 = sessionFactory.openSession();
        Transaction tx2 = session2.beginTransaction();
        Item item2 = (Item) session2.get(Item.class, new Long(1234));
        Item item3 = session2.merge(item); // Success!
        tx2.commit();
        session2.close();

需要注意的是,merge返回对实例最新更新版本的引用。它不是将项重新附加到Session。如果您测试实例是否相等(item == item3),您将发现在这种情况下它返回false。从现在开始,您可能希望使用item3。

还需要注意的是,Java Persistence API (JPA)没有分离和重新连接对象的概念,而是使用EntityManager.persist()和EntityManager.merge()。

我发现在使用Hibernate时,saveOrUpdate()通常足以满足我的需要。通常只有当我的对象可以引用相同类型的对象时,我才需要使用merge。最近,异常的原因是在验证引用不是递归的代码中。作为验证的一部分,我将相同的对象加载到会话中,导致了错误。

您在哪里遇到过这个问题?合并对你有用吗?还是你需要另一种解决方案?你喜欢总是使用归并,还是喜欢只在特定情况下使用它


╔══════════════╦═══════════════════════════════╦════════════════════════════════╗
║    METHOD    ║            TRANSIENT          ║            DETACHED            ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║       sets id if doesn't      ║   sets new id even if object   ║
║    save()    ║     exist, persists to db,    ║    already has it, persists    ║
║              ║    returns attached object    ║ to DB, returns attached object ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║       sets id on object       ║             throws             ║
║   persist()  ║     persists object to DB     ║       PersistenceException     ║
║              ║                               ║                                ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║                               ║                                ║
║   update()   ║           Exception           ║     persists and reattaches    ║
║              ║                               ║                                ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║  copy the state of object in  ║    copy the state of obj in    ║
║    merge()   ║     DB, doesn't attach it,    ║      DB, doesn't attach it,    ║
║              ║    returns attached object    ║     returns attached object    ║
╠══════════════╬═══════════════════════════════╬════════════════════════════════╣
║              ║                               ║                                ║
║saveOrUpdate()║           as save()           ║            as update()         ║
║              ║                               ║                                ║
╚══════════════╩═══════════════════════════════╩════════════════════════════════╝

我找到了一个很好的例子来说明所有hibernate保存方法之间的差异:

http://www.journaldev.com/3481/hibernate-session-merge-vs-update-save-saveorupdate-persist-example

总之,根据以上链接:

save ()

我们可以在事务外部调用此方法。如果我们在没有事务的情况下使用它,并且在实体之间有级联,那么只有主实体会被保存,除非我们刷新会话。 因此,如果主对象映射了其他对象,则在提交事务或刷新会话时保存它们。

persist ()

它类似于在事务中使用save(),所以它是安全的,并照顾任何级联对象。

saveOrUpdate ()

可以与事务一起使用,也可以不使用事务,就像save()一样,如果它在没有事务的情况下使用,映射的实体将不会被保存,除非我们刷新会话。 根据所提供的数据将结果插入或更新查询。如果数据存在于数据库中,则执行更新查询。

update ()

当我们知道我们只是在更新实体信息时,应该使用Hibernate更新。该操作将实体对象添加到持久上下文,并在事务提交时跟踪和保存进一步的更改。 因此,即使在调用update之后,如果我们在实体中设置了任何值,它们将在事务提交时被更新。

go()

Hibernate merge可用于更新现有值,但此方法从传递的实体对象创建一个副本并返回它。返回的对象是持久上下文的一部分,并跟踪任何更改,传递的对象不跟踪。这是merge()与其他方法的主要区别。

对于所有这些方法的实际示例,请参考我上面提到的链接,它展示了所有这些不同方法的示例。


上面的答案都不完整。虽然Leo Theobald的答案看起来很接近。

基本要点是hibernate如何处理实体的状态,以及当状态发生变化时如何处理它们。所有的事情都必须考虑到刷新和提交,而每个人似乎都完全忽略了这一点。

不要使用HIBERNATE的保存方法。忘记它甚至存在于冬眠!

坚持

正如大家所解释的,持久化基本上是将一个实体从“瞬态”状态转换为“托管”状态。此时,slush或commit可以创建插入语句。但实体仍将保持“托管”状态。它不随同花顺而改变。

在这一点上,如果你再次“坚持”,将不会有任何改变。如果我们试图持久化一个持久化实体,就不会有更多的保存。

当我们试图驱逐实体时,乐趣就开始了。

驱逐是Hibernate的一个特殊功能,它将实体从“托管”转换为“分离”。不能在分离实体上调用持久化。如果我们这样做,那么Hibernate将引发一个异常,整个事务将在提交时回滚。

合并与更新

这是两个有趣的函数,用不同的方法处理会产生不同的效果。它们都试图将实体从“分离”状态转换为“托管”状态。但是用不同的方式。

理解一个事实,即Detached意味着一种“脱机”状态。managed表示“在线”状态。

观察下面的代码:

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();

    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    ses1.merge(entity);

    ses1.delete(entity);

    tx1.commit();

当你这样做的时候?你认为会发生什么? 如果你说这会引起异常,那么你是正确的。这将引发异常,因为合并已经对实体对象进行了操作,该实体对象处于分离状态。但它不会改变对象的状态。

在后台,merge将引发一个选择查询,并返回一个处于附加状态的实体副本。观察下面的代码:

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();
    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    HibEntity copied = (HibEntity)ses1.merge(entity);
    ses1.delete(copied);

    tx1.commit();

上面的示例之所以有效,是因为merge将一个新的实体带入了处于持久状态的上下文中。

当与Update一起应用时,同样的工作很好,因为Update实际上不像merge那样带来实体的副本。

Session ses1 = sessionFactory.openSession();

    Transaction tx1 = ses1.beginTransaction();

    HibEntity entity = getHibEntity();

    ses1.persist(entity);
    ses1.evict(entity);

    ses1.update(entity);

    ses1.delete(entity);

    tx1.commit();

同时在调试跟踪中,我们可以看到Update并没有引发像merge这样的select SQL查询。

删除

在上面的例子中,我使用了delete而没有谈论delete。Delete基本上会将实体从托管状态转换为“已删除”状态。当刷新或提交时,将发出删除命令来存储。

然而,使用persist方法可以将实体从“已删除”状态带回“已管理”状态。

希望以上解释澄清了您的疑问。


在大多数情况下,您应该更喜欢JPA方法,而更新用于批处理任务。

JPA或Hibernate实体可以处于以下四种状态之一:

瞬态(新) 管理(持续) 分离 删除(删除)

从一个状态到另一个状态的转换是通过EntityManager或Session方法完成的。

例如,JPA EntityManager提供了以下实体状态转换方法。

Hibernate会话实现了所有JPA EntityManager方法,并提供了一些附加的实体状态转换方法,如save、saveOrUpdate和update。

坚持

要将一个实体的状态从Transient (New)更改为Managed (persistent),我们可以使用JPA EntityManager提供的持久化方法,该方法也由Hibernate会话继承。

持久化方法触发了一个PersistEvent,该事件由Hibernate事件监听器DefaultPersistEventListener处理。

因此,当执行以下测试用例时:

doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);
    
    LOGGER.info(
        "Persisting the Book entity with the id: {}", 
        book.getId()
    );
});

Hibernate生成以下SQL语句:

CALL NEXT VALUE FOR hibernate_sequence

-- Persisting the Book entity with the id: 1

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

请注意,id是在将Book实体附加到当前持久性上下文之前分配的。这是必需的,因为托管实体存储在Map结构中,其中键由实体类型及其标识符组成,值是实体引用。这就是为什么JPA实体管理器和Hibernate会话被称为一级缓存的原因。

调用persist时,实体只附加到当前运行的Persistence Context, INSERT可以推迟到调用flush为止。

唯一的例外是IDENTITY,它会立即触发INSERT,因为这是它获得实体标识符的唯一方法。因此,Hibernate不能使用IDENTITY生成器批量插入实体。

Save

特定于Hibernate的保存方法比JPA更早,并且在Hibernate项目开始时就可用了。

保存方法触发一个SaveOrUpdateEvent事件,该事件由DefaultSaveOrUpdateEventListener Hibernate事件监听器处理。因此,save方法等价于update和saveOrUpdate方法。

要了解save方法是如何工作的,请考虑以下测试用例:

doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    Session session = entityManager.unwrap(Session.class);

    Long id = (Long) session.save(book);

    LOGGER.info(
        "Saving the Book entity with the id: {}", 
        id
    );
});

当运行上面的测试用例时,Hibernate生成以下SQL语句:

CALL NEXT VALUE FOR hibernate_sequence

-- Saving the Book entity with the id: 1

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

如您所见,结果与持久化方法调用相同。但是,与persist方法不同,save方法返回实体标识符。

更新

特定于hibernate的更新方法旨在绕过脏检查机制,并强制在刷新时更新实体。

更新方法触发一个SaveOrUpdateEvent事件,该事件由DefaultSaveOrUpdateEventListener Hibernate事件监听器处理。因此,update方法等价于save和saveOrUpdate方法。

要了解更新方法是如何工作的,请考虑以下示例,该示例将Book实体持久化在一个事务中,然后在实体处于分离状态时修改它,并使用更新方法调用强制执行SQL update。

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    return book;
});

LOGGER.info("Modifying the Book entity");

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

doInJPA(entityManager -> {
    Session session = entityManager.unwrap(Session.class);

    session.update(_book);

    LOGGER.info("Updating the Book entity");
});

当执行上面的测试用例时,Hibernate生成以下SQL语句:

CALL NEXT VALUE FOR hibernate_sequence

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

-- Modifying the Book entity
-- Updating the Book entity

UPDATE 
    book 
SET 
    author = 'Vlad Mihalcea', 
    isbn = '978-9730228236', 
    title = 'High-Performance Java Persistence, 2nd edition'
WHERE 
    id = 1

注意,UPDATE是在持久化上下文刷新期间执行的,就在提交之前,这就是为什么首先记录UPDATE the Book实体消息的原因。

使用@SelectBeforeUpdate避免不必要的更新

现在,即使实体在分离状态下没有更改,也将始终执行UPDATE。为了防止这种情况,您可以使用@SelectBeforeUpdate Hibernate注释,它将触发一个SELECT语句,获取加载状态,然后由脏检查机制使用。

因此,如果我们用@SelectBeforeUpdate注释Book实体:

@Entity(name = "Book")
@Table(name = "book")
@SelectBeforeUpdate
public class Book {

    //Code omitted for brevity
}

并执行以下测试用例:

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    return book;
});

doInJPA(entityManager -> {
    Session session = entityManager.unwrap(Session.class);

    session.update(_book);
});

Hibernate执行以下SQL语句:

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

SELECT 
    b.id,
    b.author AS author2_0_,
    b.isbn AS isbn3_0_,
    b.title AS title4_0_
FROM 
    book b
WHERE 
    b.id = 1

注意,这一次没有执行UPDATE,因为Hibernate脏检查机制检测到实体没有被修改。

SaveOrUpdate

特定于hibernate的saveOrUpdate方法只是保存和更新的别名。

saveOrUpdate方法触发一个SaveOrUpdateEvent事件,该事件由DefaultSaveOrUpdateEventListener Hibernate事件监听器处理。因此,update方法等价于save和saveOrUpdate方法。

现在,当您想要持久化一个实体或强制执行一个UPDATE时,您可以使用saveOrUpdate,如下例所示。

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    Session session = entityManager.unwrap(Session.class);
    session.saveOrUpdate(book);

    return book;
});

_book.setTitle("High-Performance Java Persistence, 2nd edition");

doInJPA(entityManager -> {
    Session session = entityManager.unwrap(Session.class);
    session.saveOrUpdate(_book);
});

注意NonUniqueObjectException

使用save、update和saveOrUpdate可能会出现的一个问题是,如果持久性上下文已经包含了与下面示例中相同id和相同类型的实体引用:

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    Session session = entityManager.unwrap(Session.class);
    session.saveOrUpdate(book);

    return book;
});

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

try {
    doInJPA(entityManager -> {
        Book book = entityManager.find(
            Book.class, 
            _book.getId()
        );

        Session session = entityManager.unwrap(Session.class);
        session.saveOrUpdate(_book);
    });
} catch (NonUniqueObjectException e) {
    LOGGER.error(
        "The Persistence Context cannot hold " +
        "two representations of the same entity", 
        e
    );
}

现在,当执行上面的测试用例时,Hibernate将抛出一个NonUniqueObjectException,因为第二个EntityManager已经包含了一个Book实体,其标识符与我们传递给update的标识符相同,而持久性上下文不能容纳同一实体的两个表示。

org.hibernate.NonUniqueObjectException: 
    A different object with the same identifier value was already associated with the session : [com.vladmihalcea.book.hpjp.hibernate.pc.Book#1]
    at org.hibernate.engine.internal.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:651)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:284)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:227)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:92)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
    at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:682)
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:674)

为了避免NonUniqueObjectException,您需要使用JPA EntityManager提供的合并方法,并由Hibernate会话继承。

如果在Persistence Context中没有找到实体引用,那么merge将从数据库中获取一个新的实体快照,并复制传递给merge方法的分离实体的状态。

merge方法触发一个MergeEvent,由DefaultMergeEventListener Hibernate事件监听器处理。

要了解merge方法是如何工作的,请考虑以下示例,该示例在一个事务中持久化Book实体,然后在实体处于分离状态时修改它,并将分离实体传递到子序列持久化上下文中进行合并。

Book _book = doInJPA(entityManager -> {
    Book book = new Book()
    .setIsbn("978-9730228236")
    .setTitle("High-Performance Java Persistence")
    .setAuthor("Vlad Mihalcea");

    entityManager.persist(book);

    return book;
});

LOGGER.info("Modifying the Book entity");

_book.setTitle(
    "High-Performance Java Persistence, 2nd edition"
);

doInJPA(entityManager -> {
    Book book = entityManager.merge(_book);

    LOGGER.info("Merging the Book entity");

    assertFalse(book == _book);
});

当运行上面的测试用例时,Hibernate执行以下SQL语句:

INSERT INTO book (
    author, 
    isbn, 
    title, 
    id
) 
VALUES (
    'Vlad Mihalcea', 
    '978-9730228236', 
    'High-Performance Java Persistence', 
    1
)

-- Modifying the Book entity

SELECT 
    b.id,
    b.author AS author2_0_,
    b.isbn AS isbn3_0_,
    b.title AS title4_0_
FROM 
    book b
WHERE 
    b.id = 1

-- Merging the Book entity

UPDATE 
    book 
SET 
    author = 'Vlad Mihalcea', 
    isbn = '978-9730228236', 
    title = 'High-Performance Java Persistence, 2nd edition'
WHERE 
    id = 1

注意,merge返回的实体引用与传递给merge方法的分离实体引用不同。

现在,尽管您在复制分离实体状态时更喜欢使用JPA合并,但在执行批处理任务时,额外的SELECT可能会产生问题。

出于这个原因,当您确定没有实体引用已经附加到当前运行的持久性上下文,并且分离的实体已经被修改时,您应该更喜欢使用update。

结论

要持久化一个实体,您应该使用JPA持久化方法。要复制分离的实体状态,应优先使用merge。更新方法仅对批处理任务有用。save和saveOrUpdate只是用于更新的别名,您可能根本不应该使用它们。

有些开发人员甚至在实体已经被管理时调用save,但这是一个错误,并且会触发冗余事件,因为对于托管实体,UPDATE会在Persistence上下文刷新时自动处理。