你所不知道的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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM