DB žurnál pomocí Hibernate interceptoru

 data-srcset

Na mnoha projektech je třeba řešit databázový žurnál aplikace, který zaznamenává události v systému včetně dat, která při těchto událostech byla změněna či jen čtena. Zákazníci často požadují u událostí, které mění data, žurnálovat jak staré tak i nové hodnoty záznamu. Implementace takového mechanismu přímo na DAO vrstvě by byla pracná a hlavně složitě konfigurovatelná. Řešení žurnálování na úrovni databázových procedur a triggerů by zase zrušilo nezávislost aplikace na konkrétním typu databáze. Hibernate pro žurnálování nabízí zajímavou funkčnost interceptor pro zachycení a zpracování různých událostí, jako například databázové CRUD operace.

Vycházím z příkladu použití interceptoru na audit log (žurnál) a samozřejmě ze samotné dokumentace http://docs.jboss.org/hibernate/core/3.3/reference/en/html/events.html Po menší modifikaci lze uvedený příklad použít i na žurnálování starých a nových hodnot. Vytvořímě si entitu AuditLogData pro ukládání změněných hodnot a přidáme ji do entity 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;
  @OneToMany() @JoinColumn (name = "auditLogId") @OrderBy("propertyName") privateList auditLogData;
  ... 
}
@Entity @Table(name = "auditlogdata", catalog = "mkyong")
public class AuditLogData implements java.io.Serializable {
  private Long auditLogDataId;
  private String propertyName;
  private String oldValue;
  private String newValue;
  ... 
}

Při ukládání záznamu budeme pracovat přímo se záznamem AuditLog třídy a ne pouze s entity.

public boolean onFlushDirty(Object entity,Serializable id, Object[] currentState,Object[] previousState, String[] propertyNames,Type[] types) throws CallbackException {
  ... 
  if (entity instanceof IAuditLog){
    AuditLog auditRecord = new AuditLog("Updated“,entity.getLogDeatil(), new Date(),entity.getId(), entity.getClass().toString());
    fillChangedData(auditRecord, previousState, currentState, propertyNames, entity);
    //Add the auditLog to be saved as update after commit of transaction 
    updates.add(auditRecord);
  } 
  return false;
}

Kde plnění změněných dat by mohlo vypadat přibližně následovně:

private void fillChangedData(AuditLog auditLog, Object[] startState, Object[] endState, String[] propertyNames, Object newObject, Long persistedObjectId) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
  //check input parameters …
  for (int i = 0; i < propertyNames.length; i++) {
    //check if the property has been changed
    if (propertyValueChanged(startState[i], endState[i])) {
      // property changed, add it to auditLog.auditLogData list
      final String pn = propertyNames[i];
      String valueOld = propertyValueToString(startState[i]);
      String valueNew = propertyValueToString(endState[i]);
      addDataToAuditLog(auditLog, pn, valueOld, valueNew);
    }
  }
}

Jak je na příkladu vidět, Hibernate interceptor je mohutný nástroj, který umožňuje na aplikační úrovni nejen odchytávat operace nad databází, ale i dále zpracovávat jejich data.

Zpět

Posuňte s námi své služby dál.

Nasměrujeme vás správným směrem!

Kontakujte nás