(1)spring的配置文件里,
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 分页插件设置 --> <property name="plugins"> <array> <!-- SQL异常拦截器 --> <bean class="com.xxx.yyyy.interceptor.SqlExceptionInterceptor"></bean> </array> </property> </bean>
(2)SqlExceptionInterceptor.java的内容:
package com.xxx.yyyy.interceptor;
import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Date; import java.util.Properties; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Plugin; import org.apache.ibatis.plugin.Signature; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds;
import com.xxx.domain.SqlExceptionLog; import com.xxx.persistence.SqlExceptionLogMapper; import com.xxx.utils.SpringContextHolder;
/** * Mybatis拦截器. 拦截SQL执行时的异常,写入DB. * */ @Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }), @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }) }) public class SqlExceptionInterceptor implements Interceptor {
/** * 线程池. */ private static ExecutorService executor = Executors.newFixedThreadPool(5);
/** * 拦截方法. */ public Object intercept(Invocation invocation) throws Throwable {
try { return invocation.proceed(); } catch (Exception e) {
try { // 取得各种值 MappedStatement statement = (MappedStatement) invocation .getArgs()[0]; Object parameter = invocation.getArgs()[1]; BoundSql boundSql = statement.getBoundSql(parameter);
// 防止死循环 if (statement.getId().toUpperCase() .contains("sqlExceptionLogMapper".toUpperCase())) { throw e; }
// 日志对象 final SqlExceptionLog record = new SqlExceptionLog(); record.setSystemName("ordersystem"); // 系统名称 record.setSqlId(statement.getId()); // sqlId record.setSqlParameter(parameter.toString()); // SQL参数 record.setSqlSource(boundSql.getSql()); // SQL语句 record.setSqlType(statement.getSqlCommandType().toString()); // SQL类型 record.setExceptionMessage(e.getCause().toString()); // 异常简要信息 record.setExceptionStack(getExceptionStackTrace(e)); // 堆栈信息 record.setCreateTime(new Date()); // 创建时间
// 放入线程池 executor.execute(new Runnable() { public void run() {
// 外面类里直接注入貌似有问题,故这么搞下。 SqlExceptionLogMapper mapper = SpringContextHolder .getBean("sqlExceptionLogMapper"); mapper.insertSelective(record); } }); } catch (Exception ex) { ex.printStackTrace(); }
// 抛出异常 throw e; } }
public Object plugin(Object target) { return Plugin.wrap(target, this); }
/** * 配置文件读取属性. */ public void setProperties(Properties properties) { }
/** * 获取异常的堆栈信息. * * @param e * @return */ private String getExceptionStackTrace(Exception e) { ByteArrayOutputStream buf = new ByteArrayOutputStream(); e.printStackTrace(new java.io.PrintWriter(buf, true)); String expMessage = buf.toString(); try { buf.close(); } catch (IOException ex) { } return expMessage; } }
(3)SqlExceptionLog表的结构如下:
CREATE TABLE `sql_exception_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `systemName` varchar(30) NOT NULL COMMENT '系统名称', `sqlId` varchar(200) NOT NULL COMMENT 'sql所在类、方法名', `sqlSource` varchar(2000) NOT NULL COMMENT 'sql内容', `sqlParameter` varchar(500) DEFAULT NULL COMMENT 'sql参数', `sqlType` varchar(10) DEFAULT NULL COMMENT 'sql类型,SELECT、INSERT等', `exceptionMessage` varchar(500) DEFAULT NULL COMMENT '异常信息', `exceptionStack` mediumtext COMMENT '异常堆栈信息', `createTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='sql异常日志';
自己生成bean和Mapper即可。
(4)SpringContextHolder.java的内容:
package com.shijie99.order.common.utils;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component;
@Component public class SpringContextHolder implements ApplicationContextAware {
/** * 以静态变量保存ApplicationContext,可在任意代码中取出ApplicaitonContext. */ private static ApplicationContext context;
/** * 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量. */ public void setApplicationContext(ApplicationContext context) { SpringContextHolder.context = context; }
public static ApplicationContext getApplicationContext() { return context; }
/** * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型. */ @SuppressWarnings("unchecked") public static <T> T getBean(String name) { return (T) context.getBean(name); } }
|