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>
その理由は、オブジェクトを削除するために、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();
休止状態のこの独特の動作を理解するには、いくつかの休止状態の概念を理解することが重要です-
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'
ライフサイクルを処理します。
よくわかりませんが:
非一時オブジェクトで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はおそらく削除を関連付けられたエンティティにカスケードする必要があるかどうかを知るために、完全なエンティティをフェッチする必要があります。
使用する代わりに
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);
_
休止状態ではセッションの使用を避けてください、ここではわかりませんが、セッションの使用のために問題が発生します