1. Get は遅延をサポートしませんが、load は遅延をサポートします。
2. データをロードするには get を使用します。一致するデータがない場合は null が返され、load は例外をスローします。
3.load() を実行するときは、まず現在のオブジェクトが存在するかどうかを確認します。存在しない場合は、get( の実行時に例外がスローされます)。 )、現在のオブジェクトがセッションに存在するかどうかに関係なく、データベースから直接クエリが実行され、存在しない場合は null が返されます。
4.load() メソッドはエンティティのプロキシ クラス インスタンスを返すことができますが、get() は常にエンティティ クラスのみを返します。
get 例:
1public void testGetMethod() {
2 セッション session = null;
3 try {
4 session = HibernateUtils.getSession();
6
7 ; //すぐにクエリSQLを発行してUserオブジェクトをロードします
8 User user = (User)session.get(User.class, "402880d01b9bf210011b9bf2c2ff0002");
9 System.out.println("user.name=" + user.getName(); );
10
11 user.setName("张三");
12 session.getTransaction().commit();
14 e.printStackTrace(); () .rollback();
16 }finally {
17 HibernateUtils.closeSession(session);
18 }
19 }
追記:データベースに関連するレコードがある場合、SQL ステートメントは9 行目に user.getName() メソッド呼び出しがなくても、一致するレコードがない場合は null が返されます。
loadメソッドの例:
1public void testLoadMethod() {
2 Session session = null;
3 try {
4 session = HibernateUtils.getSession();
6
7 ///ロードメソッドが遅延(遅延ロードまたは遅延ロード)を実装しているため、クエリsqlは発行されません
8 //遅延ロード: このオブジェクトが実際に使用される場合のみ、ロードされます(SQL文が発行されます)
9 //実装Hibernateの遅延読み込みの原理はProxyメソッドです
10 User user = (User)session.load(User.class, "402880d01b9bf210011b9bf2b2ff0002");
11 System.out.println("user.name=" + user.getName()); ;
12 user.setName ("李思");
13 session.getTransaction().commit();
15 e.printStackTrace(); rollback();
17 }finally {
18 HibernateUtils.closeSession(session);
19 }
20 }
PS:load は遅延遅延ロードを実装しているため、SQL ステートメントはすぐに発行されませんでした。遅延ロードは実際の環境でのみ使用できます。オブジェクトがロードされるのは、11 行のコードです。ロード メソッドの ID がデータベース テーブルに関連していない場合、ObjectNotFoundException 例外が発行されます。
追記: ブレークポイントを設定し、デバッグを使用して関連する変数やオブジェクトの変更を追跡できるため、load メソッドと get メソッドを明確に理解できます。
休止状態、セッションロードからのオブジェクトは
です
永続状態: オブジェクトはデータベース レコードとの対応関係を確立し、同期を維持します。オブジェクトは永続コンテキストにバインドされており、将来の状態変更やデータ変更はワークユニットの管理下にあります。これが永続状態です。 Session.load は、hibernate3.2 で提供されるデフォルトの遅延読み込みメソッドです。ロードされるのは永続的とも言えるプロキシだと思います (私はこのように理解しています。間違っていたら専門家に修正してもらってください) )。
遅延読み込みを理解することは、遅延読み込みを理解するのに役立ちます:
遅延ロード メカニズムは、不要なパフォーマンスのオーバーヘッドを回避するために提案されています。いわゆる遅延ロードとは、データが実際に必要な場合にのみデータ ロード操作が実行されることを意味します。 Hibernate はエンティティ オブジェクトの遅延ロードとコレクションの遅延ロードを提供します。さらに、Hibernate3 はプロパティの遅延ロードも提供します。以下では、これらのタイプの遅延読み込みの詳細をそれぞれ紹介します。
A. エンティティ オブジェクトの遅延ロード:
エンティティ オブジェクトに遅延ロードを使用する場合は、以下に示すように、エンティティのマッピング構成ファイルでそれを構成する必要があります。 ;クラス名=”com.neusoft.entity.User”テーブル=”ユーザー”lazy=”true”>
……
クラスの Lazy 属性を true に設定して、エンティティの遅延読み込み機能を有効にします。次のコードを実行すると:
User=(User)session.load(User.class,”1”) (1)
System.out.println(user.getName()); (1) を実行すると、Hibernate はデータのクエリを開始しません。この時点で、いくつかのデバッグ ツール (JBuilder2005 のデバッグ ツールなど) を使用してユーザー オブジェクトのメモリ スナップショットを観察すると、驚くでしょう。この時点で返されるのは User$EnhancerByCGLIB$$bede8986 型のオブジェクトである可能性があり、その属性は null です。何が起こっているのでしょうか? session.load() メソッドはエンティティ オブジェクトのプロキシ クラス オブジェクトを返すと前述したことを思い出してください。ここで返されるオブジェクト タイプは、User オブジェクトのプロキシ クラス オブジェクトです。 Hibernate では、CGLIB を使用してターゲット オブジェクトのプロキシ クラス オブジェクトを動的に構築します。プロキシ クラス オブジェクトにはターゲット オブジェクトのすべてのプロパティとメソッドが含まれており、すべてのプロパティには null が割り当てられます。デバッガによって表示されるメモリ スナップショットから、この時点で実際の User オブジェクトがプロキシ オブジェクトの CGLIB$CALBACK_0.target 属性に含まれていることがわかります。コードが (2) まで実行されると、user.getName( が呼び出されます。このとき、CGLIB によって提供されるコールバック メカニズムを通じて、CGLIB$CALBACK_0.getName() メソッドが実際に呼び出されます。このメソッドを呼び出すと、Hibernate はまず CGLIB$CALBACK_0.target 属性が null かどうかを確認します。 null でない場合は、ターゲット オブジェクトの getName メソッドを呼び出します。空の場合は、データベース クエリが開始され、次のような SQL ステートメントが生成されます。データをクエリし、ターゲット オブジェクトを構築し、それを CGLIB $CALBACK_0.target 属性に割り当てます。
このように、中間プロキシ オブジェクトを通じて、Hibernate はエンティティの遅延読み込みを実装します。ユーザーが実際にエンティティ オブジェクトの属性を取得するアクションを開始した場合にのみ、データベース クエリ操作が実際に開始されます。したがって、エンティティの遅延ロードは中間プロキシ クラスを通じて完了するため、エンティティの遅延ロードを使用するのは session.load() メソッドのみです。これは、 session.load() メソッドのみがエンティティのプロキシ クラス オブジェクトを返すためです。クラス。
B. コレクション型の遅延読み込み:
Hibernate の遅延読み込みメカニズムでは、パフォーマンスを大幅に向上させることができるため、コレクション型の適用が最も重要であり、Hibernate はこの目的のために多くの作業を行ってきました。私たちの取り組みには、JDK コレクションの独立した実装が含まれます。1 対多の関係では、関連するオブジェクトを収容するために定義する Set コレクションは java.util.Set タイプまたはそのサブタイプではなく、hibernate.collection.Set です。 Hibernate は、カスタム コレクション クラスの実装を使用して、コレクション型の遅延ロードを実装します。コレクション型に遅延読み込みを使用するには、エンティティ クラスの関連付け部分を次のように構成する必要があります。
…..
User=(User)session.load(User.class,”1”);
Collection addset=user.getAddresses() (1)
Iterator it=addset.iterator ( ); (2)
while(it.hasNext()){
Address address=(Address)it.next();
System.out.println(address.getAddress());
(1)までプログラムを実行すると、この時点では関連付けは開始されませんデータ クエリは関連データのロードに使用されます。(2) に達した場合にのみ、Hibernate はキャッシュ内の修飾されたデータ インデックスに基づいて修飾されたエンティティ オブジェクトを検索します。
ここで新しい概念であるデータインデックスを紹介します。まずデータインデックスとは何かを見てみましょう。 Hibernate でコレクション タイプをキャッシュする場合、コレクション タイプは 2 つの部分に分けてキャッシュされます。まず、コレクション内のすべてのエンティティの ID リストがキャッシュされ、次に、これらのエンティティ オブジェクトの ID リストがキャッシュされます。索引。データ インデックスを検索するときに、対応するデータ インデックスが見つからない場合は、選択 SQL が実行されて修飾されたデータが取得され、エンティティ オブジェクトとデータ インデックスのコレクションが構築され、エンティティ オブジェクトのコレクションが返されて、エンティティ オブジェクトが追加されます。そしてデータは Hibernate のキャッシュにインデックス付けされます。一方、対応するデータインデックスが見つかった場合は、データインデックスから id リストを取り出し、その id に基づいてキャッシュ内で対応するエンティティを検索し、見つかった場合はキャッシュから返します。見つからない場合は、選択 SQL クエリが開始されます。ここでは、パフォーマンスに影響を与える可能性のある別の問題、それがコレクション型のキャッシュ戦略であることがわかります。コレクションタイプを次のように設定すると:
…..
<キャッシュ使用量=”読み取り専用”/>
<一対多クラス=”com.neusoft.entity.Arderss ”/>
セット>
この戦略を使用してコレクション タイプを設定する場合、Hibernate はデータ インデックスはキャッシュされますが、コレクション内のエンティティ オブジェクトはキャッシュされません。上記の構成に従って、次のコードを実行します。
User user=(User)session.load(User.class,”1”);
Collection addset=user.getAddresses(); () ; println("2 番目のクエリ...");
ユーザー user2=(User)session.load(User.class,"1"); it2.hasNext( )){
Address address2=(Address)it2.next();
System.out.println(address2.getAddress());
このコードを実行すると、次のような出力が得られます。
ID='1' のユーザーから * を選択;
ID='2' のアドレスから * を選択
天津
大連
クエリが 2 回目に実行されると、アドレス テーブルに対して 2 つのクエリ操作が実行されることがわかります。これはなぜでしょうか。これは、エンティティが初めてロードされるとき、コレクション タイプのキャッシュ戦略の構成に従って、コレクション データ インデックスのみがキャッシュされ、コレクション内のエンティティ オブジェクトはキャッシュされないためです。もう一度、Hibernate は対応するエンティティのデータ インデックスを見つけましたが、データ インデックスによると、キャッシュ内で対応するエンティティを見つけることができなかったため、Hibernate は見つかったデータ インデックスに基づいて 2 つの選択 SQL クエリ操作を開始しました。パフォーマンスの無駄を引き起こす可能性があります。どうすれば回避できますか?コレクション タイプのエンティティのキャッシュ戦略も指定する必要があるため、コレクション タイプを次のように構成する必要があります。
…..
<キャッシュの使用法=”読み取り-書き込み”/>
<一対多のクラス=”com.neusoft.entity.Arderss ”/>
セット>
この時点で、この設定に従って上記のコードを再度実行すると、次のような出力が得られます。以下:
id='1' のユーザーから * を選択
user_id='1' のアドレスから * を選択;現時点では、コレクション型に格納されているエンティティ オブジェクトはキャッシュから直接取得できるため、データ インデックスに基づいてクエリを実行する SQL ステートメントはなくなります。
C、プロパティの遅延読み込み:
Hibernate3 では、プロパティの遅延ロードという新機能が導入され、このメカニズムは高パフォーマンスのクエリを取得するための強力なツールを提供します。先ほどビッグ データ オブジェクトの読み取りについて説明しましたが、User オブジェクトには履歴書フィールドがあります。このフィールドは java.sql.Clob タイプであり、オブジェクトをロードするときに毎回ロードする必要があります。このフィールドは、本当に必要かどうかに関係なくロードする必要があり、この大きなデータ オブジェクト自体を読み取ると、パフォーマンスに多大なオーバーヘッドが生じます。 Hibernate2 では、前述したように、パフォーマンスを細かくセグメンテーションして User クラスを分解することによってのみこの問題を解決できます (そのセクションの説明を参照してください)。しかし Hibernate3 では、属性の遅延読み込みメカニズムを使用できるため、このフィールドを操作する必要がある場合にのみ、このフィールドのデータを読み取る機能を取得できます。このため、エンティティ クラスを次のように構成する必要があります。 ”com.neusoft.entity.User” table=”user”>
……
Hibernate3 のプロパティの遅延ロードを実現するには、
String sql=”from User user where user.name='zx' ”;
Query query=session.createQuery(sql); =query .list();
for(int i=0;i
ユーザー user=(User)list.get(i); user.getName());
System.out.println(user.getResume()); (2)
}
実行が (1) に達すると、次のような SQL ステートメントが生成されます。 Select id, age,name from user where name='zx';
このとき、Hibernate は (2) と同様の SQL ステートメントを実行すると、User エンティティ内のすべての非遅延読み込み属性に対応するフィールド データを取得します。
ID='1' のユーザーから履歴書を選択
;存在しないレコードをロードすると
従業員employee2 = (Employee) session.load(Employee.class, new Integer(100));
はnet.sf.hibernate.ObjectNotFoundExceptionをスローします。
この例外をスローしたくない場合は、 session.get(Class clazz, Serializable id); を使用する必要があります。
2. データベースに存在するレコードをロードします
1) セッションのキャッシュに存在する場合は、参照を直接返します。
セッション session = HibernateSessionFactory.currentSession();
Transaction tx = session.beginTransaction();
employee1.setAge((byte)10);
employee1.setBirthDay(new Date()) ;
employee1.setEmployeeName("HairRoot");
employee1.setGender('m');
session.save(employee1);
System.out.println(employee1);
/ /employee1 が保存されました
従業員employee2 = (従業員) session.load(Employee.class, new Integer(/*employee1.getId()*/100));
System.out.println(employee2);
tx.commit ();
session.close();
employee1 とemployee2 が同じ参照であることがわかります。 show_sql=true をオンにすると、hibernate がデータベースに select ステートメントを送信しないこともわかります。
2) セッションがキャッシュに存在しない場合、選択はすぐに送信されます。
セッション session = HibernateSessionFactory.currentSession();
Transaction tx = session.beginTransaction();
Employee 従業員 = (従業員) session.load(Employee.class, new Integer(100));
System.out.println(従業員) );
tx.commit();
session.close();
バックエンド:Hibernate:employee0_.idをid0_、employee0_.ageをage0_、employee0_.birthDayをbirthDay0_、employee0_.employeeNameをemployee4_0_、employee0_.genderとして選択します。 as 性別0_, 従業員0_.婚姻 as 既婚0_ from MWS_TEST_EMPLOYEE 従業員0_ ここで従業員0_.id=?
この時点で、履歴書フィールドデータの実際の読み取り操作が開始されます。