Hibernate Interceptor-Beispiel - Überwachungsprotokoll

Beispiel für einen Interceptor im Ruhezustand - Überwachungsprotokoll

Der Ruhezustand verfügt über eine leistungsstarke Funktion namens "interceptor", mit der verschiedene Arten von Ruhezustandsereignissen abgefangen oder verknüpft werden können, z. B. die Datenbank-CRUD-Operation. In diesem Artikel werde ich zeigen, wie eine Anwendungsüberwachungsprotokollfunktion mithilfe des Hibernate-Interceptors implementiert wird. Alle Vorgänge zum Speichern, Aktualisieren oder Löschen im Ruhezustand werden in einer Datenbanktabelle mit dem Namen "auditlog" protokolliert.

Beispiel für einen Interceptor im Ruhezustand - Überwachungsprotokoll

1. Erstellen Sie eine Tabelle

Erstellen Sie eine Tabelle mit dem Namen "Auditlog", um alle von der Anwendung geprüften Datensätze zu speichern.

DROP TABLE IF EXISTS `example`.`auditlog`;
CREATE TABLE  `example`.`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. Erstellen Sie eine Markierungsschnittstelle

Erstellen Sie eine Markierungsschnittstelle. Alle Klassen, die diese Schnittstelle implementiert haben, werden überprüft. Diese Schnittstelle erfordert, dass die implementierte Klasse ihre Kennung -getId() und der zu protokollierende Inhalt - "getLogDeatil()" verfügbar macht. Alle exponierten Daten werden in der Datenbank gespeichert.

package com.example.interceptor;
//market interface
public interface IAuditLog {

    public Long getId();
    public String getLogDeatil();
}

3. Ordnen Sie die Tabelle "Auditlog" zu

Eine normale Anmerkungsmodelldatei, die mit der Tabelle "Auditlog" verknüpft werden soll.

@Entity
@Table(name = "auditlog", catalog = "example")
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. Eine Klasse hat den IAuditLog implementiert

Eine normale Anmerkungsmodelldatei, die mit der Tabelle "Bestand" verknüpft werden soll und die später für die Interceptor-Demo verwendet wird. Es muss die MarkierungsschnittstelleIAuditLog implementieren und die MethodegetId() undgetLogDeatil() implementieren.

...
@Entity
@Table(name = "stock", catalog = "example"
public class Stock implements java.io.Serializable, IAuditLog {
...
        @Transient
    @Override
    public Long getId(){
        return this.stockId.longValue();
    }

    @Transient
    @Override
    public String getLogDeatil(){
        StringBuilder sb = new StringBuilder();
        sb.append(" Stock Id : ").append(stockId)
        .append(" Stock Code : ").append(stockCode)
        .append(" Stock Name : ").append(stockName);

        return sb.toString();
    }
...

5. Erstellen Sie eine Helper-Klasse

Eine Hilfsklasse, um die Daten vom Interceptor zu akzeptieren und in der Datenbank zu speichern.

...
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. Erstellen Sie eine Hibernate-Interceptor-Klasse

Erstellen Sie eine Interceptor-Klasse, indem Sie den RuhezustandEmptyInterceptorerweitern. Hier ist die beliebteste Interceptor-Funktion.

  • onSave - Wird aufgerufen, wenn Sie ein Objekt speichern. Das Objekt wird noch nicht in der Datenbank gespeichert.

  • onFlushDirty - Wird aufgerufen, wenn Sie ein Objekt aktualisieren. Das Objekt wird noch nicht in der Datenbank aktualisiert.

  • onDelete - Wird aufgerufen, wenn Sie ein Objekt löschen. Das Objekt wird noch nicht in der Datenbank gelöscht.

  • preFlush - Wird aufgerufen, bevor die gespeicherten, aktualisierten oder gelöschten Objekte in die Datenbank übernommen werden (normalerweise vor postFlush).

  • postFlush - Wird aufgerufen, nachdem die gespeicherten, aktualisierten oder gelöschten Objekte in die Datenbank übernommen wurden.

Der Code ist ziemlich ausführlich und sollte sich selbst erforschen.

...
public class AuditLogInterceptor extends EmptyInterceptor{

    Session session;
    private Set inserts = new HashSet();
    private Set updates = new HashSet();
    private Set deletes = new 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 (entity instanceof IAuditLog){
            inserts.add(entity);
        }
        return false;

    }

    public boolean onFlushDirty(Object entity,Serializable id,
        Object[] currentState,Object[] previousState,
        String[] propertyNames,Type[] types)
        throws CallbackException {

        System.out.println("onFlushDirty");

        if (entity instanceof IAuditLog){
            updates.add(entity);
        }
        return false;

    }

    public void onDelete(Object entity, Serializable id,
        Object[] state, String[] propertyNames,
        Type[] types) {

        System.out.println("onDelete");

        if (entity instanceof IAuditLog){
            deletes.add(entity);
        }
    }

    //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

Sie können den Interceptor aktivieren, indem Sie ihn als Argument anopenSession(interceptor); übergeben.

...
   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("example");
    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("example-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();
    }
   }
...

Im Einlegetest

session.saveOrUpdate(stockInsert); //it will call onSave
tx.commit(); // it will call preFlush follow by postFlush

Im Update-Test

session.saveOrUpdate(stockUpdate); //it will call onFlushDirty
tx.commit(); // it will call preFlush follow by postFlush

Im Löschtest

session.delete(stockUpdate); //it will call onDelete
tx.commit();  // it will call preFlush follow by postFlush
Ausgabe
onSave
Hibernate:
    insert into example.stock
    (STOCK_CODE, STOCK_NAME)
    values (?, ?)
preFlush
postFlush
postFlush - insert
Hibernate:
    insert into example.auditlog
    (ACTION, CREATED_DATE, DETAIL, ENTITY_ID, ENTITY_NAME)
    values (?, ?, ?, ?, ?)
preFlush
Hibernate:
    select ...
    from example.stock stock0_
    where stock0_.STOCK_CODE='1111'
preFlush
onFlushDirty
Hibernate:
    update example.stock
    set STOCK_CODE=?, STOCK_NAME=?
    where STOCK_ID=?
postFlush
postFlush - update
Hibernate:
    insert into example.auditlog
    (ACTION, CREATED_DATE, DETAIL, ENTITY_ID, ENTITY_NAME)
    values (?, ?, ?, ?, ?)
onDelete
preFlush
Hibernate:
    delete from example.stock where STOCK_ID=?
postFlush
postFlush - delete
Hibernate:
    insert into example.auditlog
    (ACTION, CREATED_DATE, DETAIL, ENTITY_ID, ENTITY_NAME)
    values (?, ?, ?, ?, ?)
In der Datenbank
SELECT * FROM auditlog a;

Alle geprüften Daten werden in die Datenbank eingefügt.

interceptor-example

Fazit

Die Überwachungsprotokolle sind eine nützliche Funktion, die in der Datenbank häufig mithilfe von Triggern verarbeitet wird. Ich würde jedoch empfehlen, die Anwendung zu verwenden, um sie aus Gründen der Portabilität zu implementieren.

Laden Sie dieses Beispiel herunter -Hibernate interceptor example.zip