1.java代码批量
public void batchInsert(final String statementName, final List list) throws DataAccessException{
SqlSession session = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);
int size = 10000;
try{
if(null != list || list.size() > 0){
for (int i = 0, n = list.size(); i < n; i++) {
this.insert(statementName, list.get(i));
if (i % 1000 == 0 || i == size - 1) {
//手动每1000个一提交,提交后无法回滚
session.commit();
//清理缓存,防止溢出
session.clearCache();
}
}
}
}catch (Exception e){
session.rollback();
if (log4j.isDebugEnabled()) {
e.printStackTrace();
log4j.debug("batchInsert error: id [" + statementName + "], parameterObject [" + list + "]. Cause: " + e.getMessage());
}
} finally {
session.close();
}
}
2.xml方式
<insert id="batchInsert">
insert into table
(
business_id,
element_id,
business_value
)
values
<foreach collection="list" item="item" index="index" separator=",">
(#{item.business_id, jdbcType=VARCHAR},
#{item.element_id, jdbcType=VARCHAR},
#{item.business_value, jdbcType=VARCHAR})
</foreach>
</insert>
使用Junit进行测试
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class WarrantTest extends BaseJunitTest {
@Resource
private IDynamicFormService dynamicFormService;
@Test
@Rollback
@Transactional
public void savetest() {
long total = 0;
for(int count=0; count<10; count++) {
long start = System.currentTimeMillis();
List<Map<String, Object>> list = new ArrayList<>();
for(int i=0; i<30; i++) {
Map<String, Object> map = new HashMap<>();
map.put("key", i);
map.put("value", i);
list.add(map);
}
dynamicFormService.saveDynamicValue("1", list);
long end = System.currentTimeMillis();
total += (end - start);
System.out.println("耗时:"+ (end - start));
}
System.out.println("平均耗时:"+(total/10));
}
}
方式1:平均耗时:1930
方式2:平均耗时:135
xml方式效率提升明显!
原因分析:
执行效率高的主要原因是合并后日志量(MySQL的binlog和innodb的事务让日志)减少了,降低日志刷盘的数据量和频率,从而提高效率。通过合并SQL语句,同时也能减少SQL语句解析的次数,减少网络传输的IO。
注意事项:
- SQL语句是有长度限制,在进行数据合并在同一SQL中务必不能超过SQL长度限制,通过max_allowed_packet配置可以修改,默认是1M,测试时修改为8M。
- 事务需要控制大小,事务太大可能会影响执行的效率。MySQL有innodb_log_buffer_size配置项,超过这个值会把innodb的数据刷到磁盘中,这时,效率会有所下降。所以比较好的做法是,在数据达到这个这个值前进行事务提交。