当前位置: 首页 > 知识库问答 >
问题:

为什么有必要在session.delete()之后调用session.flush()?

赫连华皓
2023-03-14

问题是下面的代码片段没有删除数据库中的记录。

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()。在这里的其他论坛上也提出了类似的问题,但仍未得到回答。

还有,会话。“保存”在没有会话的情况下可以正常工作。脸红

我使用的是HiberNate 4.2.16 Spring 4.0.9 JPA 1.0注解。以下是源文件供进一步参考,

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;
    ...
    ...

Spring配置文件

    <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发布的冲洗会话链接时,我的疑虑通过阅读下面的一行得到了澄清,

例外情况是,保存时会插入使用本机ID生成的对象。

我真的很感激大家给出的答案,因为几乎所有的答案都指向了正确的方向,但Afsun完全消除了我的疑虑。谢谢

共有3个答案

闾丘成双
2023-03-14

flush()此方法强制当前会话刷新。必须在工作单元结束时调用,然后提交事务并关闭会话(取决于flush模式,Transaction.commit()调用此方法)。刷新是将基础持久存储与内存中的持久状态同步的过程。

因此,调用delete时需要刷新会话,否则被删除的记录仍将存在于基础数据库中 此外,您没有关闭正在打开的会话。当您开始使用池机制时,可能会出现这个问题。在大多数情况下,最佳做法是每次请求会话。关闭会话总是会将所有工作刷新到数据库中
您还需要在批处理中刷新,否则它可能会发出OutOfMemoryException。

范彭亮
2023-03-14

从Hibernate会话类的Javadoc:

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

当你呼叫会话时。delete()告诉Hibernate从管理中删除实体。但是,相应的记录仍将存在于基础数据库中。你需要调用会话。flush()以便将数据库与Hibernate会话同步。请注意,如果程序在没有调用会话的情况下结束。flush()然后下次再次启动应用程序时,相关实体将重新出现。

佘飞鸣
2023-03-14

通过Hibernate处理数据库时,您使用的是Hibernate会话<代码>Hibernate会话通过以下三种情况刷新到数据库

  1. commit()-提交事务时
  2. 在运行查询之前
  3. 当你调用会话时。flush()

这里最重要的是第二个。每次查询后都不会Hibernate会话刷新数据库。如果我们通过Hibernate运行Native SQL查询,Hibernate不知道刷新会话,或者如果运行HQL,Hibernate也不知道刷新会话。对flush的调用将使会话状态与数据库同步请参见以下内容:在删除和刷新会话之前先Hibernate刷新

 类似资料:
  • React引入了新的静态方法,它在每个呈现方法之前都会被调用,但为什么呢?在prop change之后调用它对我来说是有意义的,但是在之后调用它就没有意义了,也许我错过了什么。 我根据公司的要求创建了一个组件,在组件中日期是从道具控制的。我在组件中有以下状态。 是的,我在中创建了一个额外的变量来跟踪是否由于而被调用,但我认为这不是正确的方法。 或者是我做错了什么或者遗漏了什么,或者不应该在之后调用

  • 问题内容: 我只是想简化我的一个类,并以与flyweight设计模式相同的样式介绍了一些功能。 但是,对于为什么总是调用after ,我有点困惑。我没想到这一点。谁能告诉我为什么会这样,否则我如何实现此功能?(除了将实现放入hack之外)。 这是一个例子: 输出: 为什么? 问题答案: 使用 时,你需要控制一个新实例的创建。 使用 时,你需要一个新的实例的控件初始化。 是实例创建的第一步。首先调用

  • 本文向大家介绍为什么在__new __()之后总是调用__init __()?,包括了为什么在__new __()之后总是调用__init __()?的使用技巧和注意事项,需要的朋友参考一下 Python具有一种称为魔术方法的特殊类型的方法,该方法以前置和双下划线命名。 如果我们想谈论魔术方法__new__,那么显然也需要谈论__init__方法。创建实例时将调用魔术方法__new__。而在创建实

  • 根据Spring Doc API http://docs.Spring.io/Spring-framework/docs/current/javadoc-api/index.html?org/springframework/web/context/contextloaderlistener.html- 这个(ContextLoaderListener)监听器应该注册在web.xml中的Log4jC

  • 问题内容: 我只是想简化我的一个类,并以与flyweight设计模式相同的样式介绍了一些功能。 但是,对于为什么总是被称为after ,我有点困惑。我没想到这一点。谁能告诉我为什么会这样,否则我如何实现此功能?(除了将实现放到中之外)。 这是一个例子: 输出: 为什么? 问题答案: 使用时,你需要控制一个新实例的创建。 使用 时,你需要一个新的实例的控件初始化。 是实例创建的第一步。首先调用它,它

  • 问题内容: 我正在尝试计算列表中值的平方和。以下是三个均计算所需值的变体。我想知道哪个是最有效的。我希望第三个装箱效率更高,因为自动装箱仅执行一次。 问题答案: 如有疑问,请测试!使用jmh,我在100k元素的列表上得到以下结果(以微秒为单位,更好): 因此,从快到慢,您已经拥有: 和 请注意,结果在很大程度上取决于JIT优化。如果映射中的逻辑更加复杂,则某些优化可能不可用(较长的代码=较少的内联