mybatisplus,jdbc 批量插入

mybatisplus,jdbc 批量插入_第1张图片

1.测试用例 

项目中遇到在做导入号码的时候我们会用到批量导入,提高入库的速度。接下来我们以10000条为测试用例。

1.1 批量执行sql语句

     当需要成批插入或者更新记录时,可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率

JDBC的批量处理语句包括下面三个方法:

  • addBatch(String):添加需要批量处理的SQL语句或是参数;
  • executeBatch():执行批量处理语句;
  • clearBatch():清空缓存的数据

通常我们会遇到两种批量执行SQL语句的情况:

  •     多条SQL语句的批量处理;
  •     一个SQL语句的批量传参;

1.2 导入excell 

 mybatisplus,jdbc 批量插入_第2张图片

2.先使用mybatisplus的批量插入

phoneListService.saveBatch(callLists);

感觉插入还是有些慢,查了下文档,需要增加一个参数 

 Postgres jdbc的连接:

url: jdbc:postgresql://102.2.1.21:5432/postgres?
binaryTransfer=false&forceBinary=false&reWriteBatchedInserts=true
 

Mysql jdbc连接:

jdbc:mysql://102.2.1.21:3306/demo?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B1&rewriteBatchedStatements=true 

增加以下的参数进行优化

  • rewriteBatchedStatements=true:控制是否将批量插入语句转换成更高效的形式,true 表示转换,默认为 false 

  • binaryTransfer=false:控制是否使用二进制协议传输数据,false 表示不适用,默认为 true

  • forceBinary=false:控制是否将非 ASCII 字符串强制转换为二进制格式,false 表示不强制转换,默认为 true

3.用jdbc插入 

感觉还是慢,不过不知道是什么原因。后来该用jdbc原生的,每500提交一次  

 Connection conn = jdbcUtils.getConnection();
        PreparedStatement ps = null;
        try {
            ps = jdbcUtils.createPreparedStatement1(conn, sql);
            //取消自动提交
            conn.setAutoCommit(false);
            for (int i = 0; i < phoneList.size(); i++) {
                PhoneList call = phoneList.get(i);
                Long startTime = DateUtils.getSec("00:00");
                String date1 = phone.getTodayBegin();
                String date2 = phone.getTodayStop();
                logger.warn("======date1:{} date2:{}", date1, date2);
                if (StringUtil.isNotEmpty(date1)) {
                    startTime = DateUtils.getSec(date1.substring(date1.indexOf(":") - 2));
                }
                long endTime = DateUtils.getSec("23:58");
                if (StringUtil.isNotEmpty(date2)) {
                    endTime = DateUtils.getSec(date2.substring(date2.indexOf(":") - 2));
                }
                logger.warn("======startTime:{} endTime:{}", startTime, endTime);
                if (StringUtils.isNotEmpty(sql)) {
                    String startTimeParam = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, phone.getStartTime());
                    String endTimeParam = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, phone.getEndTime());
                    ps = jdbcUtils.createPreparedStatement2(ps, call.getId(), 2, 1, 0, phone.getRetryCount(), startTime, endTime,
                            112, call.getId(), 0, phone.getPrefix() + call.getCustomerPhone(), 1, phone.getPrefix() + call.getCustomerPhone(),
                            1, phone.getName(), 101, phone.getCampaignId(), phone.getMark(), phone.getIvrProfileUrl(), startTimeParam, endTimeParam);
                }
                ps.addBatch();
                if (i % 500 == 0) {
                    ps.executeBatch();
                    ps.clearBatch();
                }
            }
            ps.executeBatch();
            ps.clearBatch();
            //所有语句都执行完毕后才手动提交sql语句
            conn.commit();
        } catch (SQLException e) {
            logger.error("insertBatchSql error:{}", e);
        } finally {
            jdbcUtils.close(conn, ps);
        }

jdbcutils工具,也可以自己实现

package com.gary.utils.jdbc;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
 * JDBC工具类
 *
 * @author byx
 */
public class JdbcUtils {
    private final ConnectionManager connManager;
    private static Logger logger = LoggerFactory.getLogger(JdbcUtils.class);

    /**
     * 创建JdbcUtils
     *
     * @param dataSource 数据源
     */
    public JdbcUtils(DataSource dataSource) {
        connManager = new ConnectionManager(dataSource);
    }

    public Connection getConnection() {
        return connManager.getConnection();
    }

    public void close(Connection conn, PreparedStatement stmt) {
        connManager.close(conn, stmt, null);
    }

    public PreparedStatement createPreparedStatement1(Connection conn, String sql) throws SQLException {
        PreparedStatement stmt = conn.prepareStatement(sql);
        return stmt;
    }

    public PreparedStatement createPreparedStatement2(PreparedStatement stmt, Object... params) throws SQLException {
        for (int i = 0; i < params.length; ++i) {
            stmt.setObject(i + 1, params[i]);
        }
        return stmt;
    }

    private PreparedStatement createPreparedStatement(Connection conn, String sql, Object... params) throws SQLException {
        PreparedStatement stmt = conn.prepareStatement(sql);
        for (int i = 0; i < params.length; ++i) {
            stmt.setObject(i + 1, params[i]);
        }
        return stmt;
    }

