#java #mysql #jvm #mybatis
#java #mysql #jvm #mybatis
Вопрос:
Мне нужны данные для пакетного обновления, поэтому я использую два метода. 1-Е обновление в цикле «для», и все за одну транзакцию. И 2-й, объединяющий SQL «случай, когда» в XML mybatis. Я думаю, что 1-й будет высокоэффективным, но мой тестовый вывод не в том, что, например, когда я обновляю 5000 данных, эффективность этих методов одинакова, но 2-й метод использует слишком много памяти jvm, в частности, G1 Old Gen и G1 Survivor Space, и он не может быть переработан вовремя. Я не знаю, почему это так, пожалуйста, дайте мне свой ответ.
Проект основан на Springboot 2.0.6, использует MySQL 5.
1-й способ, обновление в цикле «для».
@Transactional
public void testUpdate(){
User user;
long a = System.currentTimeMillis();
for(int i = 1; i < 5000; i ){
user = new User();
user.setId(i);
user.setUsername(RandomStringUtils.randomAlphanumeric(5));
user.setEmail(RandomStringUtils.randomAlphanumeric(5));
user.setPassword(RandomStringUtils.randomAlphanumeric(5));
user.setPhone(RandomStringUtils.randomAlphanumeric(5));
userMapper.updateByPrimaryKey(user);
}
long b = System.currentTimeMillis();
System.out.println("testUpdateT ************************ " (b-a));
}
2-й метод, объединяющий SQL ‘case-when’ в XML mybatis.
public void testUpdateBatch(){
User user;
long a = System.currentTimeMillis();
List<User> list = new ArrayList<>();
for(int i=1;i<5000;i ){
user = new User();
user.setId(i);
user.setUsername(RandomStringUtils.randomAlphanumeric(5));
user.setEmail(RandomStringUtils.randomAlphanumeric(5));
user.setPassword(RandomStringUtils.randomAlphanumeric(5));
user.setPhone(RandomStringUtils.randomAlphanumeric(5));
list.add(user);
}
userMapper.updateBatch(list);
long b = System.currentTimeMillis();
System.out.println("testUpdateT ************************ " (b-a));
}
sql
<update id="updateBatch">
update user
<trim prefix="set" suffixOverrides=",">
<trim prefix="username =case" suffix="end,">
<foreach collection="list" item="i" index="index">
when id=#{i.id} then #{i.username}
</foreach>
</trim>
<trim prefix=" password =case" suffix="end,">
<foreach collection="list" item="i" index="index">
when id=#{i.id} then #{i.password}
</foreach>
</trim>
<trim prefix="email =case" suffix="end," >
<foreach collection="list" item="i" index="index">
when id=#{i.id} then #{i.email}
</foreach>
</trim>
<trim prefix="phone =case" suffix="end," >
<foreach collection="list" item="i" index="index">
when id=#{i.id} then #{i.phone}
</foreach>
</trim>
</trim>
where
<foreach collection="list" separator="or" item="i" index="index" >
id=#{i.id}
</foreach>
</update>
В этой таблице 27000 элементов, 1-й стоит 5500 мс, а 2-й — 8000-10000 мс, и, что наиболее важно, после завершения 2-го метода использование памяти кучи увеличивается, и она не может быть собрана за короткий промежуток времени.
Комментарии:
1. Используете ли вы
BATCH
executor в первом методе? Когда вы говорите, что второй методcan't recycle in time
что именно вы имеете в виду? Когда вы ожидаете освобождения памяти?2. Я не использую batch executor. Теперь я знаю, что большой объект напрямую перейдет к старому поколению, поэтому до следующего полного GC он не может быть переработан. Спасибо за ответ!