因为目前SME项目中编写了一套蜘蛛爬虫程序,所以导致插入数据库的数据量剧增。就项目中使用到的3种DB插入方式进行了一个Demo分析:
具体代码如下:
1: MyBatis 开启Batch方式,最普通的带自动事务的插入:
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, true);
try {
Date dt1 = new Date();
SemAccountMapper dao = session.getMapper(SemAccountMapper.class);
dao.addSemAccountBatch(accounts);
//session.commit();
//session.clearCache();
Date dt2 = new Date();
return (dt2.getTime() - dt1.getTime()) / 1000.0;
} catch (Exception e) {
session.rollback();
throw e;
}
1.1 开启Batch,但不使用自动事务
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false); try { Date dt1 = new Date(); SemAccountMapper dao = session.getMapper(SemAccountMapper.class); dao.addSemAccountBatch(accounts); session.commit(); session.clearCache(); Date dt2 = new Date(); return (dt2.getTime() - dt1.getTime()) / 1000.0; }
2: MyBatis_spring 普通的插入
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, true); try { Date dt1 = new Date(); SemAccountMapper dao = session.getMapper(SemAccountMapper.class); dao.addSemAccountBatch(accounts); session.commit(); session.clearCache(); Date dt2 = new Date(); return (dt2.getTime() - dt1.getTime()) / 1000.0; }
3:Jdbc 批量操作,设置普通连接字符串
public static final String DBURL = "jdbc:mysql://192.168.21.225:3306/sem"; Connection con = null; // 表示数据库的连接对象 Class.forName(DBDRIVER); // 1、使用CLASS 类加载驱动程序 con = DriverManager.getConnection(DBURL, DBUSER, DBPASS); // 2、连接数据库 try { con.setAutoCommit(false); String sql = "Insert into" + " sem_account(ClientId,Name,SEAccountName,SEPassword,SEStatus,Status,CreatorId,CreatedTime,LastChanged) " + " Values " + " (?,?,?,?,?,?,?,?,?) "; PreparedStatement prest = con.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); for (int i = 0; i < length; i++) { prest.setInt(1, 1); prest.setString(2, i + ""); prest.setString(3, i + ""); prest.setString(4, i + ""); prest.setInt(5, 1); prest.setInt(6, 1); prest.setInt(7, 1); prest.setString(8, DateUtil.getCurrentDate()); prest.setString(9, DateUtil.getCurrentDate()); prest.addBatch(); } Date dt1 = new Date(); prest.executeBatch(); con.commit(); Date dt2 = new Date(); return (dt2.getTime() - dt1.getTime()) / 1000.0; }
3.1 设置批量连接字符串 rewriteBatchedStatements=true,与上面不同的只有连接字符串不同
public static final String DBURL = "jdbc:mysql://192.168.21.225:3306/sem?rewriteBatchedStatements=true";
以上所有方法,在测试程序中,都执行2次,防止有连接池缓存影响速度上的判断,插入数据库数据位10w条数据,得到以下分析结果:
插入数据库方式 | 第一次插入10w条时间(s) | 第二次插入10w条时间(s) |
MyBatis 开启Batch 自动事务提交 | 42.703 | 35.747 |
MyBatis 开启Batch 关闭自动事务,自提交 | 38.875 | 40.285 |
MyBatis-Spring 普通提交 | 37.199 | 36.607 |
Jdbc 批量操作,普通连接字符串 | 98.589 | 97.973 |
Jdbc 批量操作,设置批量操作字符串 | 3.311 | 3.244 |
从以上操作来看,其中Mybatis自动事务,和Mybatis-Spring 的方法所用时间基本一致,
而最快的操作在 Jdbc 带上批量操作参数以后的速度 3.244s。
附带InsertBatch的Mapper文件
<insert id="addSemAccountBatch" parameterType="SemAccount"> Insert into sem_account (ClientId,Name,SyncId,SyncTime,SEId,SESyncTime,SEAccountName,SEPassword,SEApiToken,SEStatus,Cost,BudgetPerDay,Balance,Payment,ExcludeIps,RegionTargets,OpenDomains,BudgetOfflineTime,Remark,WarningRemainingDays,WarningRemainingCost,Status,CreatorId,CreatedTime,LastChanged,SearchEngineType,SearchEngineConstId) Values <foreach collection="list" item="item" index="index" separator=","> (#{item.clientId},#{item.name},#{item.syncId},#{item.syncTime},#{item.sEId},#{item.sESyncTime},#{item.sEAccountName},#{item.sEPassword},#{item.sEApiToken},#{item.sEStatus},#{item.cost},#{item.budgetPerDay},#{item.balance},#{item.payment},#{item.excludeIps},#{item.regionTargets},#{item.openDomains},#{item.budgetOfflineTime},#{item.remark},#{item.warningRemainingDays},#{item.warningRemainingCost},#{item.status},#{item.creatorId},#{item.createdTime},#{item.lastChanged},#{item.searchEngineType},#{item.searchEngineConstId}) </foreach> </insert>