この記事の主な研究は、HibernateのSession_Flushと分離レベルです。具体的な紹介と例は次のとおりです。
最初にいくつかの概念を見てみましょう:
1。汚い読み物:汚い読みは、無効なデータの読み取りとも呼ばれます。これは、データベースアクセス中に、Thing T1が特定の値を変更し、T2 T2が値を読み取ることを意味します。その後、T1は何らかの理由で値の変更をキャンセルします。これにより、T2による読み取りデータが無効になります。ダーティリーディングとは、Thingがデータにアクセスしてデータを変更している場合、この変更がデータベースに送信されていない場合、もう1つはこのデータにもアクセスしてからこのデータを使用することを意味します。このデータはまだ送信されていないため、別のもので読み取られるデータは汚いデータであり、汚れたデータに基づいて実行される操作は正しくありません。
2。繰り返し読んでいない:たとえば、私が投稿を読んでいたとき、私が見つけたデータはZhang SanとLi Siでした。その後、リフレッシュした後、最初のチャンサンがチャンバになったことがわかりました。これは、私が読んだデータが繰り返されなかったため、いわゆる非繰り返しの読み物です。
3。ファンタジーリーディング:データを調べていたとき、3つのレコードを見つけ始めました。リフレッシュしたとき、レコードが8になったことがわかりました。これはファンタジーの読書です。
4。読書を送信:送信後にのみ読むことができます。 Oracleはこれにデフォルトです。このように汚い読みはありません。
5。再現性:それは明らかに反復性のない読書の反対です。繰り返しのない読書を避けることができますが、これは幻想の読み物を避けることはできません。
6。シリアル化:この方法は非常に厳しいです。素人の言葉で言えば、私が何かをしているとき、他の誰もそれをすることができません。それは非常に安全ですが、非常に非効率的です。
以下に、実用的な例を使用して、冬眠キャッシュクリアランスの適用を理解します。
Hibernateマッピングデータベースは、主要なキー生成戦略に関連しています。
UUIDで主要なキーを生成する例:
public class user {private string uid; private string uname; private date Birthday; public string getuid(){return uid;} public void setuid(this.uid uid;} public string getuname(){return uname;} public void setuname(string uname){this.uname = uname;} public getbid;} public getbir( SetBirthday(日付の誕生日){this.birthday = Birthday;}}user.hbm.xml:
<?xml version = "1.0"?> <!doctype hibernate-mapping public " - // hibernate/hibernateマッピングDTD 3.0 // en" "http://hibernate.sourceforge.net/hibernate-mapting-3.0.dtd"> <! package = "com.lixue.bean"> <! - クラスノードの名前はエンティティのクラス名を表し、テーブルはデータベースのテーブルにマッピングされたエンティティの名前を表します - > <クラス名= "ユーザー"テーブル= "t_user"> <id name = "uid"> <! name = "Birthday"/> </class> </hibernate-mapping>
テスト方法:
/ ***UUIDプライマリキー生成戦略をテスト*/ public void testsave1(){/*定義済みセッションおよび物*/セッションセッション= null;トランザクショントランザクション= null; { /*セッションと物を取得* /セッション= hibernateutils.getSession(); transaction = session.begintransaction(); /*ユーザーの作成*/ user user = new user(); user.setuname( "xi jinping"); user.setbirthday(new date()); / ***ユーザーの主要なキー生成戦略はUUIDであるため、Saveを呼び出した後、セッション管理にユーザーが含まれます*挿入ステートメントは発行されませんが、IDは生成され、PersistenceContextのexpencesIndateBaseステータスはfalse*/ session.save(user); /** * Flushの呼び出し、Hibernateはキャッシュをクリーンアップします(データベースへのセッションの挿入、一時的なコレクションのクリアの一時コレクションのオブジェクトを挿入) *現時点では、データベースでデータを見ることができませんが、データベースの分離レベルが読み取りにならない場合 *で、flushedAbaseの存在は、存在します。 session.flush(); /** *物事を送信 *デフォルトでは、コミット操作はフラッシュクリーニングキャッシュを実行します *したがって、ディスプレイなしでフラッシュを呼び出すとデータを巻き戻すことはできません * commit * transaction.commit(); } catch(Exception e){e.printstacktrace(); transaction.rollback(); }最後に{hibernateutils.closessession(session); }}ブレークポイントを介してプログラムをデバッグできます。
1.ユーザーのプライマリキー生成のサイドレートはUUIDであるため、save()メソッドを呼び出した後、ユーザーオブジェクトはセッション管理にのみ含めることができ、挿入ステートメントは発行されませんが、IDは生成されます。 persipenceContext-> entityEntries-> map-> table->> valueは、値の下に別の属性を保存します。写真に示されているように:
2。flush()メソッドを呼び出した後、セッションのActionQueueの一時的な保存値がクリアされ、その後、PersistenceContextのExististindAtabaseの値がTrueに設定されます。現時点ではデータベースに対応するデータがありますが、データベースを開いてテーブルを開くと、デフォルトのデータが表示されているため、デフォルトのデータが表示されます。 commit()メソッドを呼び出した後、データベースにデータがあります。
ネイティブの方法で一次キーを生成する例:
public class user1 {private integer uid; private string uname; private date Birthday; public Integer getUid(){return uid;} public void setuid(integer uid){this.uid = uid;} public string getuname(){return uname;} public void setuname(string uname){this.uname = uname;}誕生日;} public void setbirthday(日付の誕生日){this.birthday = Birthday;}}user1.hbm.xml:
<?xml version = "1.0"?> <!doctype hibernate-mapping public " - // hibernate/hibernateマッピングDTD 3.0 // en" "http://hibernate.sourceforge.net/hibernate-mapting-3.0.dtd"> <! package = "com.lixue.bean"> <! - クラスノード名はエンティティのクラス名を表します(マッピングファイルを割り当てるときにクラス名を変更することを忘れないでください、それ以外の場合はバグが発生します)、テーブルはデータベースのテーブルにマッピングされたエンティティの名前を表します - > <クラス名= "user1"テーブル= "t_user1" </id> <プロパティ名= "uname"/> <プロパティ名= "誕生日"/> </class> </hibernate-mapping>
テスト方法:
/ ***ネイティブプライマリキー生成戦略をテスト*/ public void testsave2(){/*定義済みセッションおよび物*/セッションセッション= null;トランザクショントランザクション= null; { /*セッションと物を取得* /セッション= hibernateutils.getSession(); transaction = session.begintransaction(); /*ユーザーの作成*/ user1ユーザー= new user1(); user.setuname( "li keqiang"); user.setbirthday(new date()); / *** user1の主要なキー生成戦略はネイティブであるため、session.save()を呼び出した後、挿入ステートメントが実行され、一時的なコレクションオブジェクトがクリアされます*データベースによって生成されたIDを返し、セッション管理に含まれ、セッションでindatabaseステータスを修正しました。 transaction.commit(); } catch(Exception e){e.printstacktrace(); transaction.rollback(); }最後に{hibernateutils.closessession(session); }}ブレークポイントを介してプログラムをデバッグします:
1.主要なキー生成戦略はネイティブであるため、Save()メソッドを呼び出した後、挿入ステートメントが実行され、一時的な収集オブジェクトのデータがクリアされ、データベースによって生成されたIDが返されます。
2。セッション管理にオブジェクトを含め、PersistenceContextのExististSindatabaseプロパティをTrueに変更します(データベースに対応するデータがあることを示しますが、分離領域のためには見えません)。
冬眠の別の方法をテストしましょう。これはevict()であり、セッションからオブジェクトを追放することを意味します。
UUID一次キー戦略を生成するプログラムの場合、ここにテスト方法があります。
/ ***UUIDプライマリキー生成戦略をテスト*/ public void testsave3(){/*定義済みセッションおよび物*/セッションセッション= null;トランザクショントランザクション= null; { /*セッションと物を取得* /セッション= hibernateutils.getSession(); transaction = session.begintransaction(); /*ユーザーの作成*/ user user = new user(); user.setuname( "hu jintao"); user.setbirthday(new date()); /***ユーザーの主要なキー生成戦略はUUIDであるため、Saveを呼び出した後、ユーザーをセッション管理に組み込むだけで挿入ステートメントは発行されませんが、IDは生成されました。セッションのExististsIndateBaseステータスはfalse */ session.save(user); /*セッションからユーザーオブジェクト、つまりentityEntriesプロパティからexpelled extecencecontext.evict.evict(user); /** *は、Hibernateがキャッシュをクリーンアップすると、ユーザーオブジェクトが挿入後にセッションインサートから挿入されるため、操作後にユーザーオブジェクトが挿入されるため、EntityEntriesプロパティのexpencesIndatabaseは邪悪な方法に更新する必要があります。 transaction.commit(); } catch(Exception e){e.printstacktrace(); transaction.rollback(); }最後に{hibernateutils.closessession(session); }}ブレークポイント経由のデバッグ:
1。UUIDの主要なキー生成戦略が使用されるため、save()メソッドを呼び出すと挿入ステートメントは送信されません。オブジェクトはセッション管理に含まれています。 IDが生成されており、データベースに対応するデータはありません(つまり、ExistsIndataBase属性値はfalse)。
2。evict()を呼び出した後、セッションからユーザーオブジェクトを追放します。つまり、persistenceContextのエンティティエントリプロパティから追放されます。
3. commit()メソッドをもう一度呼び出すと、infcutedatabaseプロパティが虚偽であったため、データベースに対応するデータがないため、データを保存できないことがわかります。次に、Evil()を呼び出して、PersistenceContextのすべてのオブジェクトプロパティを削除します(IndectindAtabaseプロパティも含まれています)が、ActionQueueの一時保存されたデータは削除されていません。 commit()メソッドを呼び出すと、まずflush()メソッドを暗黙的に呼び出します。この方法の機能も前に言及されています。 ActionQueueに一時的なオブジェクトを挿入し、PersistenceContextのExististSindataBaseプロパティ値をtrueに設定します。残念ながら、PersistenceContextにはExististSindatabaseプロパティはありません。そのため、エラーが発生し、節約できなくなります。
これを行うには、上記の手順を改善します。
/ ***UUIDプライマリキー生成戦略をテスト*/ public void testsave4(){/*定義セッションおよび物*/セッションセッション= null;トランザクショントランザクション= null; { /*セッションと物を取得* /セッション= hibernateutils.getSession(); transaction = session.begintransaction(); /*ユーザーの作成*/ user user = new user(); user.setuname( "hu jintao"); user.setbirthday(new date()); /***ユーザーの主要なキー生成戦略はUUIDであるため、Saveを呼び出した後、ユーザーをセッション管理に組み込むだけで挿入ステートメントは発行されませんが、IDは生成されました。 persistenceContextのinfistentIndateBaseステータスはfalse */ session.save(user); / ***フラッシュ後、Hibernateはキャッシュをクリーニングし、ユーザーオブジェクトをデータベースに保存し、セッション*の挿入にユーザーオブジェクトをクリアし、exististSindatabaseのステータスをpersistenceContextのステータスをtrue*/ session.flush()に設定します。 / *セッションからユーザーオブジェクトを追い出します。つまり、PersistenceContextのエンティティエントリプロパティから追放されます */ session.evict(user); / ***キャッシュをクリーンアップするときに冬眠がセッション挿入コレクションに含まれないために正常に送信できます*ユーザーオブジェクトが見つかった(フラッシュが呼び出されたときにクリアされた)ため、挿入ステートメントは発行されません。 } catch(Exception e){e.printstacktrace(); transaction.rollback(); }最後に{hibernateutils.closessession(session); }}注:保存後、Flush()メソッドを呼び出してから、変更されたプログラムの後にevict()メソッドを呼び出します。
ブレークポイント経由のデバッグ:
1.それはまだUUID生成戦略であるため、Saveを呼び出した後、挿入ステートメントは発行されませんが、オブジェクトはセッション管理に含まれています。 PersistenceContextのexististSindatabaseプロパティはfalseです。
2。save()を呼び出した後、flush()メソッドを再度呼び出します。この方法の機能は、キャッシュをクリーニングすることです。つまり、挿入ステートメントを発行し、セッションの挿入に一時オブジェクトをデータベースに挿入し、一時コレクションをクリアし、existsIndataBaseプロパティをpersistenceContextに設定します。
3。flush()を呼び出した後、evict()メソッドが呼び出されます。その機能は、セッションからユーザーオブジェクトをクリアすることです。つまり、PersistenceContextのエンティティエントリプロパティをクリアすることです。
4。evict()メソッドを呼び出した後、commit()メソッドは最初にflush()メソッドを暗黙的に呼び出します。フラッシュの機能は、キャッシュをクリアすることです。つまり、セッション - >挿入の一時コレクションをデータベースに挿入しますが、Flush()メソッドを前に呼び出しました(注:このメソッドを呼び出すと、一時コレクションにはオブジェクトがまったくないため、挿入ステートメントは発行されません。 PersipenceContextでExistsIndataBaseステータスを更新しません。正常に送信してください。
ネイティブの主要なキー生成戦略でevict()メソッドを使用することを考えてみましょう。
/ ***ネイティブプライマリキー生成戦略をテスト*/ public void testsave5(){/*定義されたセッションおよび物*/セッションセッション= null;トランザクショントランザクション= null; { /*セッションと物を取得* /セッション= hibernateutils.getSession(); transaction = session.begintransaction(); /*ユーザーの作成*/ user1ユーザー= new user1(); user.setuname( "ma ying-jeou"); user.setbirthday(new date()); / *** user1の主要なキー生成戦略はネイティブであるため、session.save()を呼び出した後、挿入ステートメントが実行されます。*セッション管理に含まれるデータベースによって生成されたIDを返し、セッションのexpencesindatabaseステータスをtrueに変更し、一時セットをクリアし、データベースの分離レベルが読み取られない場合に設定されている場合、saved save sess inthine(saved sess inthins(save ses)が表示されます。 /*セッションからユーザーオブジェクトを追い出します。つまり、persistenceContextのエンティティエントリプロパティから追放されます*/ session.evict(user); / ***は、ユーザーオブジェクトが見つからないため、CACHE*のクリーニングが発見されないため、Hibernateがセッション挿入コレクションにあるために正常に送信できます。そのため、挿入ステートメントは発行されません。 } catch(Exception e){e.printstacktrace(); transaction.rollback(); }最後に{hibernateutils.closessession(session); }}デバッグを通じて:
1.主要なキー生成戦略はネイティブであるため、Saveメソッドを呼び出した後、挿入ステートメントがすぐに発行され、データベースによって生成されたIDを返却し、オブジェクトをセッション管理に組み込み、PersistenceContextのIndectenceContextの修正、つまりデータベースに対応するデータがあり、一時的なコレクションのオブジェクトがクリアされます。ただし、MySQLの分離レベルのため、データをコミットする前にデータを表示できません。
2。Saveを呼び出した後、オブジェクトが呼び出され、オブジェクトはセッションから追放されます。つまり、PersistenceContextのエンティティエントリから追放されます。
3。evict()メソッドを呼び出した後、commit()メソッドを正常に呼び出すことができます。 commit()を呼び出す前に、flush()メソッドが暗黙的に呼ばれるため、commitを正常に保存できます。つまり、キャッシュをクリーニングして一時コレクションのオブジェクトを検索してデータベースに挿入します。ただし、一時的なコレクションにはデータがないため、挿入ステートメントは発行されず、PersistenceContextのIndectIndatabaseプロパティは更新されません。
上記のケースを通して、キャッシュをクリーニングするためにflush()メソッドを呼び出す必要があることがわかります。さらに、上記から問題を発見しました。つまり、データを保存すると、データを送信する前にデータを表示できません。つまり、データベースの分離レベルが制限されています。それでは、mysqlの分離レベルについて話しましょう。
1.MySQLデータベースの現在の分離レベルを確認してください。
@@ tx_isolationを選択します。
注:図から、MySQLデータベースのデフォルトの分離レベルが繰り返し可能であることがわかります。つまり、非繰り返しの読み取り値はありません。つまり、読み取る前に送信する必要があります。
2。MySQLの現在の分離レベルを変更します(読み取りに提出されていないと仮定します。つまり、コミットなしで読むことができます):
set transaction isolation level read uncommited;
上記は、HibernateのSession_Flushおよび分離レベルコードのすべての詳細な説明です。私はそれが誰にでも役立つことを願っています。興味のある友人は、このサイトの他の関連トピックを引き続き参照できます。欠点がある場合は、それを指摘するためにメッセージを残してください。このサイトへのご支援をありがとうございました!