ユーザーが実行した結果、対応するテーブルが変更されたアクションを監査しようとしています。たとえば、ユーザーが 2 つのアカウント間で送金を行う場合、次の一連のイベントが生成されます。
- 送金テーブルに送金金額を挿入する
- 口座 1 の残高表の残高から送金金額を差し引きます。
- アカウント 2 のバランス テーブルの残高に送金金額を追加します。
すべてのテーブルの親監査メッセージは次のようになります。
これは、次のスキーマで実現されます 。
代替テキスト http://img48.imageshack.us/img48/7460/auditloggingiv6.png
問題は、休止状態でこれをどのように表現するかです。
私は以下を作成しました:
In Balance and Transfer のマッピング ファイル
<set name="auditRecords" table="TransferAuditRecord" inverse="false" cascade="save-update">
<key>
<column name="AuditRecordID" not-null="true" />
</key>
<one-to-many class="audit.AuditRecord"/>
</set>
Transfer クラスと Balance クラスは、メソッドを持つ IAuditable を実装します。
public void setAuditRecords(Set<AuditRecord> auditRecord);
public Set<AuditRecord> getAuditRecords();
AuditRecord のマッピング ファイルには次のものがあります。
<many-to-one name="parentAuditRecord" lazy="false"
column="parent_id"
class="audit.AuditRecord"
cascade="all" />
次に、AOP と Hibernate Interceptors を使用する Logging クラスで、次のことを行います。
AuditRecord auditRecord = new AuditRecord();
auditRecord.setUser(userDAO.findById(
org.springframework.security.context.SecurityContextHolder.getContext()
.getAuthentication().getName()));
auditRecord.setParentAuditRecord(getCurrentActiveServiceRecord());
auditable.getAuditRecords().add(auditRecord);
次に、サービス クラスで、次のメソッドをトランザクションに含めて呼び出します。
save(balance1);
save(balance2);
transfer.setPassed(true);
update(transfer);
parentAuditRecord は AOP を使用してスレッド セーフ スタックで作成され、AuditRecordType_id はメソッドの注釈を使用して設定されます。
転送テーブルの「合格」列を省略しました。以前は、save(transfer) を呼び出して、転送金額を Transfer テーブルに挿入し、passed を false に設定していました。(このアクションも監査されます)。
私の要件は、上記の例よりも少し複雑です:P
したがって、上記の一連のイベントは次のようになります。
- 転送テーブルの更新
- AuditRecord (親) に挿入
- AuditRecord に挿入 (子)
- TransferAuditRecord への挿入
- バランス表に挿入
- AuditRecord に挿入 (子)
- BalanceAuditRecord に挿入
- バランス表に挿入
- AuditRecord に挿入 (子)
- BalanceAuditRecord に挿入
ただし、上記で定義したカスケード オプションは update ステートメントで失敗します。Hibernate は多対多テーブルへのレコードの挿入を拒否します (AuditRecord マッピングで unsaved-value="any" であっても)。私は常に多対多テーブルに行を挿入したいので、1 回の転送で以前のイベントをマークする多くの監査レコードが存在する可能性があります。ただし、最新のイベントによって、ユーザーが見たいメッセージが決まります。Hibernate は、多対多テーブルと以前の AuditRecord エントリを更新しようとするか、単に AuditRecord と TransferAuditRecord への挿入を拒否して、TransientObjectException をスローします。
監査メッセージは次のように取得されます。
msg=... + ((AuditRecord) balance.getAuditRecords().toArray()[getAuditRecords().size()-1])
.getParentAuditRecord().getAuditRecordType().getDescription() + ...;
メッセージは次のようになります。「Username set transfer to pass at 11-Oct-2008」
編集多対多テーブルを明示的にマッピングし(関連付けられたインターフェースを使用)、afterTransactionCompletionで、親監査レコードで保存を呼び出し(保存を子監査レコードにカスケードします)、インターフェースを明示的に保存することにしましたすべての子マッピング テーブル。これは真の監査履歴ではなく、ユーザー アクションを記録する非侵襲的な方法です。後でより完全な監査履歴が必要な場合は、Envers を調べます。