![](/img/trans.png)
[英]Does a Hibernate transaction rollback delete “session.flush()”ed entities?
[英]Why is it necessary to call session.flush() after session.delete() in Hibernate?
问题是以下代码片段不会删除DB中的记录。
import org.hibernate.Session;
import org.hibernate.SessionFactory;
...
...
void deleteForm() {
Session session = sessionFactory.openSession();
FormDO formDO = new FormDO();
formDO.setId(formId);
session.delete(formDO); // No delete SQL query is getting fired.
但是,如果我在删除后调用session.flush() ,它可以正常工作。 请注意,我没有使用任何交易。
在Session类的JavaDoc中,delete方法的描述是:
从数据存储中删除持久性实例。 该参数可以是与接收会话相关联的实例,或者是具有与现有持久状态相关联的标识符的瞬态实例 。
我在网上看到很多代码片段,表明没有必要在delete()之后调用flush()。 其他论坛也在这里提出了类似的问题,但仍未得到答复。
另外,session.save在没有session.flush的情况下工作正常。
我正在使用Hibernate 4.2.16 + Spring 4.0.9 + JPA 1.0注释。 以下是供进一步参考的源文件,
FormDO.java
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="form")
public class FormDO {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id")
Integer id;
@Column(name="name")
String name;
...
...
弹簧配置文件
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/tempdb" />
<property name="username" value="root" />
<property name="password" value="****" />
</bean>
<!-- Hibernate 4 SessionFactory Bean definition -->
<bean id="hibernate4AnnotatedSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" >
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.test.FormDO</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
FormDAO.java
@Named
public class FormDAO {
@Inject
private SessionFactory sessionFactory;
public boolean deleteForm(Integer formId) {
Session session = sessionFactory.openSession();
FormDO formDO = new FormDO();
formDO.setId(formId);
session.delete(formDO);
session.flush(); // If this line is commented, record DOES NOT get deleted
return true;
}
public boolean saveForm(FormDO formDO) {
Session session = sessionFactory.openSession();
session.save(formDO); // Save doesn't require session.flush
return true;
}
...
...
更新:
我的困境主要是由于不一致.. session.save立即插入记录但session.delete没有反映,除非显式调用flush()。 但是,当我参考Afsun发布的Flushing the Session链接时,通过阅读以下行清除了我的疑虑,
一个例外是在保存时会插入使用本机ID生成的对象。
我非常感谢大家发布的答案,因为几乎所有人都指向正确的方向,但Afsun完全清除了我的怀疑。 谢谢!
当您通过Hibernate使用数据库时,您正在使用Hibernate session
。 Hibernate sessions
通过以下三种情况刷新到数据库。
commit()
- 提交事务时 session.flush()
这里最重要的是第二个。 每次查询后都没有Hibernate session
刷新数据库。 如果我们通过Hibernate运行Native SQL Query
,Hibernate不知道刷新会话,或者如果运行HQL
Hibernate也不知道刷新会话。 对flush的调用将使会话状态与数据库同步。
请参阅以下内容: 删除前刷新Hibernate和刷新 会话
从Javadoc for Hibernate Session类:
刷新是将底层持久存储与内存中保持的可持久状态同步的过程。
当您调用session.delete()
您告诉Hibernate从实体中删除该实体。 但是,相应的记录仍将存在于底层数据库中。 您需要调用session.flush()
才能将数据库与Hibernate会话同步。 请注意,如果您的程序在没有调用session.flush()
下结束,则下次再次启动应用程序时,相关实体将重新出现。
flush()此方法强制当前会话刷新。 必须在提交事务并关闭会话之前在工作单元结束时调用(取决于flush模式,Transaction.commit()调用此方法)。 刷新是将底层持久存储与内存中保持的可持久状态同步的过程。
因此,在调用delete时必须刷新会话,否则删除的记录仍将存在于基础数据库中。 此外,您还没有关闭正在打开的会话。当您开始使用池化机制时,这可能会出现问题。 在大多数情况下,最佳实践是每个请求的会话。关闭会话将始终将工作清理到数据库。
您还需要在批处理中进行刷新,否则可能会产生OutOfMemoryException。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.