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

时间:2014-02-04 12:23:17

标签: spring jpa transactional

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

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

2 个答案:

答案 0 :(得分:15)

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

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

如果发生错误,将回滚事务,这意味着不会对数据库进行任何更改。

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

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

编辑:如果你想加载延迟属性并且能够在没有将更改持久保存到数据库的情况下更改你的实体,你可以获取具有延迟属性的获取连接的实体。

em.createQuery("SELECT e FROM MyEntity e JOIN FETCH e.lazyProp");

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

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

myEntity.getLazyProp().size();

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

答案 1 :(得分:13)

这是正常的JPA行为。

通过find()左右检索对象后,该对象被视为附加或属于持久性上下文。退出方法后,@Transactional将触发Spring事务管理方面,该方面将每个“脏”对象刷新到数据库并提交事务。由于您的对象已在持久性上下文和事务的上下文中更改,因此更改将保存到数据库中,即使不需要显式调用save方法。

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

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