Mybatis的幾種數據插入方式的效率對比


Mybatis作為一種非常流行的ORM框架,經常會遇到需要插入大量數據的情況,本文對比一下幾種插入方式的效率。

1、DefaultSqlSession,單條插入

 private static void insertSingle(SqlSessionFactory factory) {
        SqlSession sqlSession = factory.openSession(false);
        SysUserMapper mapper = sqlSession.getMapper(SysUserMapper.class);
        long start = System.currentTimeMillis();
        for (long i = 0; i < SIZE; i++) {
            SysUser sysUser = createSysUser();
            mapper.insertUser(sysUser);
        }
        sqlSession.commit();
        sqlSession.close();
        long end = System.currentTimeMillis();
        System.out.println(String.format("single insert %s items cost:%s ms.", SIZE, end - start));
    }

2、DefaultSqlSession,BatchExecutor批量插入 

private static void insertBatch(SqlSessionFactory factory) {
        SqlSession sqlSession = factory.openSession(ExecutorType.BATCH, false);
        SysUserMapper mapper = sqlSession.getMapper(SysUserMapper.class);
        long start = System.currentTimeMillis();
        for (long i = 0; i < SIZE; i++) {
            SysUser sysUser = createSysUser();
            mapper.insertUser(sysUser);
        }
        sqlSession.commit();
        sqlSession.close();
        long end = System.currentTimeMillis();
        System.out.println(String.format("batch insert %s items cost:%s ms.", SIZE, end - start));
    }

 3、Mybatis的動態Sql,foreach標簽拼接

<insert id="insertUsers" parameterType="java.util.List">
        insert into sys_user( user_id, dept_id, login_name, user_name, email, avatar, phonenumber,
        sex, password, salt, status, create_by, remark, create_time )
        values
        <foreach collection="list" item="item" index="index" separator="," >
            (#{item.userId},
            #{item.deptId},
            #{item.loginName},
            #{item.userName},
            #{item.email},
            #{item.avatar},
            #{item.phonenumber},
           #{item.sex},
            #{item.password},
            #{item.salt},
           #{item.status},
            #{item.createBy},
            #{item.remark},
            sysdate())
        </foreach>
    </insert>

 

 private static void insertForeach(SqlSessionFactory factory) {
        SqlSession sqlSession = factory.openSession(false);
        SysUserMapper mapper = sqlSession.getMapper(SysUserMapper.class);
        long start = System.currentTimeMillis();
        List<SysUser> userList = new ArrayList<>();
        for (long i = 0; i < SIZE; i++) {
            SysUser sysUser = createSysUser();
            userList.add(sysUser);
        }
        mapper.insertUsers(userList);
        sqlSession.commit();
        sqlSession.close();
        long end = System.currentTimeMillis();
        System.out.println(String.format("mybatis foreach insert %s items cost:%s ms.", SIZE, end - start));
    }

4、手動拼接Sql語句,然后調用Mybatis框架執行現成的Sql語句

 需要定義一個對象封裝sql語句:

public class SqlVo {
    private String sql;

    public SqlVo(String sql) {
        this.sql = sql;
    }

    public String getSql() {
        return sql;
    }

    public void setSql(String sql) {
        this.sql = sql;
    }
}

mapper文件里定義一個標簽,將sql語句作為參數傳入: 

<select id="executeSql" parameterType="domain.SqlVo">
        ${sql}
 </select>

然后拼接Sql語句:

  private static void insertSqlJoin(SqlSessionFactory factory) {
        SqlSession sqlSession = factory.openSession(false);
        long start = System.currentTimeMillis();
        SysUserMapper mapper = sqlSession.getMapper(SysUserMapper.class);
        String sqlHeader = " insert into sys_user(dept_id,login_name,user_name,email,avatar,phonenumber,sex,password,salt,status,create_by,remark,create_time)values";
        StringBuilder sql = new StringBuilder(sqlHeader);
        for (long i = 0; i < SIZE; i++) {
            SysUser sysUser = createSysUser();
            sql.append("(");
            sql.append(sysUser.getDeptId()).append(",");
            sql.append("'").append(sysUser.getLoginName()).append("'").append(",");
            sql.append("'").append(sysUser.getUserName()).append("'").append(",");
            sql.append("'").append(sysUser.getEmail()).append("'").append(",");
            sql.append("'").append(sysUser.getAvatar()).append("'").append(",");
            sql.append("'").append(sysUser.getPhonenumber()).append("'").append(",");
            sql.append("'").append(sysUser.getSex()).append("'").append(",");
            sql.append("'").append(sysUser.getPassword()).append("'").append(",");
            sql.append("'").append(sysUser.getSalt()).append("'").append(",");
            sql.append("'").append(sysUser.getStatus()).append("'").append(",");
            sql.append("'").append(sysUser.getCreateBy()).append("'").append(",");
            sql.append("'").append(sysUser.getRemark()).append("'").append(",");
            sql.append("'").append(format0.format(sysUser.getCreateTime())).append("'").append(")");
            sql.append(",");
        }
        sql.setCharAt(sql.length() - 1, ';');
        mapper.executeSql(new SqlVo(sql.toString()));
        sqlSession.commit();
        sqlSession.close();
        long end = System.currentTimeMillis();
        System.out.println(String.format("sql join insert %s items cost:%s ms.", SIZE, end - start));
    }

