最近業務需要同步遠程數據,而遠程數據只開放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();
}
最後,技術是服務於業務的,沒有最好的技術,只有相對合適的技術,具體實現根據具體業務選擇。
具體效率數據,後續有時間再單獨測試下再更新文章,各位可根據自身的業務需要結合數據量以及字段數量評估,自行選擇。