Hibernateインターセプタの例 – 監査ログ
Hibernateには、データベースCRUD操作のような異なる種類のHibernateイベントをインターセプトしたりフックしたりするための強力な機能があります。
この記事では、Hibernateインターセプタを使用してアプリケーション監査ログ機能を実装する方法を示し、Hibernateの保存、更新、または削除のすべての操作を ‘
auditlog
‘という名前のデータベーステーブルに記録します。
Hibernateインターセプタの例 – 監査ログ
1.テーブルを作成する
「auditlog」という表を作成して、すべてのアプリケーション監査レコードを保管します。
DROP TABLE IF EXISTS `mkyong`.`auditlog`; CREATE TABLE `mkyong`.`auditlog` ( `AUDIT__LOG__ID` bigint(20) unsigned NOT NULL AUTO__INCREMENT, `ACTION` varchar(100) NOT NULL, `DETAIL` text NOT NULL, `CREATED__DATE` date NOT NULL, `ENTITY__ID` bigint(20) unsigned NOT NULL, `ENTITY__NAME` varchar(255) NOT NULL, PRIMARY KEY (`AUDIT__LOG__ID`) ) ENGINE=InnoDB AUTO__INCREMENT=9 DEFAULT CHARSET=utf8;
2.マーカーインターフェースを作成する
マーカーインターフェイスを作成します。このインターフェイスを実装したクラスはすべて監査されます。このインタフェースでは、実装されたクラスがidentifier –
getId()
および内容をログに記録する – ‘
getLogDeatil()
‘を公開する必要があります。すべての公開データはデータベースに格納されます。
package com.mkyong.interceptor;//market interface public interface IAuditLog { public Long getId(); public String getLogDeatil(); }
3. ‘auditlog’テーブルをマップする
テーブル ‘auditlog’でマップする通常の注釈モデルファイル。
@Entity @Table(name = "auditlog", catalog = "mkyong") public class AuditLog implements java.io.Serializable { private Long auditLogId; private String action; private String detail; private Date createdDate; private long entityId; private String entityName; ... }
4. IAuditLogを実装したクラス
後でインターセプタのデモに使用するテーブル ‘stock’でマップする通常のアノテーションモデルファイル。
IAuditLog
マーカーインターフェースを実装し、
getId()
および
getLogDeatil()
メソッドを実装する必要があります。
... @エンティティ @Table(name = "stock"、catalog = "mkyong" パブリッククラスStockはjava.io.Serializable、IAuditLog { ... @Transient @オーバーライド public Long getId(){ これを返す.stockId.longValue(); } @Transient @オーバーライド public String getLogDeatil(){ StringBuilder sb =新しいStringBuilder(); sb.append( "在庫ID:").append(在庫ID) .append( "ストックコード:").append(stockCode) .append( "ストック名:").append(stockName); 戻り値sb.toString(); } ...
5. Create a Helper class
A helper class to accept the data from interceptor and store it into
database.
... public class AuditLogUtil{ public static void LogIt(String action, IAuditLog entity, Connection conn ){ Session tempSession = HibernateUtil.getSessionFactory().openSession(conn); try { AuditLog auditRecord = new AuditLog(action,entity.getLogDeatil() , new Date(),entity.getId(), entity.getClass().toString()); tempSession.save(auditRecord); tempSession.flush(); } finally { tempSession.close(); } } }
6. Hibernateインターセプタクラスを作成する
Hibernate
EmptyInterceptor
を拡張してインターセプタクラスを作成します。
ここで最も一般的なインターセプタ関数です。
データベースはまだありません。
-
onFlushDirty – オブジェクトを更新するときに呼び出され、オブジェクトは更新されません
まだデータベースに更新しないでください。
-
onDelete – オブジェクトを削除すると呼び出され、オブジェクトは削除されません
データベースにまだ入っていません。
-
preFlush – 保存、更新、または削除されたオブジェクトの前に呼び出されます。
データベースにコミットします(通常postFlushの前)。
-
postFlush – 保存、更新、または削除されたオブジェクトの後に呼び出されます。
データベースにコミットします。
コードは非常に冗長であり、自己探索的でなければなりません。
... パブリッククラスAuditLogInterceptorはEmptyInterceptorを継承します。プライベートセットの挿入=新しいHashSet();プライベートセットの更新=新しいHashSet();プライベートセットの削除=新しいHashSet(); public void setSession(Session session){this.session = session; } public boolean onSave(Object entity、Serializable id、Object[]state、String[]propertyNames、Type[]types)throws CallbackException {System.out.println( "onSave"); if(エンティティインスタンスのIAuditLog){inserts.add(エンティティ); }偽を返します。 }}}}} public boolean onFlushDirty(Object entity、Serializable id、Object[]currentState、Object[]previousState、String[]プロパティ名、型[]型)は、CallbackExceptionをスローします(System.out.println( "onFlushDirty"); if(エンティティインスタンスIAuditLog){updates.add(エンティティ); }偽を返します。 } public void onDelete(Object entity、Serializable id、Object[]state、String[]プロパティ名、型[]型){System.out.println( "onDelete"); if(エンティティインスタンスIAuditLog){deletes.add(エンティティ); }} //called before commit into database public void preFlush(Iterator iterator) { System.out.println("preFlush"); } //called after committed into database public void postFlush(Iterator iterator) { System.out.println("postFlush"); try{ for (Iterator it = inserts.iterator(); it.hasNext();) { IAuditLog entity = (IAuditLog) it.next(); System.out.println("postFlush - insert"); AuditLogUtil.LogIt("Saved",entity, session.connection()); } for (Iterator it = updates.iterator(); it.hasNext();) { IAuditLog entity = (IAuditLog) it.next(); System.out.println("postFlush - update"); AuditLogUtil.LogIt("Updated",entity, session.connection()); } for (Iterator it = deletes.iterator(); it.hasNext();) { IAuditLog entity = (IAuditLog) it.next(); System.out.println("postFlush - delete"); AuditLogUtil.LogIt("Deleted",entity, session.connection()); } } finally { inserts.clear(); updates.clear(); deletes.clear(); } } }
7.Enabling the interceptor
You can enable the interceptor by pass it as an argument to
openSession(interceptor);
.
... Session session = null; Transaction tx = null; try { AuditLogInterceptor interceptor = new AuditLogInterceptor(); session = HibernateUtil.getSessionFactory().openSession(interceptor); interceptor.setSession(session); //test insert tx = session.beginTransaction(); Stock stockInsert = new Stock(); stockInsert.setStockCode("1111"); stockInsert.setStockName("mkyong"); session.saveOrUpdate(stockInsert); tx.commit(); //test update tx = session.beginTransaction(); Query query = session.createQuery("from Stock where stockCode = '1111'"); Stock stockUpdate = (Stock)query.list().get(0); stockUpdate.setStockName("mkyong-update"); session.saveOrUpdate(stockUpdate); tx.commit(); //test delete tx = session.beginTransaction(); session.delete(stockUpdate); tx.commit(); } catch (RuntimeException e) { try { tx.rollback(); } catch (RuntimeException rbe) { //log.error("Couldn’t roll back transaction", rbe); } throw e; } finally { if (session != null) { session.close(); } } ...
In insert test
session.saveOrUpdate(stockInsert);//onSaveを呼び出します tx.commit();//preFlushを呼び出すと、postFlushが続きます。
更新テスト
session.saveOrUpdate(stockUpdate);//onFlushDirtyを呼び出します tx.commit();//preFlushを呼び出すと、postFlushが続きます。
削除テストで
session.delete(stockUpdate);//onDeleteを呼び出します tx.commit();//preFlushを呼び出すと、postFlushが続きます。
======出力
onSave Hibernate:mkyong.stock(STOCK__CODE、STOCK__NAME)の値(?、?)に挿入するpreFlush postFlush postFlush - hibernateを挿入する:mkyong.auditlog(ACTION、CREATED__DATE、DETAIL、ENTITY__ID、ENTITY__NAME)の値(?、?、?、 ?、?)preFlush Hibernate:select ... mkyong.stock stock0__よりStock0__.STOCK__CODE = '1111' preFlush onFlushDirty Hibernate:mkyong.stock setをSTOCK__CODE = ?, STOCK__NAME =に更新しますか?ここで、STOCK__ID =? postFlush postFlush - hibernateを更新します。mKeyong.auditlog(ACTION、CREATED__DATE、DETAIL、ENTITY__ID、ENTITY__NAME)の値(?、?、?、?、?)に挿入します。preFlush hibernate:mkyong.stockから削除します。 ポストフラッシュ postFlush - 削除 休止状態: mkyong.auditlogに挿入する (ACTION、CREATED__DATE、DETAIL、ENTITY__ID、ENTITY__NAME) 値(?、?、?、?、?)
======データベース内
SELECT ** FROM auditlog a;
すべての監査データがデータベースに挿入されます。
===結論
監査ログは、多くの場合データベースで処理される便利な機能です。
トリガを使用して、私はそれを実装するためにアプリケーションを使用することをお勧めします
移植性に関する懸念があります。
この例をダウンロードする –
リンク://wp-content/uploads/2010/02/HibernateInterceptotExample.zip[Hibernate
インターセプタexample.zip]
hibernate
interceptor