为什么在Hibernate中调用session.delete()之后需要调用session.flush()?

Gau*_*tel 6 java spring 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. 
Run Code Online (Sandbox Code Playgroud)

但是,如果我在删除后调用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;
    ...
    ...
Run Code Online (Sandbox Code Playgroud)

弹簧配置文件

    <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>
Run Code Online (Sandbox Code Playgroud)

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;
    }
    ...
    ...
Run Code Online (Sandbox Code Playgroud)

更新:

我的困境主要是由于不一致.. session.save立即插入记录但session.delete没有反映,除非显式调用flush().但是,当我参考Afsun发布的Flushing the Session链接时,通过阅读以下行清除了我的疑虑,

一个例外是在保存时会插入使用本机ID生成的对象.

我非常感谢大家发布的答案,因为几乎所有人都指向正确的方向,但Afsun完全清除了我的怀疑.谢谢!

Tim*_*sen 6

来自Hibernate Session 类的Javadoc

刷新是将底层持久存储与保存在内存中的持久状态同步的过程。

当你打电话给session.delete()你时,你告诉 Hibernate 从被管理的实体中删除。但是,相应的记录仍将存在于底层数据库中。您需要调用 以session.flush()将数据库与 Hibernate 会话同步。请注意,如果您的程序在没有您调用的情况session.flush()下结束,那么下次您再次启动应用程序时,相关实体将重新出现。


Afs*_*dli 5

当您使用Hibernate处理数据库时Hibernate session.Hibernate sessions通过以下三种情况刷新到数据库.

  1. commit()- 提交交易时
  2. 在运行查询之前
  3. 你打电话的时候 session.flush()

这里最重要的是第二个.每次查询后都不Hibernate session刷新数据库.如果我们Native SQL Query通过Hibernate 运行,Hibernate不知道刷新会话还是运行HQLHibernate也不知道刷新会话.对flush的调用将使会话状态与数据库同步.

请参阅以下内容: 休眠刷新之前,删除法拉盛会议