Mybatis攔截器 mysql load data local 內存流處理


Mybatis 攔截器不做解釋了,用過的基本都知道,這里用load data local主要是應對大批量數據的處理,提高性能,也支持事務回滾,且不影響其他的DML操作,當然這個操作不要涉及到當前所load的數據,其中在使用的時候一定要local , 這個命令使用是mysql規定的,否則不加則會認為是服務器本地的文件。這里主要是以流的方式來做處理,這樣可以使用內存流,這樣就可以避免在某些時候需要生成文件才能導入的多余操作,和IO性能消耗。也可以是應用本地的文件。

注:該做法只試用於存入數據的表,不試用於有頻繁更新,查詢操作的表。 因為load 命令的優先級比更新命令,及查詢命令的優先級低。

mybatis 插件配置

<plugins>
   <plugin interceptor="com.yunat.channel.process.util.LoadDataInterceptor">
       <property name="databaseType" value="mysql"/>
   </plugin>
</plugins>

插入SQL

<select id="saveTest" parameterType="map">
    LOAD DATA LOCAL INFILE 'sql.csv' IGNORE INTO TABLE test (a,b,d)
</select>

插件代碼

package com.yunat.channel.process.util;
 
import java.io.InputStream;
import java.sql.Statement;
import java.util.Properties;
 
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
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;
 
@Intercepts({ @Signature(method = "update", type = StatementHandler.class, args = { Statement.class }) })
public class LoadDataInterceptor implements Interceptor {
 
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();
        BoundSql boundSql = handler.getBoundSql();
        if (boundSql.getSql().toLowerCase().contains("load data local infile")) {
            Object in = boundSql.getParameterObject();
            if (in != null && in instanceof InputStream) { // 如果不使用流的方式, 則會讀取語句中對應在本地的文件
                Statement statement = (Statement) invocation.getArgs()[0];
                if (statement.isWrapperFor(com.mysql.jdbc.Statement.class)) {
                    com.mysql.jdbc.PreparedStatement mysqlStatement = statement.unwrap(com.mysql.jdbc.PreparedStatement.class);
                    // 將流設置到執行語句中,在后續執行過程中,會忽略load data 語句中的文件名,改用當前設置流
                    mysqlStatement.setLocalInfileInputStream((InputStream)in);
                    invocation.getArgs()[0] = mysqlStatement; // 將當前語句執行代理,換成mysql的語句對象,方便下面執行。
                }
            }
        }
        return invocation.proceed();
    }
 
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
 
    @Override
    public void setProperties(Properties properties) {
 
    }
 
}

本文轉自:http://www.oschina.net/code/snippet_144320_24440#66175


免責聲明!

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



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