Hibernate envers。 変更を行った人のユーザーIDを変更する

画像



こんにちは、ハブロビテス。 これは私の最初の記事です、あまり誓わないでください。



Hibernateはすでにリスニングについて多くのことを書いています。 あまり標準的ではないタスク-データベースにエンティティを書き込む操作の直前に割り当てられたユーザーのIDをリビジョンテーブルに書き込む-について説明したいと思います。 公式ドキュメントで提案されている標準ソリューションは、セッションコンポーネントに保存されているユーザーIDを使用することです。 ただし、ユーザーIDを変更する必要がある場合があります。 例:ユーザーは、DTMF信号を介したテレフォニーサーバーとの対話を通じて操作を実行します。 この場合、セッションを作成する必要はまったくありません。 長い間インターネットで解決策を探しましたが、何も見つかりませんでしたので、私のバージョンに注意を向けます。 おそらく、私のような新参者の一部にとって、それは有用であることが証明されるでしょう。



ドキュメントを読んだ後、Hibernateでのリスニングはインターセプターに基づいていることに気付きました。 これは、データベース内のエンティティを更新するスレッドがリスニングを担当することを意味します-これはすでに何かです。



それを活用してみましょう。 ペアを持つ静的マップが格納されるステートレスコンポーネントを作成します:ストリームID-ユーザーID。 startメソッドは、ユーザーID(パラメーターで渡される)と現在のスレッドのIDをマップに追加し、必要なアクションを実行する新しいトランザクションでメソッドを開始し、メソッド(トランザクション)が終了するのを待ち、ストリームIDとユーザーをマップから削除します。



@Stateless @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) public class FakeOwnerTransaction { @Inject private Provider<FakeOwnerTransaction> providerFakeOwnerNewTransaction; private static ThreadLocal<Long> threadOwnerID = new ThreadLocal<>() @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public void newCMT(Runnable action) { action.run(); } public void start(Long personID, Runnable action) { threadOwnerID.set(personID); try { providerFakeOwnerNewTransaction.get().newCMT(action); } finally { threadOwnerID.remove(); } } public static Long getFakeChanger() { return threadOwnerID.get(); } }
      
      





次に、RevisionListenerの実装がどのようになるかを見てみましょう。 現在のスレッドがユーザーIDに関連付けられている場合は、このIDを使用します。そうでない場合は、UserManagerのセッションコンポーネントからユーザーIDを取得します。



 public class Audition implements RevisionListener { @Override public void newRevision(Revinfo revinfo) { Long personID = FakeOwnerTransaction.getFakeChanger(); if (personID == null) { UserManager userManager = SystemUtils.lookup(JNDI_NAME_PREFIX, UserManager.class); personID = userManager.getPersonID(); } revinfo.setPersonID(personID); } }
      
      





最後に、指定されたユーザーのIDを使用して、データベースに変更を加えてみましょう。



 FakeOwnerTransaction fakeOwnerTransaction = SystemUtils.lookup(JNDI_NAME_PREFIX, FakeOwnerTransaction.class); fakeOwnerTransaction.start(getPersonID(), new Runnable() { @Override public void run() { Dao dao = SystemUtils.lookup(JNDI_NAME_PREFIX, Dao.class); dao.add(new Person(“Smirmov”)); } });
      
      







クラスSystemUtils
 public class SystemUtils { public static <T> T lookup(String jndiNamePrefix, Class<T> clazz) { String jndiName = jndiNamePrefix; jndiName += clazz.getSimpleName() + "!" + clazz.getName(); try { return (T) new InitialContext().lookup(jndiName); } catch (Exception e) { CoreSharedUtils.getLogger().severe("Error. Bean '" + jndiName + "' not found!"); e.printStackTrace(); } return null; } … }
      
      







重要な注意事項
今日、何らかの理由でコメントを書くことができないHabrの賢い人が、注意を払う価値のある重要な問題に気付きました。

スレッドはJVMの外部から終了できます。その場合、最終ブロックは実行されません。 仮に、これはメモリリークにつながる可能性がありますが、このオプションは私に合っています。





それだけです。 誰かがより興味深い解決策や批判がある場合は、コメントへようこそ。



All Articles