转自:https://blog.csdn.net/he90227/article/details/44783099
开发应用程序的过程中,经常会对一些比较重要的数据修改都需要写日志。在实际工作的工程中,这些数据都是存在表中的, 一个常见的做法是用触发器,在增删改的时候,用触发器将数据写入到另一张表中去,但个人不推荐这么做,原因如下:
1. 如果有多个表,得写很多触发器。
2. 触发器与数据库特性关联太紧,不同的数据库,虽然思路一样,但语法却不太一样。
对数据库表操作的日志记录,完全可以利用Hibernate的Interceptor特性来实现,也就是拦截器。下面用一个具体的例子来说明如何使用Hibernate的Interceptor。
创建一个表,用来记录日志的表
Create TABLE `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;
创建这个表对应的实体类:
@Entity
@Table(name = "auditlog") 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; public AuditLog() { } public AuditLog(String action, String detail, Date createdDate, long entityId, String entityName) { this.action = action; this.detail = detail; this.createdDate = createdDate; this.entityId = entityId; this.entityName = entityName; } @Id @GeneratedValue(strategy = IDENTITY) @Column(name = "AUDIT_LOG_ID", unique = true, nullable = false) public Long getAuditLogId() { return this.auditLogId; } .... 余下部分可以参考提供下载的源代码.
创建一个接口,所有实现了这个接口的实体类,都会写日志
package com.mkyong.interceptor; //market interface public interface IAuditLog { public Long getId(); public String getLogDeatil(); }
这里有两个方法,getId,getLogDetail 需要实现类去实现具体的方法,也就是要被写入到日志表中的详细记录.
创建一个类实现了IAuditLog 接口,并给出接口方法的具体实现
@Entity
@Table(name="stock") public class Stock implements java.io.Serializable,IAuditLog { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="STOCK_ID") private Integer stockId; @Column(name="STOCK_CODE", length=10) private String stockCode; @Column(name="STOCK_NAME", length=20) private String stockName; public Stock() { } public Stock(String stockCode, String stockName) { this.stockCode = stockCode; this.stockName = stockName; } ....省略部分getter,setter。 @Transient public Long getId(){ return this.stockId.longValue(); } @Transient 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(); } }
创建记录日志的工具类,所有写日志公用
public class AuditLogUtil{ public static void LogIt(String action, IAuditLog entity){ Session tempSession = HibernateUtil.getSessionFactory().openSession(); try { tempSession.getTransaction().begin(); AuditLog auditRecord = new AuditLog(action,entity.getLogDeatil() , new Date(),entity.getId(), entity.getClass().toString()); tempSession.save(auditRecord); tempSession.getTransaction().commit(); } finally { tempSession.close(); } } }
创建 Hibernate interceptor 拦截器,这是重点,这里拦截所有需要记录日志的类,并处理
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; } @Override public String onPrepareStatement(String sql) { System.out.println("execute sql: " + sql); return super.onPrepareStatement(sql); } 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,