我有一个被 @Transactional 注释的方法。 我从数据库中检索一个对象,更改一个字段,然后从该方法返回。 没有保存我的对象,但数据库仍会更新,这很奇怪。
请告诉我如何避免这种行为?
我有一个被 @Transactional 注释的方法。 我从数据库中检索一个对象,更改一个字段,然后从该方法返回。 没有保存我的对象,但数据库仍会更新,这很奇怪。
请告诉我如何避免这种行为?
这是JPA的正常行为。
一旦您通过find()
或其他方式检索到对象,该对象被视为已附加或属于持久性上下文。一旦退出方法,@Transactional
触发Spring事务管理方面,将每个“脏”对象刷新到数据库并提交事务。由于您的对象已在持久性上下文和事务的上下文中进行了更改,因此即使不需要显式调用保存方法,更改也会保存到数据库中。
如果要更改对象而不影响数据库,则有两个选项:
@Transactional
注解的方法返回后更新字段这种行为是事务性的主要目的之一。
在事务方法即将返回之前,事务会提交,意味着对托管实体所做的所有更改都被刷新到数据库中。
如果发生错误,事务将被回滚,意味着不会向数据库提交任何更改。
当尝试访问惰性加载属性(可能是实体的集合)时,您可能会遇到LazyInitializationException
。惰性加载属性在从数据库中提取实体时不会被实例化。
如果在事务中访问惰性加载属性,持久性提供程序将创建一个查询,实例化结果并将其附加到“父”实体。
编辑:如果您想要加载延迟属性,并且能够更改实体而不将更改持久化到数据库中,则可以使用fetch joins获取具有惰性属性的实体。
em.createQuery("SELECT e FROM MyEntity e JOIN FETCH e.lazyProp");
然后按照@orid描述的任一方法继续进行。
如果您没有使用fetch joins,则需要在事务内部访问延迟加载的属性:
myEntity.getLazyProp().size();
请注意调用 size()
方法。仅调用 getter 方法是不够的,因为您将得到一个代理。您需要执行需要来自属性的实际数据的操作。