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

Spring 为什么@Transactional会自动保存到数据库,spring,jpa,transactional,Spring,Jpa,Transactional,我有一个用@Transactional注释的方法。我从数据库中检索一个对象,更改一个字段,然后从方法返回。在不保存我的对象的情况下,数据库会得到更新,这很奇怪 您能告诉我如何避免这种行为吗?这种行为是交易性的主要目的之一 在事务方法即将返回之前,事务将提交,这意味着对托管实体的所有更改都将刷新到数据库中 如果发生错误,事务将回滚,这意味着不会向数据库提交任何更改 当尝试访问延迟加载的属性(可能是来自实体的集合)时,您可能会遇到LazyInitializationException。当您从数据库获

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


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

这种行为是交易性的主要目的之一

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

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

当尝试访问延迟加载的属性(可能是来自实体的集合)时,您可能会遇到
LazyInitializationException
。当您从数据库获取实体时,延迟隐藏的属性不会被实例化

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

编辑:如果您希望加载惰性属性,并且能够在不将更改持久化到DB的情况下更改实体,则可以使用惰性属性的获取连接获取实体

em.createQuery("SELECT e FROM MyEntity e JOIN FETCH e.lazyProp");
然后继续使用@orid描述的方法之一

如果未使用fetch连接,则需要在事务内部访问延迟加载的属性:

myEntity.getLazyProp().size();

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

这是正常的JPA行为

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

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

  • 从带有
    @Transactional
  • 如果使用该方法,请调用实体管理器

  • 如果该方法不是事务性的,会发生什么?我实际上需要@transactional来避免LazyInitializationException。你对这方面的参考资料有什么建议吗?谢谢,凯文。我唯一可以推荐的资源是,因为这是我用来学习JPA的。第6章,EntityManager/事务管理可能是最好的查找位置。同样的知识也可以在Hibernate和Eclipselink文档中找到。感谢kosjta的回答非常有用,我的想法是,不调用更新数据就不会提交给DB。再次感谢:)不客气:)是的,容器管理的JPA在幕后做了一些比obvoius小的把戏。我真的可以推荐我上面链接的专业JPA2书籍。你好,kosjta,我回来只是想告诉你一件事。即使我使用readOnly=true来避免LazyInitializationException,同时不更新数据库,实际上数据库还是会得到更新!有什么想法吗?谢谢你的回答,我现在明白它是怎么工作的了;)