休眠删除查询

2022-09-01 03:27:12

当我尝试从数据库中删除条目时,使用

session.delete(object) 

那么我可以以下:

1) 如果该行存在于 DB 中,则执行两个 SQL 查询:选择,然后删除

2) 如果该行不存在于数据库中,则仅执行选择查询

但同样,更新并非如此。无论是否存在 DB 行,都只执行更新查询。

请让我知道为什么这种行为删除操作。这不是一个性能问题,因为两个查询被击中而不是一个?

编辑:

我正在使用休眠 3.2.5

示例代码:

SessionFactory sessionFactory = new Configuration().configure("student.cfg.xml").buildSessionFactory();
    Session session = sessionFactory.openSession();
    Student student = new Student();
    student.setFirstName("AAA");
    student.setLastName("BBB");
    student.setCity("CCC");
    student.setState("DDD");
    student.setCountry("EEE");
    student.setId("FFF");
    session.delete(student);
    session.flush();
            session.close();

cfg.xml

<property name="hibernate.connection.username">system</property>
    <property name="hibernate.connection.password">XXX</property>
    <property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver</property>
    <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521/orcl</property>      
    <property name="hibernate.jdbc.batch_size">30</property>
    <property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
    <property name="hibernate.cache.use_query_cache">false</property>
    <property name="hibernate.cache.use_second_level_cache">false</property>
    <property name="hibernate.connection.release_mode">after_transaction</property>
    <property name="hibernate.connection.autocommit">true</property>
    <property name="hibernate.connection.pool_size">0</property>
    <property name="hibernate.current_session_context_class">thread</property>    
    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.hbm2ddl.auto">update</property>        

hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.infy.model.Student" table="STUDENT">
    <id name="id" column="ID">
        <generator class="assigned"></generator>
    </id>
    <property name="firstName" type="string" column="FIRSTNAME"></property>
    <property name="lastName" type="string" column="LASTNAME"></property>
    <property name="city" type="string" column="CITY"></property>
    <property name="state" type="string" column="STATE"></property>
    <property name="country" type="string" column="COUNTRY"></property>        
</class>


答案 1

原因是,对于删除对象,Hibernate 要求该对象处于持久状态。因此,休眠首先获取对象 (SELECT),然后将其删除 (DELETE)。

为什么休眠需要先获取对象?原因是可能启用了 Hibernate 拦截器(http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/events.html),并且必须通过这些拦截器传递对象才能完成其生命周期。如果直接在数据库中删除行,则拦截器将不会运行。

另一方面,可以使用批量操作在单个 SQL DELETE 语句中删除实体:

Query q = session.createQuery("delete Entity where id = X");
q.executeUpdate();

答案 2

要了解这种特殊的休眠行为,重要的是要了解一些休眠概念 -

休眠对象状态

瞬态 - 如果对象已实例化并且仍未与休眠会话关联,则该对象处于瞬态状态。

持久性 - 持久性实例在数据库中具有表示形式和标识符值。它可能只是被保存或加载,但是,根据定义,它位于会话的范围内。

已分离 - 已分离的实例是已持久存在但其会话已关闭的对象。

http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/objectstate.html#objectstate-overview

事务写后

接下来要理解的是“事务写入后面”。当附加到休眠会话的对象被修改时,它们不会立即传播到数据库。Hibernate这样做至少有两个不同的原因。

  • 执行批处理插入和更新。
  • 仅传播最后一个更改。如果一个对象被多次更新,它仍然只触发一个更新语句。

http://learningviacode.blogspot.com/2012/02/write-behind-technique-in-hibernate.html

第一级缓存

休眠有一种叫做“一级缓存”的东西。每当将对象传递给 或 时,以及每当使用 、 、 或 检索对象时,该对象都会添加到 Session 的内部缓存中。这是它跟踪对各种对象的更改的地方。save()update()saveOrUpdate()load()get()list()iterate()scroll()

休眠拦截器和对象生命周期侦听器 -

从会话到应用程序的 Interceptor 接口和侦听器回调允许应用程序在保存、更新、删除或加载持久性对象之前检查和/或操作持久性对象的属性。http://docs.jboss.org/hibernate/orm/4.0/hem/en-US/html/listeners.html#d0e3069


本节已更新

级 联

休眠允许应用程序定义关联之间的级联关系。例如,从父项到子项的关联将导致在删除父项时删除所有子项。'cascade-delete'

那么,为什么这些很重要。

为了能够执行事务写后,为了能够跟踪对对象(对象图)的多个更改,并且能够执行生命周期回调休眠,需要知道对象是否是,并且在对基础对象和关联关系进行任何更改之前,它需要将对象放在它的第一级缓存中。transient/detached

这就是为什么休眠(有时)发出一个语句,在对对象进行更改之前,将对象(如果尚未加载)加载到它的第一级缓存中。'SELECT'

为什么休眠只偶尔发出“SELECT”语句?

休眠发出一个语句来确定对象处于什么状态。如果 select 语句返回一个对象,则该对象处于状态,如果它不返回一个对象,则该对象处于状态。'SELECT'detachedtransient

进入您的场景 -

删除 - “删除”发出 SELECT 语句,因为休眠需要知道数据库中是否存在该对象。如果数据库中存在该对象,则休眠会将其视为对象,然后将其重新附加到会话并处理删除生命周期。detached

更新 - 由于您是显式调用而不是 ,因此休眠会盲目地假定对象处于状态,将给定对象重新附加到会话第一级缓存并处理更新生命周期。如果事实证明数据库中不存在该对象,则与休眠的假设相反,则在会话刷新时会引发异常。'Update''SaveOrUpdate'detached

SaveOrUpdate - 如果调用 ,休眠必须确定对象的状态,因此它使用 SELECT 语句来确定对象是否处于状态。如果对象处于状态,它将处理生命周期,如果对象处于状态,它将处理生命周期。'SaveOrUpdate'Transient/Detachedtransient'insert'detached'Update'


推荐