    /**
     * 查询数据库并转换结果集。
     * 用户可自定义结果集转换器。
     * 用户也可使用预定义的结果集转换器。
     *
     * @param sql          sql语句
     * @param resultMapper 结果集转换器
     * @param params       sql参数
     * @param           resultSetMapper返回的结果类型
     * @return 成功则返回转换结果,失败则抛出DbException,结果为空则返回空列表
     * @see ResultMapper
     * @see ListResultMapper
     * @see SingleRowResultMapper
     */
    public  T query(String sql, ResultMapper resultMapper, Object... params) {
        ResultSet rs = null;
        PreparedStatement stmt = null;
        Connection conn = null;
        try {
            conn = connManager.getConnection();
            logger.info("conn:{}", conn);
            stmt = createPreparedStatement(conn, sql, params);
            rs = stmt.executeQuery();
            return resultMapper.map(rs);
        } catch (SQLException e) {
            throw new DbException(e.getMessage(), e);
        } finally {
            connManager.close(conn, stmt, rs);
        }
    }

    /**
     * 查询数据库,对结果集的每一行进行转换,然后将所有行封装成列表。
     * 用户可自定义行转换器。
     * 用户也可使用预定义的行转换器。
     *
     * @param sql       sql语句
     * @param rowMapper 行转换器
     * @param params    sql参数
     * @param        rowMapper返回的结果类型
     * @return 成功则返回结果列表,失败则抛出DbException,结果为空则返回空列表
     * @see RowMapper
     * @see BeanRowMapper
     * @see MapRowMapper
     * @see SingleColumnRowMapper
     */
    public  List queryList(String sql, RowMapper rowMapper, Object... params) {
        return query(sql, new ListResultMapper<>(rowMapper), params);
    }

    /**
     * 查询数据库,将结果集的每一行转换成JavaBean,然后将所有行封装成列表。
     *
     * @param sql    sql语句
     * @param type   JavaBean类型
     * @param params sql参数
     * @param     JavaBean类型
     * @return 成功则返回结果列表,失败则抛出DbException,结果为空则返回空列表
     */
    public  List queryList(String sql, Class type, Object... params) {
        return query(sql, new ListResultMapper<>(new BeanRowMapper<>(type)), params);
    }

    /**
     * 查询数据库,返回结果集中的单个值。
     * 如果结果集中有多个值,则只返回第一行第一列的值。
     *
     * @param sql    sql语句
     * @param params sql参数
     * @param     结果类型
     * @return 成功则返回结果值,失败则抛出DbException,结果为空则返回null
     */
    public  T querySingleValue(String sql, Object... params) {
        return query(sql, new SingleRowResultMapper<>(new SingleColumnRowMapper<>()), params);
    }

    /**
     * 查询数据库,返回结果集中的单行数据。
     * 如果结果集中有多行数据,则只返回第一行数据。
     * 用户可自定义行转换器。
     * 用户也可使用预定义的行转换器。
     *
     * @param sql       sql语句
     * @param rowMapper 行转换器
     * @param params    sql参数
     * @param        rowMapper返回的结果类型
     * @return 成功则返回结果,失败则抛出DbException,结果为空则返回null
     * @see RowMapper
     * @see BeanRowMapper
     * @see MapRowMapper
     * @see SingleColumnRowMapper
     */
    public  T querySingleRow(String sql, RowMapper rowMapper, Object... params) {
        return query(sql, new SingleRowResultMapper<>(rowMapper), params);
    }

    /**
     * 查询数据库,将结果集中的单行数据转换成JavaBean。
     *
     * @param sql    sql语句
     * @param type   JavaBean类型
     * @param params sql参数
     * @param     JavaBean类型
     * @return 成功则返回结果,失败则抛出DbException,结果为空则返回null
     */
    public  T querySingleRow(String sql, Class type, Object... params) {
        return querySingleRow(sql, new BeanRowMapper<>(type), params);
    }

    /**
     * 更新数据库,返回影响行数
     *
     * @param sql    sql语句
     * @param params sql参数
     * @return 成功则返回影响行数,失败则抛出DbException
     */
    public int update(String sql, Object... params) {
        Connection conn = null;
        PreparedStatement stmt = null;

        try {
            conn = connManager.getConnection();
            stmt = createPreparedStatement(conn, sql, params);
            return stmt.executeUpdate();
        } catch (Exception e) {
            throw new DbException(e.getMessage(), e);
        } finally {
            connManager.close(conn, stmt, null);
        }
    }

    /**
     * 开启事务
     */
    public void startTransaction() {
        connManager.startTransaction();
    }

    /**
     * 提交事务
     */
    public void commit() {
        connManager.commit();
    }

    /**
     * 回滚事务
     */
    public void rollback() {
        connManager.rollback();
    }

    /**
     * 判断当前是否在事务中
     */
    public boolean inTransaction() {
        return connManager.inTransaction();
    }
}

Datasource实现

package com.system.modules.utils.jdbc;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class JdbcDataSource {
    private static Logger logger = LoggerFactory.getLogger(JdbcDataSource.class);
    // 1.	声明静态数据源成员变量
    private static DataSource ds;

    // 2. 创建连接池对象
    static {
        logger.info("===数据库初始化====");
        // 加载配置文件中的数据
        InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("durid.properties");
        Properties pp = new Properties();

        try {
            pp.load(is);
            logger.info("===数据库初始化====:{}",pp);
            // 创建连接池,使用配置文件中的参数
            ds = DruidDataSourceFactory.createDataSource(pp);
        } catch (IOException e) {
            logger.info("===数据库初始化====error:{}",e);
        } catch (Exception e) {
            logger.info("===数据库初始化====Exception:{}",e);
        }
    }

    // 3. 定义公有的得到数据源的方法
    public static DataSource getDataSource() {
        return ds;
    }
}

durid.propertes 实现:

driverClassName=org.postgresql.Driver
url=jdbc:postgresql://100.2.13.2:5432/postgres?reWriteBatchedInserts=true
username=root
password=123456
initialSize=5
maxActive=50
maxWait=3000

 执行时间:

看着速度快了许多。 

4.总结 

接下来还要研究下,mybatisplus为什么还是慢。 

你可能感兴趣的:(服务器,运维)