60

我有一个用@Transactional 注释的方法。我从我的 Oracle DB 中检索一个对象,更改一个字段,然后从该方法返回。我忘了保存对象,但发现数据库无论如何都会更新。

应用上下文

<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

我的方法

@Transactional
public void myMethod(long id) {
    MyObject myObj = dao.getMstAttributeById(id);
    myObj.setName("new name");
    //dao.update(myObj);
}

我的问题是为什么 MyObject 会持久化到数据库中?

4

5 回答 5

76

因为hibernate会自动检测对持久实体所做的更改并相应地更新数据库。这种行为记录在hibernate 参考手册的第 11 章中。相关部分内容如下:

Hibernate 定义并支持以下对象状态:

  • Transient - 如果一个对象刚刚使用 new 运算符实例化,并且它不与 Hibernate Session 关联,则它是瞬态的。它在数据库中没有持久表示,也没有分配标识符值。如果应用程序不再持有引用,垃圾收集器将销毁瞬态实例。使用 Hibernate Session 使对象持久化(并让 Hibernate 处理需要为此转换执行的 SQL 语句)。

  • 持久性- 持久性实例在数据库中具有表示形式和标识符值。它可能刚刚被保存或加载,但是,根据定义,它在 Session 的范围内。Hibernate 将检测对处于持久状态的对象所做的任何更改,并在工作单元完成时将状态与数据库同步。开发人员不执行手动 UPDATE 语句,或在对象应为瞬态时执行 DELETE 语句。

  • Detached - 一个分离的实例是一个已经被持久化的对象,但是它的 Session 已经被关闭了。当然,对对象的引用仍然有效,分离的实例甚至可能在这种状态下被修改。一个分离的实例可以在稍后的时间点重新附加到一个新的 Session 上,使其(以及所有修改)再次持久化。此功能为需要用户思考时间的长时间运行的工作单元启用了编程模型。我们称它们为应用事务,即从用户的角度来看的一个工作单元。

于 2011-11-19T00:51:02.970 回答
14

如果您使用的是 JPA,那么规范说明如果您的实体处于托管状态(这是您通过在活动事务中从 DAO 获取数据所做的事情),对其所做的所有更改都将反映在事务提交期间的数据库。

因此,换句话说 -是否调用更新操作并不重要,因为事务提交会将更改刷新到数据库。

于 2011-11-19T00:47:24.937 回答
6

我曾经@Transactional(readOnly = true)解决它

于 2019-02-12T07:51:16.397 回答
4

我发现防止自动更新数据库是一个两步过程。

第一步::

getSession().setFlushMode(FlushMode.MANUAL) // [FlushMode.NEVER is depracated in 4.x]

第二步:

getSession().clear(); //This will actually discard all changes
于 2014-04-10T09:46:51.353 回答
2

对于 JPA,调用entityManager.detach(entity)以避免自动刷新。但是你需要注意的是,分离的实体将失去 ORM 魔法,例如延迟获取、级联更新。

于 2019-03-20T10:02:43.640 回答