记录Hibernate 增删改 执行的SQL语句

今天发现了以前写的一个记录Hibernate执行增删改的SQL日志的功能

即记录的sql日志可以直接拿到数据库中执行

想起来当初为了这个功能费了不少周折,网上也找了好多资料,但是都无法记录确切的SQL语句  如:insert into table (name,age)  values('李刚',35);


思路: 通过Hibernate 拦截器 + hibernate事件监听器 完成此功能 

要求:hibernate版本 3.2.5.ga  其他版本在方法调用上可能有些出入,需自行调整代码。 比如3.1中就没有getRootTableName()方法 ,至于hibernate4没有验证过

转载请注明:http://blog.csdn.net/zidasine/article/details/7242829

1、监听器

package com.sqllog;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.EmptyInterceptor;
import org.hibernate.Transaction;
/**
 * hibernate 拦截器
 * @author Zidasine
 *
 */
public class SQLInterceptor extends EmptyInterceptor {

	/**
	 * 
	 */
	private static final long serialVersionUID = 4147408208347438253L;
	private final ThreadLocal> content = new ThreadLocal>();
	private Logger logger = Logger.getLogger(SQLInterceptor.class);
	
	public void add(String sql){
		content.get().add(sql);
	}
	private List get(){
		return content.get();
	}
	private void set(List value){
		content.set(value);
	}
	private void clear(){
		content.remove();
	}
	@Override
	public void afterTransactionBegin(Transaction tx) {
		set(new ArrayList());
		super.afterTransactionBegin(tx);
	}
	@Override
	public void afterTransactionCompletion(Transaction tx) {
		if(tx.wasCommitted()){
			List sqls = get();
			DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
			String logName = format.format(new Date());
			StringBuffer buff = new StringBuffer();
			for(int i = 0;i < sqls.size();i++){
				buff.append(sqls.get(i));
				buff.append("\r\n\r\n");
			}
			try {
				SQLLogHandler.writeLog(logName, true, buff.toString());
			} catch (IOException e) {
				logger.error("记录sql日志错误", e);
			}
		}
		clear();
		super.afterTransactionCompletion(tx);
	}
}

2、日志处理器

package com.sqllog;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
/**
 * 日志处理类
 * @author Zidasine
 *
 */
public class SQLLogHandler {
	// 日志输入目的目录
	private static final File LOG_PARENT_DIR = new File("D:\\SQL_LOG");
	private static final String LOG_SUFFIX = "log";
	static {
		if (!LOG_PARENT_DIR.exists()) {
			LOG_PARENT_DIR.mkdirs();
		}
	}

	private SQLLogHandler() {
	}

	public static void writeLog(String logName, boolean append, String message) throws IOException {
		File log = getLog(logName);
		if(log == null){
			log = createLog(logName);
		}
		if(log == null){
			throw new IOException("can't create log file: "+logName+"."+LOG_SUFFIX);
		}
		Writer writer = new FileWriter(log,append);
		writer.write(message);
		writer.flush();
		writer.close();
	}

	private static File getLog(String logName) {
		File log = new File(LOG_PARENT_DIR, logName + "." + LOG_SUFFIX);
		return log.exists() && log.isFile() ? log : null;
	}

	private static File createLog(String logName) throws IOException {
		File log = new File(LOG_PARENT_DIR, logName + "." + LOG_SUFFIX);
		return log.createNewFile() ? log : null;
	}
}

3、sql语句转换器

package com.sqllog;

/**
 * 生成SQL 语句用 Hibernate Object 操作 不考虑级联删除和多对象情况
 * 
 * @author Zidasine
 * 
 */
public class SQLConvertor {
	/**
	 * 非主键字段名称
	 */
	private String[] columnNames;
	/**
	 * 主键字段名称
	 */
	private String[] pkColumnNames;
	/**
	 * 非主键值
	 */
	private Object[] columnValues;
	/**
	 * 主键值
	 */
	private Object[] pkColumnValues;
	/**
	 * 表名
	 */
	private String tableName;
	/**
	 * 数据库中NULL值
	 */
	private final static String NULL = "NULL";

	private SQLConvertor() {
	}

	private SQLConvertor(String[] pkColumnNames, Object[] pkColumnValues,
			String[] columnNames, Object[] columnValues, String tableName) {
		super();
		this.columnNames = columnNames;
		this.pkColumnNames = pkColumnNames;
		this.columnValues = columnValues;
		this.pkColumnValues = pkColumnValues;
		this.tableName = tableName;
	}

	public String[] getColumnNames() {
		return columnNames;
	}

	public void setColumnNames(String[] columnNames) {
		this.columnNames = columnNames;
	}

	public String[] getPkColumnNames() {
		return pkColumnNames;
	}

	public void setPkColumnNames(String[] pkColumnNames) {
		this.pkColumnNames = pkColumnNames;
	}

	public Object[] getColumnValues() {
		return columnValues;
	}

	public void setColumnValues(Object[] columnValues) {
		this.columnValues = columnValues;
	}

	public Object[] getPkColumnValues() {
		return pkColumnValues;
	}

	public void setPkColumnValues(Object[] pkColumnValues) {
		this.pkColumnValues = pkColumnValues;
	}

	public String getTableName() {
		return tableName;
	}

