Finalizeは後のJVMのまだ悪いニュースであると確信しています - 代替手段はありますか?
-
27-10-2019 - |
質問
発信者が到達できなくなったときにPOJOの更新を保存できるORMスタイルのシステムを実装したいと思います。
参照クラスはそれを行うことができると思いましたが、オブジェクトがクリアされた後にのみ参照を除いているように見えます(私はそれが収集されることができたときだったと思っていました)。ヌル。
ファイナルライザーを使用することもできますが、前回それらが疑わしいことを確認したとき(迅速に走ることもまったく走ることも保証されていません) - ファイナライザーとRunshutdownhook()の組み合わせが機能すると思いますが、それはかなり沼地の領土に入っています。
「義務的な「発信者に.save()が終わったときに.save()を呼び出すだけです」以外に考えていない別のパスはありますか?
解決
あなたはただ電話をかけないようにしようとしていますか? save()
あなたが変更するすべてのポジョで?
これは、このような永続的なセッションオブジェクトを使用して確実に実行できます。
- 新しいセッションオブジェクトを開きます。
- セッションオブジェクトを介してオブジェクトをロードします。セッションオブジェクトは、ロードするすべてのオブジェクトへの参照を維持します。
- ロードされたオブジェクトに変更を加えます。更新されたオブジェクトの保存方法を呼び出す必要はありません。
- セッションオブジェクトを閉じます。セッションはすべてのオブジェクトを保存します。クリーンロードされたデータのコピーを保持し、そのすべてのオブジェクトをクリーンデータと比較し、変更されたもののみを保存するのに十分なほど空想的かもしれません。
また、セッションオブジェクトをコードに渡したくない場合は、セッションオブジェクトを現在のスレッドに関連付けて、作業パターンの単位でさらに一歩進むことができます。
- 作業単位を開始します。これにより、舞台裏のセッションオブジェクトが作成され、現在のスレッドに関連付けられます。
- オブジェクトをロードします。オブジェクトがロードされるたびに、ORMは現在のスレッドに基づいてセッションオブジェクトと自動的に関連付けます。
- ロードされたオブジェクトに変更を加えます。更新されたオブジェクトの保存方法を呼び出す必要はありません。
- 作業単位を完了します。これにより、セッションオブジェクトが閉じられ、すべてのオブジェクトが保存されます。
これにより、到達可能性ベースのソリューションでいくつかの問題が修正されます。
- あなたは無皮質のゴミコレクションに依存していません。これは、ランの間に長い時間があるか、まったく実行されない可能性があります。
- 1つの操作で変更されたすべてのオブジェクトは一緒に保存されます。到達可能性に依存している場合、同じ操作で変更された異なるオブジェクトは、異なる時期に到達できなくなる可能性があります。つまり、修正はビットアンドピースのデータベースに保存できます。
- ロールバックははるかに簡単です - セッションオブジェクトにロールバック()メソッドを与えるだけです。到達可能性のソリューションを使用すると、操作が失敗した場合、すべての変更されたPOJOでRollBack()を呼び出すことを忘れないでください。これは、元の問題と実際に同じです。
おそらく見てください http://nhibernate.info/doc/patternsandpractices/nhibernate-and-the-of-of-work-of-work-pattern.html または、作業パターンの単位を調査し、それらのアイデアのいくつかをエミュレートします。
他のヒント
オブザーバーパターンを使用して、ClearanceManagerといくつかの破壊可能なものを構築します。 idestroyableはインターフェイスであり、オブザーバーに使用されているパブリックボイド破壊()clearancemanagerがObserverpatternの対象です。ここでは、Singletonを使用して、アプリケーションにClearanceManagerオブジェクトを1つだけ持っていることを確認してください。
ClearanceManager内で内部のセットを使用します(リストではなく、オブジェクトを1回だけ追加できるようにします)
addEstroyable(idestroyable destoryable)メソッド(およびおそらく削除可能な方法)をサポートします。
ランタイム中に、いくつかのデストラクタエミュレーションが必要なクラスは、ClearenceManagerで自己登録できます。 clearencemanager.getInstance()。addDestroyable(this);
ClearanceManagerにはdoclearance()メソッドがあり、メインメソッドの最後に呼び出される必要があります。プライベートセットを投げて、すべてのidestroyableオブジェクトでDestroy()を呼び出します。
このようにそれを行うと、デストラクタを使用せずにエミュレートできます。デストラクタを使用すると、Myabeが必要とするオブジェクトの存在についてコントロールを失っているからです。上書きがいつ完成するか、いつ呼び出されるかはわかりません。
たぶん、メインメソッドでdoclearance()を呼び出したくない場合は、ここで使用できますが、ここでは実際のデストラクタがfirenize()を使用できます。 ClearenceManagerに必要なオブジェクトへの参照があるため、最初に破壊されることはありません。しかし、多分MHH、相互参照がある場合....ファイナライズを使用しないでください、DocLearance()を使用して、それを楽しんでください:)
あなたはここで間違った木をbarえていると思います。
到達可能性に基づくJavaのファイナルイザーおよび参照メカニズムはすべて、ガベージコレクターに依存して、それぞれのオブジェクトに到達可能かどうかを判断します。したがって、何らかのファイナライズに参照メカニズムを使用する場合、あなたはほぼ同じ問題に遭遇します finalize
悪い考え。
技術的には、到達可能性を実行するための独自のメカニズムを実装することが可能です。たとえば、独自のアプリケーション固有の参照カウントを実装します。ただし、高価で壊れやすい可能性が高く、コードを恐ろしく見せます。 (Javaでの参照カウントは、参照カウントが透過的に調整されるように参照割り当てオペレーターを過負荷にすることができないため、C ++よりも厄介で脆弱である可能性があります。私はあなた自身の到達可能性分析をすることは 悪いアイデア.
したがって、実用的であるためには、次のどちらも必要です。
- デザインを再考して、到達可能性に基づいて何かをしないようにするか、
- ファイナライズを使用する結果とともに生きる。
最初のオプションは明らかに最高のIMOです。
たぶん、あなたは幻のサブクラスを使用して、最終アクションに必要なデータを保存することができます。