40

データベースからエントリを削除しようとすると、

session.delete(object) 

次に、次のことができます。

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

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

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

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

編集:

休止状態 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>

4

4 に答える 4

83

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

Hibernate が最初にオブジェクトを取得する必要があるのはなぜですか? その理由は、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();
于 2012-11-05T21:50:34.577 に答える
24

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

オブジェクトの休止状態

Transient - オブジェクトがインスタンス化され、まだ 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 には「First Level Cache」と呼ばれるものがあります。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'親から子への関連付けでは、親が削除されるとすべての子が削除されます。

では、なぜこれらが重要なのでしょうか。

トランザクションのライト ビハインドを実行できるようにするため、オブジェクト (オブジェクト グラフ) への複数の変更を追跡できるようにするため、およびライフサイクル コールバックを実行できるようにするために、休止状態はオブジェクトがそうであるかどうかを知るtransient/detached必要があり、オブジェクトを最初のレベルに置く必要があります。基になるオブジェクトと関連する関係に変更を加える前にキャッシュします。

そのため、hibernate は(場合によって'SELECT'は)オブジェクトに変更を加える前に、オブジェクト (まだロードされていない場合) を最初のレベルのキャッシュにロードするステートメントを発行します。

hibernate が「SELECT」ステートメントを時々しか発行しないのはなぜですか?

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

あなたのシナリオに来て-

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

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

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

于 2012-11-06T13:31:56.920 に答える
3

よくわかりませんが:

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

  • 一時的なオブジェクトで delete メソッドを呼び出す場合、cascade="delete"必要に応じて「ネストされたアクション」を実行できるように、最初にオブジェクトを取得する必要がある、または同様のものがある可能性があります。


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

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

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

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

于 2012-11-04T13:15:24.473 に答える
1

使用する代わりに

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

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

于 2012-11-09T09:28:44.210 に答える