	public void setTableName(String tableName) {
		this.tableName = tableName;
	}
	public static SQLConvertor newInstance(String[] pkColumns,Object[] pkValues,String[] columns,Object[] values,String table){
		return new SQLConvertor(pkColumns,pkValues,columns,values,table);
	}
	public String toInsertSQL(){
		// 表的列名称
			String[] tableColumns = new String[columnNames.length+pkColumnNames.length];
			System.arraycopy(columnNames, 0, tableColumns, 0, columnNames.length);
			System.arraycopy(pkColumnNames, 0, tableColumns, columnNames.length, pkColumnNames.length);
			// 列值
			Object[] tableColumnValues = new Object[columnValues.length+pkColumnValues.length];
			System.arraycopy(columnValues, 0, tableColumnValues, 0, columnValues.length);
			System.arraycopy(pkColumnValues, 0, tableColumnValues, columnValues.length, pkColumnValues.length);
			// 拼接语句
			StringBuffer buff = new StringBuffer();
			buff.append("insert into ");
			buff.append(tableName);
			buff.append(" (");
			StringBuffer values = new StringBuffer();
			values.append("values(");
			int columnCount = tableColumns.length;
			for(int i =0;i

4、hibernate 增删改监听器

package com.sqllog;

import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.event.PostInsertEvent;
import org.hibernate.event.PostInsertEventListener;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.type.Type;

public class SQLPostInsertEventListener extends SQLPropertyValues implements
		PostInsertEventListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = -6424496850696095293L;

	@Override
	public void onPostInsert(PostInsertEvent event) {
		AbstractEntityPersister ep = (AbstractEntityPersister) event.getPersister();
		//主键
		Type idType = ep.getIdentifierType();
		String[] keyColumns = ep.getRootTableKeyColumnNames();
		Object[] keyValues = null;
		try {
			keyValues = getPkValues(idType, event.getId(), ep.getFactory());
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IntrospectionException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		//其他列
		String[] propertys = ep.getPropertyNames();
		List columnNamesList = new ArrayList();
		for(String property : propertys){
			String[] columns = ep.getPropertyColumnNames(property);
			for(String column : columns){
				columnNamesList.add(column);
			}
		}
		Object[] values = getValues(event.getState(),ep.getPropertyTypes(),ep.getFactory());
		String table = ep.getRootTableName();
		String[] columnArr = new String[columnNamesList.size()];
		SQLConvertor convertor = SQLConvertor.newInstance(keyColumns, keyValues, columnNamesList.toArray(columnArr), values, table);
		String sql = convertor.toInsertSQL();
		SQLInterceptor interceptor = (SQLInterceptor) ep.getFactory().getInterceptor();
		interceptor.add(sql);
	}

}

package com.sqllog;

import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.event.PostUpdateEvent;
import org.hibernate.event.PostUpdateEventListener;
import org.hibernate.persister.entity.AbstractEntityPersister;

public class SQLPostUpdateEventListener extends SQLPropertyValues implements
		PostUpdateEventListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 5734527340990478299L;

	@Override
	public void onPostUpdate(PostUpdateEvent event) {
		AbstractEntityPersister ep = (AbstractEntityPersister) event.getPersister();
		//主键
		String[] keyColumns = ep.getRootTableKeyColumnNames();
		Object[] keyValues = null;
		try {
			keyValues = getPkValues(ep.getIdentifierType(), event.getId(), ep.getFactory());
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IntrospectionException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		String[] propertys = ep.getPropertyNames();
		List columnNamesList = new ArrayList();
		for(String property : propertys){
			String[] columns = ep.getPropertyColumnNames(property);
			for(String column : columns){
				columnNamesList.add(column);
			}
		}
		Object[] values = getValues(event.getState(),ep.getPropertyTypes(),ep.getFactory());
		String table = ep.getRootTableName();
		String[] columnArr = new String[columnNamesList.size()];
		SQLConvertor convertor = SQLConvertor.newInstance(keyColumns, keyValues, columnNamesList.toArray(columnArr), values, table);
		String sql = convertor.toUpdateSQL();
		SQLInterceptor interceptor = (SQLInterceptor) ep.getFactory().getInterceptor();
		interceptor.add(sql);
	}

}

package com.sqllog;

import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;

import org.hibernate.event.PostDeleteEvent;
import org.hibernate.event.PostDeleteEventListener;
import org.hibernate.persister.entity.AbstractEntityPersister;

public class SQLPostDeleteEventListener extends SQLPropertyValues implements PostDeleteEventListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = -8623174144121579378L;

	@Override
	public void onPostDelete(PostDeleteEvent event) {
		AbstractEntityPersister ep = (AbstractEntityPersister) event.getPersister();
		//主键
		String[] keyColumns = ep.getRootTableKeyColumnNames();
		Object[] keyValues = null;
		try {
			keyValues = getPkValues(ep.getIdentifierType(), event.getId(), ep.getFactory());
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IntrospectionException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		String table = ep.getRootTableName();
		SQLConvertor convertor = SQLConvertor.newInstance(keyColumns,keyValues,null,null,table);
		String sql = convertor.toDeleteSQL();
		SQLInterceptor interceptor = (SQLInterceptor) ep.getFactory().getInterceptor();
		interceptor.add(sql);
	}

}


package com.sqllog;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;

import org.hibernate.engine.Mapping;
import org.hibernate.type.ComponentType;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;

public class SQLPropertyValues {
	protected Object[] getPkValues(Type type,Serializable id,Mapping factory) throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
		Object[] keyValues = null;
		if(type instanceof ComponentType){
			ComponentType keyType = (ComponentType) type;
			Type[] subTypes = keyType.getSubtypes();
			String[] keyNames = keyType.getPropertyNames();
			keyValues = new Object[subTypes.length];
			for(int i=0;i



 applicationContext.xml 
  







       
       	   
       	         
       	    
       	    
       	         
       	    
       	    
       	         
       	    
       
  


缺点:对于hibernate级联操作不支持

对于主键 如果是联合主键只处理了2层

功能虽然不算强大 基本可以满足需求 。。

至于如果有其他需求可以进行修改

由于源代码在内网中 以上代码为手动敲入,如果错误请见谅。

你可能感兴趣的:(hibernate)