对MySQL中的表进行批量update的时候,如果每个记录用一个update语句,5000条记录的话,大概需要30秒钟。下面采用的case when方法可以把5000条update拼成一条:
- Update myTable
- SET myField = CASE id
- WHEN 1 THEN 'value1'
- WHEN 2 THEN 'value2'
- WHEN 3 THEN 'value3'
- END
- WHERE id IN (1,2,3)
具体的MyBatis代码如下:
- <update id="updatePrice" parameterType="java.util.List">
- UPDATE t_price
- SET price = CASE code
- <foreach collection="list" item="item">
- WHEN #{item.code} THEN #{item.price}
- </foreach>
- END
- WHERE
- code in
- <foreach collection="list" item="item" open="(" separator="," close=")">
- #{item.code}
- </foreach>
- </update>
实际上,为了避免一条语句超过MySQL语句的最大长度限制,一般会把5000个数据分成几组,每组拼凑一条语句。因此,Java代码调用MyBatis的dao之前需要拆分被update的List,以避免sql语句超长。比如按1000条每组来拆分,使用Guava的工具类Lists中的partition方法:
- import com.google.common.collect.Lists;
- ......
- List<List<Map<String, Object>>> list = (List<List<Map<String, Object>>>) Lists.partition(orders, 1000);
- int success = 0;
- for (List<Map<String, Object>> l : list) {
- success += priceDao.updatePrice(l);
- }
这样优化后,原来的5000条update语句,就被合并成了5条,执行时间缩短到了2秒钟以内。