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;

すべての監査データがデータベースに挿入されます。


interceptor-example、title = "interceptor-example"

===結論

監査ログは、多くの場合データベースで処理される便利な機能です。
トリガを使用して、私はそれを実装するためにアプリケーションを使用することをお勧めします
移植性に関する懸念があります。

この例をダウンロードする –
リンク://wp-content/uploads/2010/02/HibernateInterceptotExample.zip[Hibernate
インターセプタexample.zip]

hibernate


interceptor