最近业务需要同步远程数据,而远程数据只开放HTTP接口,返回JSON,用ETL工具比较难做,还是决定写个简单程序。看到好多文章写到批量更新时提到如下格式会报错
<update id="updateBatch" parameterType="java.util.List">
<foreach item="item" collection="list" separator=";" index="index">
update myTable set name=#{item.name}
where id = #{id}
</foreach>
</update>
建议使用以下格式:
<update id="updateBatch" parameterType="java.util.List">
update table set index=
<foreach collection="list" item="item" index="index" separator=" " open="case ID" close="end">
when #{item.id} then #{item.name}
</foreach>
where ID in
<foreach collection="list" item="item" index="index" separator="," open="(" close=")">
#{item.id}
</foreach>
</update>
其实第一种格式是可以的,只要在配置数据库连接地址中加上&allowMultiQueries=true就可以
jdbcDriver=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql:///localhost:3306/test?characterEncoding=utf-8&allowMultiQueries=true
jdbcusername=root
jdbcpassword=root
1、第一种格式书写方便,看起来更直观,但是生成的sql依然是一条数据一条。和代码for循环差别不大,数据量特别大的时候效率特别低。
2、第二种只生成一条sql,但是sql写起来相当麻烦,每个字段要一个foreach,字段特别多的时候遍历效率也不高,并且如果百万级的数据一条sql推送到db,db压力特别大,锁表时间也特别长。
其实mybatis还有一种方式,通过可以批量提交的 SqlSession 执行:
@Autowired
private SqlSessionFactory sqlSessionFactory;
@Transactional(rollbackFor = Exception.class)
@Override
public void batchTest() {
int commitSize = 200;//单次提交数量
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);
List<Person> personList = mapper.selectAll();
for (int i = 0; i < personList.size(); i++) {
Person person = personList.get(i);
person.setName(person.getName() + "Test");
mapper.updateById(person);
//达到数量提交一次
if((i + 1) % commitSize == 0){
sqlSession.flushStatements();
}
}
sqlSession.flushStatements();
}
最后,技术是服务于业务的,没有最好的技术,只有相对合适的技术,具体实现根据具体业务选择。
具体效率数据,后续有时间再单独测试下再更新文章,各位可根据自身的业务需要结合数据量以及字段数量评估,自行选择。