为什么@Transactional会自动保存到数据库

Rac*_*don 15 spring jpa transactional

我有一个使用@Transactional注释的方法.我从我的数据库中检索一个对象,更改一个字段,然后从该方法返回.在不保存我的对象的情况下,数据库无论如何都会更新,这很奇怪.

你能告诉我如何避免这种行为吗?

kos*_*tja 17

此行为是事务性的主要目的之一.

在事务方法即将返回之前,事务提交,这意味着对托管实体的所有更改都将刷新到数据库.

如果发生错误,将回滚事务,这意味着不会向数据库提交任何更改.

您可能正在LazyInitializationException尝试访问延迟加载的属性,可能是实体的集合.从DB获取授权时,不会实例化Lazily loded属性.

如果在事务中访问延迟加载的属性,则持久性提供程序将创建查询,实例化结果并将其附加到"父"实体.

编辑:如果要加载延迟属性并且能够在不将更改保留到数据库的情况下更改实体,则可以使用获取连接获取延迟属性的实体.

em.createQuery("SELECT e FROM MyEntity e JOIN FETCH e.lazyProp");
Run Code Online (Sandbox Code Playgroud)

然后继续使用@orid描述的方法之一.

如果您不使用fetch join,则需要在仍处于事务内部时访问延迟加载的属性:

myEntity.getLazyProp().size();
Run Code Online (Sandbox Code Playgroud)

请注意拨打电话size().调用getter是不够的,因为你将得到一个代理.您需要执行需要来自属性的实际数据的操作.


Ori*_*Dar 14

这是正常的JPA行为.

通过find()左右检索对象后,该对象被视为附加或属于持久性上下文.退出方法后,@Transactional触发Spring事务管理方面,将每个"脏"对象刷新到数据库并提交事务.因为你的对象持久化上下文和交易的范围内已经发生变化,这些变化甚至无需显式调用保存方法保存到数据库中.

如果要在不影响数据库的情况下更改对象,可以使用以下两个选项:

  1. 从带注释的方法返回后更新字段 @Transactional
  2. 如果使用该方法,请在实体管理器上调用detach