5、采用Load Data Local InFile,這種方式與mybatis框架無關,但也可以適配使用:

  定義一個工具類:

import javax.sql.DataSource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class LoadDataInFileUtil {
   private   Connection conn;

    private int loadoadFromInputStream(String loadDataSql,
                                       InputStream dataStream,
                                       DataSource dataSource) throws SQLException {
        if (null == dataStream) {
            return 0;
        }
        conn = dataSource.getConnection();
        PreparedStatement statement = conn.prepareStatement(loadDataSql);
        int result = 0;
        if (statement.isWrapperFor(com.mysql.jdbc.Statement.class)) {
            com.mysql.jdbc.PreparedStatement mysqlStatement = statement.unwrap(com.mysql.jdbc.PreparedStatement.class);
            mysqlStatement.setLocalInfileInputStream(dataStream);
            result = mysqlStatement.executeUpdate();
        }
        return result;
    }

    public String assembleSql(String dataBaseName, String tableName, String[] columnNames) {
        String insertColumnName = String.join( ",",columnNames);
        String sql = "LOAD DATA LOCAL INFILE 'sql.csv' IGNORE INTO TABLE " + dataBaseName + "." + tableName + "(" + insertColumnName + ")";
        return sql;
    }

    public void builderAppend(StringBuilder builder, Object object) {
        builder.append(object);
        builder.append("\t");
    }


    public void builderEnd(StringBuilder builder, Object object) {
        builder.append(object);
        builder.append("\n");
    }

    public int fastInsertData(String sql, StringBuilder builder,DataSource dataSource) {
        int rows = 0;
        InputStream is = null;
        try {
            byte[] bytes = builder.toString().getBytes();
            if (bytes.length > 0) {
                is = new ByteArrayInputStream(bytes);
                rows = loadoadFromInputStream(sql, is, dataSource);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != is) {
                    is.close();
                }
                if (null != conn) {
                    conn.close();
                }
            } catch (IOException | SQLException e) {
                e.printStackTrace();
            }
        }
        return rows;
    }

}

 業務流程:

 private static void insertLoadDataLocalInFile(SqlSessionFactory factory) {
        long start = System.currentTimeMillis();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < SIZE; i++) {
            SysUser sysUser = createSysUser();
            loadDataInFileUtil.builderAppend(sb, sysUser.getDeptId());
            loadDataInFileUtil.builderAppend(sb, sysUser.getLoginName());
            loadDataInFileUtil.builderAppend(sb, sysUser.getUserName());
            loadDataInFileUtil.builderAppend(sb, sysUser.getEmail());
            loadDataInFileUtil.builderAppend(sb, sysUser.getAvatar());
            loadDataInFileUtil.builderAppend(sb, sysUser.getPhonenumber());
            loadDataInFileUtil.builderAppend(sb, sysUser.getSex());
            loadDataInFileUtil.builderAppend(sb, sysUser.getPassword());
            loadDataInFileUtil.builderAppend(sb, sysUser.getSalt());
            loadDataInFileUtil.builderAppend(sb, sysUser.getStatus());
            loadDataInFileUtil.builderAppend(sb, sysUser.getCreateBy());
            loadDataInFileUtil.builderAppend(sb, sysUser.getRemark());
            loadDataInFileUtil.builderEnd(sb, format0.format(sysUser.getCreateTime()));
        }
        String sql = loadDataInFileUtil.assembleSql("ry", "sys_user", COLUMN_NAME);
        DataSource dataSource = factory.getConfiguration().getEnvironment().getDataSource();
        loadDataInFileUtil.fastInsertData(sql, sb, dataSource);
        long end = System.currentTimeMillis();
        System.out.println(String.format("Load Data Local InFile insert %s items cost:%s ms.", SIZE, end - start));
    }

  

結論:

 

 

 

 

 

注:每種插入方式都是在空表情況下進行。

附:表結構

 

 

 

  


免責聲明!

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



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