mysql 进行批量修改(包括 on duplicate key update)

1.

说明:mybatis 做批量修改的时候,需要配置文件中(数据库URL后面加上 &allowMultiQueries=true),允许通过代码进行 批量修改

之前遇到问题:扒出来的批量修改的SQL在datagrip可以运行,在代码中运行就报语法问题(check right synax?) 就是少了&allowMultiQueries=true 这个

作用:

MySQL连接数据库时,添加语句:“allowMultiQueries=true”的作用:
1.可以在sql语句后携带分号,实现多语句执行。
2.可以执行批处理,同时发出多个SQL语句。

1. mysql 批量修改的思路:

① 在mybatis 的xml 文件中拼接update语句,每个语句后面 都追加 “;” ,一个会话执行多个sql(数据量不超过1000的话,可以用这种方法,1000条数据耗时15s,太多的话易堵塞,而且语法简单,方便扩展,增加一个字段,减少一个字段,很方便,数据量不大的情况推荐使用此法)

case id when 某个id值 then else end 语法(注意:else 必须要加,非常重要,如果不指定else的话,其他不符合条件的字段数据会被置为null,所以这个语法有风险,不熟悉的话,一般用id 限制的话就没问题),主要表的字段名不要取 order,name 这些,用在 case when then else end 语法里会报错

设置为null的情况:(没有限制条件)

UPDATE graduates
SET income =
CASEWHEN income = 20000 THENincome * 0.5WHEN income = 15000 THENincome + 500
#  像这种场景,where 后面没有条件,也没有加 else ,就会把库里 不是  20000 和 15000 的数据 设置为 null
#  ELSE income
END ;
# where name = '怀特'

之前所有的income都有值:

+----+------+
|name|income|
+----+------+
|桑普森 |NULL  |
|迈克  |NULL  |
|怀特  |NULL  |
|阿诺德 |10000 |
|史密斯 |10000 |
|劳伦斯 |15500 |
|哈德逊 |15500 |
|肯特  |NULL  |
|贝克  |NULL  |
|斯科特 |NULL  |
+----+------+

 

case when then else end的正确sql如下:(不要在网上copy 示例,要尽量自己写,网上有的示例自己copy过来,运行时候,可能有特殊字符,肉眼无法发现,最终报错:排查了一个上午最终决定自己写一下子就出来了,原因在最底下,告诫自己以后不要犯类似的错误)

# 3 rows affected in 7 ms
update  girls set
name = case  when  id = 1  then '1111111'  else name   end ,
name = case  when  id = 2  then '2222222'  else name   end ,
name = case  when  id = 3  then '3333333'  else name   end ,sex = case  when  id = 1  then 'W'  else sex   end ,
sex = case  when  id = 2  then 'W'   else sex   end ,
sex = case  when  id = 3  then 'W'   else sex   end
where id in (1,2,3)

③ on duplicate  key on

④ 修改多表的sql演变:语法如下:

   


UPDATE A as a
INNER JOIN B as b ON b.aid = a.id
AND a.is_deleted = 0SET a.字段1=b.value1,a.字段2=b.value2,a.字段3=b.value3WHERE a.id=b.aid
#   其他限制条件AND a.字段4=? ;

demo:

