欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

你所不知道的mybatis居然也有拦截器

发布时间:2025/3/15 40 豆豆
生活随笔 收集整理的这篇文章主要介绍了 你所不知道的mybatis居然也有拦截器 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

对于mybatis的拦截器这个想法我来自于三个地方

也就是下面这个三个地方是可以使用的,其他的情况需要开发人员根据实际情况来使用。

1、对于分页的查询,我们可以对于分页的方法采用比较规范的命名,然后根据这个命名来拦截需要分页查询的sql然后把分页的总数,分页数,页码数,页码总数等放在一个对象中返回去,这样分页只要调用dao的一个方法即可。

2、读写分离,我们可以在sql执行之前,获取sql是不是查询方法,然后根据这个条件去控制需要访问的数据源。

3、需要统计分析sql的执行时间(这边要说的是这里的执行包含了网络带宽,因为不是在mysql执行前后做的拦截,所以这里的sql并不只是sql在数据库真正执行的时间,要比实际长)

 

如何实现这样一个拦截器

首先mybatis官方早就想到我们开发会有这样的需求,所以开放了一个org.apache.ibatis.plugin.Interceptor这样一个接口。

我们只要实现这个接口并且加上注解然后重写intercept方法。

最后如果你使用的是mybatis.xml也就是mybatis本身单独的配置,你可以需要在这里配置相应的拦截器名字等。

如果你使用的是spring管理的mybatis,那么你需要在spring配置文件里面配置注册相应的拦截器。

 

代码实现

下面对于3,也就是实现统计sql执行时间,简单摘录一下实现代码。

还有两种开发可以根据自己的想法去实现和摸索。

package com.ssm;import java.text.DateFormat; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Properties;import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ParameterMapping; 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.reflection.MetaObject; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.apache.ibatis.type.TypeHandlerRegistry; import org.apache.log4j.Logger;@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 SqlStatementInterceptor implements Interceptor{ private static Logger logger = Logger.getLogger(SqlStatementInterceptor.class); @SuppressWarnings("unused") private Properties properties; @Override public Object intercept(Invocation arg0) throws Throwable { MappedStatement mappedStatement = (MappedStatement) arg0.getArgs()[0]; Object parameter = null; if (arg0.getArgs().length > 1) { parameter = arg0.getArgs()[1]; } String sqlId = mappedStatement.getId(); BoundSql boundSql = mappedStatement.getBoundSql(parameter); Configuration configuration = mappedStatement.getConfiguration(); Object returnValue = null; long start = System.currentTimeMillis(); returnValue = arg0.proceed(); long end = System.currentTimeMillis(); long time = (end - start); if (time > 1) { String sql = getSql(configuration, boundSql, sqlId, time); logger.error(sql);} return returnValue; } public static String getSql(Configuration configuration, BoundSql boundSql, String sqlId, long time) { String sql = showSql(configuration, boundSql); StringBuilder str = new StringBuilder(100); str.append(sqlId); str.append(":"); str.append(sql); str.append(":"); str.append(time); str.append("ms"); return str.toString(); } public static String showSql(Configuration configuration, BoundSql boundSql) { Object parameterObject = boundSql.getParameterObject(); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); String sql = boundSql.getSql().replaceAll("[\\s]+", " "); if (parameterMappings.size() > 0 && parameterObject != null) { TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { sql = sql.replaceFirst("\\?", getParameterValue(parameterObject)); } else { MetaObject metaObject = configuration.newMetaObject(parameterObject); for (ParameterMapping parameterMapping : parameterMappings) { String propertyName = parameterMapping.getProperty(); if (metaObject.hasGetter(propertyName)) { Object obj = metaObject.getValue(propertyName); sql = sql.replaceFirst("\\?", getParameterValue(obj)); } else if (boundSql.hasAdditionalParameter(propertyName)) { Object obj = boundSql.getAdditionalParameter(propertyName); sql = sql.replaceFirst("\\?", getParameterValue(obj)); } } } } return sql; } private static String getParameterValue(Object obj) { String value = null; if (obj instanceof String) { value = "'" + obj.toString() + "'"; } else if (obj instanceof Date) { DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA); value = "'" + formatter.format(new Date()) + "'"; } else { if (obj != null) { value = obj.toString(); } else { value = ""; } } return value; } @Override public Object plugin(Object arg0) { return Plugin.wrap(arg0, this); } @Override public void setProperties(Properties arg0) { this.properties = arg0; } }

下面是spring中的配置,如果你是单独配置mybatis配置文件的话,你需要查询一下如何配置

<!-- 配置mybitasSqlSessionFactoryBean --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource" /><property name="typeAliasesPackage" value="com/ssm/entity"></property><property name="mapperLocations" value="classpath*:com/ssm/dao/sqlxml/*.xml"></property><property name="plugins"><array><bean class="com.ssm.SqlStatementInterceptor"><property name="properties"><value>property-key=property-value</value></property></bean></array></property></bean>

会在log日志中输出最后执行的sql和sqlID和sql执行的时间。

 

 

参考资料:

分页实现(本人没有亲自实现,因为现实情况还没有这样特别需要这样的业务逻辑):

http://www.cnblogs.com/jethypc/p/5149183.html

执行时间统计实现(我修改了其中spring的配置,不知为何下面博主的配置并没有用):

http://blog.csdn.net/tq02h2a/article/details/50772652

读写分离实现(其中的第四种方案就是利用了拦截器):

http://www.jianshu.com/p/2222257f96d3

转载于:https://www.cnblogs.com/linkstar/p/6039513.html

新人创作打卡挑战赛发博客就能抽奖!定制产品红包拿不停!

总结

以上是生活随笔为你收集整理的你所不知道的mybatis居然也有拦截器的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。