web-dev-qa-db-ja.com

Hibernate Deleteクエリ

Dbからエントリを削除しようとすると、

session.delete(object) 

その後、私は次のことができます:

1)DBに行が存在する場合、2つのSQLクエリが実行されます:選択してから削除

2)行がDBに存在しない場合、選択クエリのみが実行されます

しかし、これもアップデートの場合ではありません。 DB行の存在に関係なく、更新クエリのみが実行されます。

削除操作に対するこのような動作の理由を教えてください。 1つではなく2つのクエリがヒットするため、パフォーマンスの問題ではありませんか?

編集:

Hibernate 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>
35
user182944

その理由は、オブジェクトを削除するために、Hibernateはオブジェクトが永続状態にあることを必要とするためです。したがって、Hibernateは最初にオブジェクトをフェッチし(SELECT)、次に削除します(DELETE)。

Hibernateが最初にオブジェクトを取得する必要があるのはなぜですか?理由は、Hibernateインターセプターが有効になっている可能性があるためです( http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/events.html )。オブジェクトを渡す必要がありますこれらのインターセプターを介してライフサイクルを完了します。データベースで行が直接削除された場合、インターセプターは実行されません。

一方、一括操作を使用して、1つの単一のSQL DELETEステートメントでエンティティを削除できます。

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

休止状態のこの独特の動作を理解するには、いくつかの休止状態の概念を理解することが重要です-

Hibernate Object States

一時的-オブジェクトは、インスタンス化されており、Hibernateセッションに関連付けられていない場合、一時的な状態になります。

永続-永続インスタンスには、データベース内の表現と識別子値があります。それは単に保存またはロードされただけかもしれませんが、セッションのスコープ内の定義によるものです。

切り離された-切り離されたインスタンスは永続的なオブジェクトですが、そのセッションは閉じられています。

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

Transaction Write-Behind

次に理解すべきことは、「トランザクションライトビハインド」です。 hibernateセッションにアタッチされたオブジェクトが変更されても、それらはすぐにデータベースに伝播されません。 Hibernateは、少なくとも2つの異なる理由でこれを行います。

  • バッチの挿入と更新を実行します。
  • 最後の変更のみを伝播します。オブジェクトが複数回更新された場合でも、1つの更新ステートメントのみが実行されます。

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

一次キャッシュ

Hibernateには「一次キャッシュ」と呼ばれるものがあります。オブジェクトをsave()update()、またはsaveOrUpdate()に渡すとき、およびload()get()list()iterate()またはscroll()を使用してオブジェクトを取得するたびに、そのオブジェクトはセッションの内部キャッシュに追加されます。これは、さまざまなオブジェクトへの変更を追跡する場所です。

Hibernateインターセプターとオブジェクトライフサイクルリスナー-

セッションからアプリケーションへのInterceptorインターフェースおよびリスナーコールバックにより、アプリケーションは、保存、更新、削除、またはロードする前に、永続オブジェクトのプロパティを検査および/または操作できます。 http://docs.jboss.org/hibernate/orm/4.0/hem/en-US/html/listeners.html#d0e3069


このセクションは更新されました

カスケード

Hibernateを使用すると、アプリケーションは関連付け間のカスケード関係を定義できます。たとえば、親から子への関連付けから'cascade-delete'を指定すると、親が削除されるとすべての子が削除されます。

だから、なぜこれらが重要なのか

トランザクションの書き込みビハインドを行い、オブジェクト(オブジェクトグラフ)への複数の変更を追跡し、ライフサイクルコールバックを実行できるようにするには、hibernateはオブジェクトがtransient/detachedであり、基礎となるオブジェクトと関連する関係に変更を加える前に、そのオブジェクトは一次キャッシュにあります。

そのため、休止状態(時々)'SELECT'ステートメントを発行して、オブジェクトをロードします(まだロードされていない場合)。変更を加えます。

休止状態で「SELECT」ステートメントが発行されるのはなぜですか?

Hibernateは'SELECT'ステートメントを発行して、オブジェクトの状態を判断します。selectステートメントがオブジェクトを返す場合、オブジェクトはdetached状態にあり、オブジェクトを返さない場合、オブジェクトはtransient状態。

シナリオに来る-

Delete-hibernateはデータベースにオブジェクトが存在するかどうかを知る必要があるため、 'Delete'はSELECTステートメントを発行しました。オブジェクトがデータベースに存在する場合、Hibernateはそれをdetachedと見なし、セッションに再アタッチし、ライフサイクルを削除します。

Update-'Update'の代わりに'SaveOrUpdate'を明示的に呼び出しているため、休止状態はオブジェクトがdetached状態。指定されたオブジェクトをセッションの第1レベルキャッシュに再アタッチし、更新ライフサイクルを処理します。休止状態の仮定に反してオブジェクトがデータベースに存在しないことが判明した場合、セッションのフラッシュ時に例外がスローされます。

SaveOrUpdate-'SaveOrUpdate'を呼び出す場合、Hibernateはオブジェクトの状態を判断する必要があるため、SELECTステートメントを使用してオブジェクトがTransient/Detached状態です。オブジェクトがtransient状態にある場合、'insert'ライフサイクルを処理し、オブジェクトがdetached状態にある場合、'Update'ライフサイクルを処理します。

22
Sashi

よくわかりませんが:

  • 非一時オブジェクトでdeleteメソッドを呼び出す場合、これは最初にDBからオブジェクトをフェッチしたことを意味します。したがって、selectステートメントが表示されるのは正常です。おそらく最後に2 select + 1 deleteが表示されますか?

  • 一時オブジェクトでdeleteメソッドを呼び出すと、cascade="delete"または同様の何か。最初にオブジェクトを取得する必要があるため、必要に応じて「ネストされたアクション」を実行できます。


編集:一時的なインスタンスでdelete()を呼び出すことは、そのようなことをすることを意味します:

MyEntity entity = new MyEntity();
entity.setId(1234);
session.delete(entity);

これは、オブジェクトがHibernateによって取得されず、セッションキャッシュに存在せず、Hibernateによってまったく管理されない単純なpojoである場合でも、ID 1234の行を削除します。

エンティティの関連付けがある場合、Hibernateはおそらく削除を関連付けられたエンティティにカスケードする必要があるかどうかを知るために、完全なエンティティをフェッチする必要があります。

3

使用する代わりに

session.delete(オブジェクト)

つかいます

_getHibernateTemplate().delete(object)
_

selectクエリとdeleteの両方の場所でgetHibernateTemplate()を使用します

selectクエリでは、DetachedCriteriaまたはCriteriaを使用する必要があります

選択クエリの例

_List<foo> fooList = new ArrayList<foo>();
DetachedCriteria queryCriteria = DetachedCriteria.forClass(foo.class);
queryCriteria.add(Restrictions.eq("Column_name",restriction));
fooList = getHibernateTemplate().findByCriteria(queryCriteria);
_

休止状態ではセッションの使用を避けてください、ここではわかりませんが、セッションの使用のために問題が発生します

1
Jubin Patel