mybatis的攔截器實現統計分析sql的執行時間,mybatis統計分析
轉載自:http://blog.csdn.net/andyzhaojianhui/article/details/72823055
對於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執行時間,簡單摘錄一下實現代碼。
還有兩種開發可以根據自己的想法去實現和摸索。
- Hide code
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設定檔的話,你需要查詢一下如何配置
- Hide code
<!-- 配置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
查看評論