#  3 rows affected in 8 ms
update (
#     操作的数据集start(select '1' as id , '黄蓉1' as name, 'W' as sexunionselect '2' as id , '黄蓉1' as name, 'W' as sexunionselect '3' as id , '陆无双1' as name, 'W' as sex) as tmp inner join girl on girl.id = tmp.id
#       只对物理表的女生进行操作:限制条件 是为了获取更少的数据集and girl.sex = '女'
#     操作的数据集end)
# 将 前段传过来的  tem 里的 字段值 赋值给 物理表
setgirl.name  = tmp.name,girl.sex = tmp.sex
# girl.sex = '女' 加到这里也行 做个限制
where  girl.sex = '女' ;

 

1. 

on duplicate key update 是  mysql的 特有功能(必须得设定主键,否则,会不停的进行插入操作)

有就进行插入,没有就根据主键进行更新

1. 没有设定主键

 

create table sql_test.on_duplicate_key_update_employee
(id       int                     not null,name     varchar(20)             null,password varchar(20)             null,sex      varchar(10) default 'M' null
);

 

查询表结果为空:

select * from on_duplicate_key_update_employee;
# +--+----+--------+---+
# |id|name|password|sex|
# +--+----+--------+---+

 

连续执行两次以下sql:

INSERT INTO on_duplicate_key_update_employee (id, name, password)
VALUES (1, '郭一光','111111'),(2, '慕容皝','2222222'),(3, '慕容垂','333333')
ON DUPLICATE KEY UPDATEpassword = 'upPassword';

 

查询表:发现每执行一个插入sql就会 执行插入(因为现在没有建主键)

select * from on_duplicate_key_update_employee;
# +--+----+--------+---+
# |id|name|password|sex|
# +--+----+--------+---+
# |1 |郭一光 |111111  |M  |
# |2 |慕容皝 |2222222 |M  |
# |3 |慕容垂 |333333  |M  |
# |1 |郭一光 |111111  |M  |
# |2 |慕容皝 |2222222 |M  |
# |3 |慕容垂 |333333  |M  |
# +--+----+--------+---+

 

2. 清空上表的数据,(不清空数据,因为表里有重复的 id 所以建立不了主键,所以必须清空数据)并建立主键后 

create table sql_test.on_duplicate_key_update_employee
(id       int                     not nullprimary key,name     varchar(20)             null,password varchar(20)             null,sex      varchar(10) default 'M' null
);

执行两次sql,并查询结果

 


#  执行 第一次
select * from on_duplicate_key_update_employee;
# +--+----+------------------------------+---+
# |id|name|password                      |sex|
# +--+----+------------------------------+---+
# |1 |郭一光 |建立主键后的 on_duplicate_key_update|M  |
# |2 |慕容皝 |建立主键后的 on_duplicate_key_update|M  |
# |3 |慕容垂 |建立主键后的 on_duplicate_key_update|M  |
# +--+----+------------------------------+---+#  执行 第二次
select * from on_duplicate_key_update_employee;
# +--+----+----------+---+
# |id|name|password  |sex|
# +--+----+----------+---+
# |1 |郭一光 |upPassword|M  |
# |2 |慕容皝 |upPassword|M  |
# |3 |慕容垂 |upPassword|M  |
# +--+----+----------+---+

 

 

 

2. 批量更新(根据主键,给不同的记录进行更新)说明:关键是 用 values() 函数

方便测试:还是清空表里的数据:

# 第一次执行的sql
INSERT INTO on_duplicate_key_update_employee (id, name, password)
VALUES (1, '郭一光','111111'),(2, '慕容皝','2222222'),(3, '慕容垂','3333333')
ON DUPLICATE KEY UPDATE
password =  VALUES(password);select  * from  on_duplicate_key_update_employee;
# +--+----+--------+---+
# |id|name|password|sex|
# +--+----+--------+---+
# |1 |郭一光 |111111  |M  |
# |2 |慕容皝 |2222222 |M  |
# |3 |慕容垂 |3333333 |M  |
# +--+----+--------+---+# 第二次执行的sql
INSERT INTO on_duplicate_key_update_employee (id, name, password)
VALUES (1, '郭一光','update_111111'),(2, '慕容皝','update_2222222'),(3, '慕容垂','3333333')
ON DUPLICATE KEY UPDATE
password =  VALUES(password);select  * from  on_duplicate_key_update_employee;
# +--+----+--------------+---+
# |id|name|password      |sex|
# +--+----+--------------+---+
# |1 |郭一光 |update_111111 |M  |
# |2 |慕容皝 |update_2222222|M  |
# |3 |慕容垂 |3333333       |M  |
# +--+----+--------------+---+# 第三次执行的sql
INSERT INTO on_duplicate_key_update_employee (id, name, password)
VALUES (1, '郭一光','update_111111'),(2, '慕容皝','update_2222222'),(3, '慕容垂','3333333'),(4, '慕容雪','insert_test')
ON DUPLICATE KEY UPDATE
password =  VALUES(password);select  * from  on_duplicate_key_update_employee;
# +--+----+--------------+---+
# |id|name|password      |sex|
# +--+----+--------------+---+
# |1 |郭一光 |update_111111 |M  |
# |2 |慕容皝 |update_2222222|M  |
# |3 |慕容垂 |3333333       |M  |
# |4 |慕容雪 |insert_test   |M  |
# +--+----+--------------+---+# 4 rows affected in 7 ms

 

3. 批量更新多个字段


# 增加多个字段# 先插入测试数据
INSERT INTO on_duplicate_key_update_employee (id, name, password,sex)
VALUES (1, '郭一光','update_111111','M'),(2, '慕容皝','update_2222222','M'),(3, '慕容垂','3333333','M'),(4, '慕容雪','insert_test','M')
ON DUPLICATE KEY UPDATE
name =  VALUES(name),
password =  VALUES(password),
sex =  VALUES(sex) ;
# 4 rows affected in 7 msselect * from on_duplicate_key_update_employee ;
# +--+----+--------------+---+
# |id|name|password      |sex|
# +--+----+--------------+---+
# |1 |郭一光 |update_111111 |M  |
# |2 |慕容皝 |update_2222222|M  |
# |3 |慕容垂 |3333333       |M  |
# |4 |慕容雪 |insert_test   |M  |
# +--+----+--------------+---+# 进行批量更新多个字段INSERT INTO on_duplicate_key_update_employee (id, name, password,sex)
VALUES (1, '郭一光','update_111111','M'),(2, '慕容皝','update_2222222','M'),(3, '慕容垂','3333333','M'),(4, '慕容雪','insert_test','W')
ON DUPLICATE KEY UPDATE
name =  VALUES(name),
password =  VALUES(password),
sex =  VALUES(sex) ;# 5 rows affected in 8 ms# 查看
select * from on_duplicate_key_update_employee ;
# +--+----+--------------+---+
# |id|name|password      |sex|
# +--+----+--------------+---+
# |1 |郭一光 |update_111111 |M  |
# |2 |慕容皝 |update_2222222|M  |
# |3 |慕容垂 |3333333       |M  |
# |4 |慕容雪 |insert_test   |W  |
# +--+----+--------------+---+

如果给 created_time  一个非空 约束,则操作的时候必须给 created_time 一个默认值 ,否则报错,所以如果是批量更新就把创建日期给 改了,不合适,所以可以考虑不加created_time 

### SQL: INSERT INTO on_duplicate_key_update_employee (id, name, password,sex)     VALUES                         (   ? , ? , ? , ? )          ,              (   ? , ? , ? , ? )          ,              (   ? , ? , ? , ? )          ,              (   ? , ? , ? , ? )                ON DUPLICATE KEY UPDATE     name =  VALUES(name),     password =  VALUES(password),     sex =  VALUES(sex)
### Cause: java.sql.SQLException: Field 'created_time' doesn't have a default value
; Field 'created_time' doesn't have a default value; nested exception is java.sql.SQLException: Field 'created_time' doesn't have a default value

但是呢,onDuplicate key  update 一般是用来批量操作的,可以考虑将  created_time 的 非空约束去掉

mybatis 的用法:

   List a = new ArrayList();OnDuplicateKeyUpdateUser user1 =  new OnDuplicateKeyUpdateUser();user1.setId(1);user1.setName("王五");user1.setSex("M");user1.setPassword("******");OnDuplicateKeyUpdateUser user2 =  new OnDuplicateKeyUpdateUser();user2.setId(2);user2.setName("李四2222222222");user2.setSex("M");user2.setPassword("******");OnDuplicateKeyUpdateUser para =    new OnDuplicateKeyUpdateUser();para.setId(1);para.setName("h");para.setSex("h");para.setPassword("p");para.setList(a);int i = onDupicateKeyUpdateMapper.updateBatch3(para);
package com.springboot.demo.model;import lombok.Data;import java.time.LocalDateTime;
import java.util.List;@Data
public class OnDuplicateKeyUpdateUser  {private Integer id;private String name;private String password;private String sex;private LocalDateTime createdTime;List list;
}
package com.springboot.demo.mapper;import com.springboot.demo.model.Region;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import com.springboot.demo.model.OnDuplicateKeyUpdateUser;
import java.util.List;@Repository
public interface OnDupicateKeyUpdateMapper {public int updateBatch1(@Param("list") List list);public int updateBatch2(@Param("list") List list);public int updateBatch3(OnDuplicateKeyUpdateUser para);}

 

 



UPDATE on_duplicate_key_update_employeename = #{item.name},password = #{item.password},sex = #{item.sex},created_time = #{item.createdTime},id = #{item.id}update on_duplicate_key_update_employeewhen id=#{item.id} then #{item.name}when id=#{item.id} then on_duplicate_key_update_employee.namewhen id=#{item.id} then #{item.password}when id=#{item.id} then #{item.sex}when id=#{item.id} then #{item.createdTime}where id in#{item.id}
INSERT INTO on_duplicate_key_update_employee(id,name,password,sex)VALUES(#{item.id} ,#{item.name} ,#{item.password} ,#{item.sex})ON DUPLICATE KEY UPDATEname =  VALUES(name),password =  VALUES(password),sex =  VALUES(sex)

二 case when then end 做批量修改:(一个update语句就把批量数据处理了,但是有风险,如果  不加 else的话,很容易将全库的某列字段 设置为 null,如果是金额话)

update on_duplicate_key_update_employee
SET name=casewhen id = 1 then '1111111111111'when id = 2 then '2222222222'when id = 3 then '3333333333'when id = 4 then '44444444444'
#            ELSE name 这个条件非常重要,没有的话,会把所有不满足条件的数据都清理成nullELSE nameend
WHERE id in (1, 2, 3, 4);

 

update s_order
set name        = case when id = 16 then '测试' else name END,description = CASE WHEN id = 16 THEN '测试批量修改' else description END,updatedGUID = CASE WHEN id = 16 THEN '12345234563456' else updatedGUID END,updatedTime = CASE WHEN id = 16 THEN '2021-03-04 19:08:59.157' else updatedTime END,name        = case when id = 17 then '测试' else name END,description = CASE WHEN id = 17 THEN '测试批量修改' else description END,updatedGUID = CASE WHEN id = 17 THEN '12345234563456' else updatedGUID END,updatedTime = CASE WHEN id = 17 THEN '2021-03-04 19:08:59.157' else updatedTime END,name        = case when id = 18 then '测试' else name END,description = CASE WHEN id = 18 THEN '测试批量修改' else description END,updatedGUID = CASE WHEN id = 18 THEN '12345234563456' else updatedGUID END,updatedTime = CASE WHEN id = 18 THEN '2021-03-04 19:08:59.157' else updatedTime END,name        = case when id = 19 then '测试' else name END,description = CASE WHEN id = 19 THEN '测试批量修改' else description END,updatedGUID = CASE WHEN id = 19 THEN '12345234563456' else updatedGUID END,updatedTime = CASE WHEN id = 19 THEN '2021-03-04 19:08:59.157' else updatedTime END,name        = case when id = 20 then '测试' else name END,description = CASE WHEN id = 20 THEN '测试批量修改' else description END,updatedGUID = CASE WHEN id = 20 THEN '12345234563456' else updatedGUID END,updatedTime = CASE WHEN id = 20 THEN '2021-03-04 19:08:59.158' else updatedTime END
WHERE id in (16, 17, 18, 19, 20);

参考xml:

update s_ordername = case when id = #{item.id} then #{item.name} else name END,description = CASE WHEN id = #{item.id} THEN #{item.description} else description END,updatedGUID = CASE WHEN id = #{item.id} THEN #{item.updatedGUID} else updatedGUID END,updatedTime = CASE WHEN id = #{item.id} THEN #{item.updatedTime} else updatedTime END,where id in#{item.id}

mapper 接口:

 int  updateBatchOrders(@Param("list") List list);

 

 

 

 

注意一定要  加这个配置:否则 批量修改不生效(在可视化工具执行没问题,在Java代码中就有问题)

spring.datasource.url=jdbc:mysql://localhost:3306/sql_test?serverTimezone=UTC&characterEncoding=utf-8&allowMultiQueries=true

1. 之前从网上copy的代码模板,一直运行不了,报语法问题,检查版本

 

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部