0

呼び出し元が到達できなくなったときにPOJOへの更新を保存できるORMスタイルのシステムを実装したいと思います。

参照クラスはそれを実行できると思いましたが、オブジェクトがクリアされた後にのみ参照をキューに入れるようです(収集できるようになったときだと思っていました)。したがって、キューに入れると、.get()メソッドは常に返されます。ヌル。

ファイナライザーを使用することはできましたが、前回それらが疑わしいことを確認しました(すぐに実行される、またはまったく実行されるとは限りません)-ファイナライザーとrunShutdownHook()の組み合わせは機能すると思いますが、それはかなり沼沢地になりつつあります。

義務的な「呼び出し元が完了したら.save()を呼び出すだけ」以外に、私が考えていない別のパスはありますか?

4

4 に答える 4

1

オブザーバーパターンを使用して、ClearanceManagerといくつかのDestroyableをビルドします。IDestroyableは、メソッドpublic void destroy()を含むオブザーバーに使用されるインターフェースです。ClearanceManagerはObserverpatternのサブジェクトです。ここでシングルトンを使用して、アプリケーションにClearanceManagerオブジェクトが1つだけあることを確認してください。

ClearanceManager内で内部的にSetを使用します(オブジェクトを一度だけ追加できるようにするためのリストではありません)

addDestroyable(IDestroyable destoryable)メソッド(およびおそらくremoveDestroyableメソッド)をサポートします。

ランタイム中に、デストラクタエミュレーションが必要なクラスは、ClearenceManagerに自分で登録できます。ClearenceManager.getInstance()。addDestroyable(this);

ClearanceManagerにはdoClearance()メソッドがあり、Mainメソッドの最後で呼び出す必要があります。プライベートセットのスローを繰り返し、すべてのIDestroyableオブジェクトに対してdestroy()を呼び出します。

このようにすると、デストラクタを使用せずにデストラクタをエミュレートできます。デストラクタを使用すると、myabeに必要なオブジェクトの存在を制御できなくなるためです。いつ上書きファイナライズが呼び出されるかはわかりません。

MainメソッドでdoClearance()を呼び出したくない場合は、ここで使用できますが、ここでは、実際のデストラクタfinalize()を使用できます。ClearenceManagerには必要なオブジェクトへの参照があるため、最初に破棄されることはありません。しかし、相互参照がある場合は、多分mhh .... finalizeを使用せず、doClearance()を使用して、楽しんでください:)

于 2011-03-19T01:38:08.560 に答える
1

ここで間違った木を吠えていると思います。

到達可能性に基づくJavaのファイナライザーと参照メカニズムはすべて、それぞれのオブジェクトが到達可能かどうかを判断するためにガベージコレクターに依存しています。したがって、ある種のファイナライズに参照メカニズムのいずれかを使用するとfinalize、悪い考えを生み出すのとほぼ同じ問題が発生します。

到達可能性を実現するための独自のメカニズムを実装することは技術的に可能です。たとえば、独自のアプリケーション固有の参照カウントを実装することによって。ただし、高価で壊れやすく、コードがひどく見える可能性があります。(Javaでの参照カウントは、C ++よりも厄介で壊れやすい可能性があります。これは、参照割り当て演算子をオーバーロードして参照カウントが透過的に調整されるようにすることができないためです。したがって、すべての参照割り当てをメソッド呼び出しでラップする必要があります。)独自の到達可能性分析を行うことは悪い考えだと思います。

したがって、実用的にするには、次のいずれかを行う必要があります。

  • 到達可能性に基づいて物事を行わないように、デザインを再考します。
  • ファイナライズを使用した結果と共存します。

最初のオプションは明らかに最良のIMOです。

于 2011-03-19T02:37:19.517 に答える
1

save()変更するすべてのPOJOを呼び出す必要がないようにしようとしているだけですか?

これは、次のような永続セッションオブジェクトを使用して確実に実行できます。

  1. 新しいセッションオブジェクトを開きます。
  2. セッションオブジェクトを介してオブジェクトをロードします。セッションオブジェクトは、ロードするすべてのオブジェクトへの参照を維持します。
  3. ロードされたオブジェクトに変更を加えます。更新されたオブジェクトに対してsaveメソッドを呼び出す必要はありません。
  4. セッションオブジェクトを閉じます。セッションはすべてのオブジェクトを保存します。クリーンにロードされたデータのコピーを保持し、そのすべてのオブジェクトをクリーンなデータと比較し、変更されたものだけを保存するのは、十分に凝ったことかもしれません。

また、コードを介してセッションオブジェクトを渡したくない場合は、作業単位パターンを使用してさらに一歩進んで、セッションオブジェクトを現在のスレッドに関連付けることができます。

  1. 作業単位を開始します。これにより、バックグラウンドでセッションオブジェクトが作成され、現在のスレッドに関連付けられます。
  2. オブジェクトをロードします。オブジェクトがロードされるたびに、ORMは現在のスレッドに基づいてオブジェクトをセッションオブジェクトに自動的に関連付けます。
  3. ロードされたオブジェクトに変更を加えます。更新されたオブジェクトに対してsaveメソッドを呼び出す必要はありません。
  4. 作業単位を完了します。これにより、セッションオブジェクトが閉じられ、すべてのオブジェクトが保存されます。

これにより、到達可能性ベースのソリューションに関するいくつかの問題が修正されます。

  • 非決定論的なガベージコレクションに依存していません。これは、実行の間隔が長いか、まったく実行されない可能性があります。
  • 1回の操作で変更されたすべてのオブジェクトが一緒に保存されます。到達可能性に依存している場合、同じ操作で変更されたさまざまなオブジェクトがさまざまな時間に到達不能になる可能性があります。つまり、変更内容を少しずつデータベースに保存できます。
  • ロールバックははるかに簡単です-セッションオブジェクトにrollback()メソッドを与えるだけです。到達可能性ソリューションでは、操作が失敗した場合、変更されたすべてのPOJOでrollback()を呼び出すことを忘れないでください。これは、元の問題と実際に同じです。

おそらくhttp://nhibernate.info/doc/patternsandpractices/nhibernate-and-the-unit-of-work-pattern.htmlを参照するか、Unit of Workパターンを調べて、それらのアイデアのいくつかをエミュレートします。

于 2011-03-19T03:56:46.857 に答える
0

PhantomReferenceをサブクラス化し、最終的なアクションのために必要なデータをそこに保存できるかもしれません。

于 2011-03-19T01:55:35.400 に答える