MySQLGORM插入数据,存在则覆盖之前的数据
Posted LD无一
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQLGORM插入数据,存在则覆盖之前的数据相关的知识,希望对你有一定的参考价值。
简述
根据业务背景(将备份的数据覆盖当前记录),做冲突时批量更新操作。
mysql支持的批量更新操作。
insert into...on duplicate key update 的 自增 ID 跳跃和处理方式。
插入失败自增 ID 增加问题。
GORM实现的冲突时批量更新操作。
目录
1、insert into...on duplicate key update
3、update...set...case...when...where
MySQL支持的批量更新
1、insert into...on duplicate key update
插入操作。主键(PRIMARY KEY)或者唯一索引(unique key)冲突时,执行update,除主键外字段都更新。支持批量。values是针对该语句添加批量数据的。mysql8.0以后values推荐其他写法。
注意:经过测试,唯一值(unique)也会触发更新。不必须是索引和主键。
insert into users (id, job, age) values (1, 'job11', 11),(2, 'job22', 22)
on duplicate key update job=values(job), age=values(age);
1.1 自增id跳跃现象
执行该SQL,利用 name 字段唯一的冲突更新记录时,下次插入记录,自增id会跳跃(该SQL会占用一个自增id的值)。
# id 自增主键, name 唯一。
# 原始记录
mysql> select * from for_update;
+----+-------+------+
| id | name | age |
+----+-------+------+
| 12 | disi | 25 |
| 13 | diliu | 26 |
+----+-------+------+
# 更新id=13的记录
mysql> insert into for_update(name, age) values('diliu', 16)
on duplicate key update name=values(name), age=values(age);
# 更新后的记录
mysql> select * from for_update;
+----+-------+------+
| id | name | age |
+----+-------+------+
| 12 | disi | 25 |
| 13 | diliu | 16 |
+----+-------+------+
# 插入一条新记录
mysql> insert into for_update(name, age) values('qi',27);
# 新插入的记录自增id=15,跳过14
mysql> select * from for_update;
+----+-------+------+
| id | name | age |
+----+-------+------+
| 12 | disi | 25 |
| 13 | diliu | 16 |
| 15 | qi | 27 |
+----+-------+------+
1.2 解决自增id跳跃问题
暂时忽略方法:网上说修改 innodb_autoinc_lock_mode
改变加锁的范围,有0,1,2模式,网上说设置0,加表锁,解决id跳跃。但是并发不好。
实际使用方法:执行 insert into...on duplicate key update 语句时,指定自增 id 的值,利用id冲突更新。
自增 id 的自增情况:
- insert语句,value没有包含自增 id 的值,默认设置为最大序号+1。
- insert语句,value指定 id 值,没有冲突会将指定的值插入,并且更新最大序号。当前插入的id值是最大的,最大序号会变为插入的值。下一次插入会最大序号+1。
特殊情况:insert插入有冲突会报错,但是自增id会增加。
经过测试: id 冲突时,自增id不会自增。
注意:暂时不知道哪些插入失败的情况id不会增加,不知道为什么不会增加
# id 自增主键,name 唯一值
# 原始记录
mysql> select * from for_update;
+----+-------+------+
| id | name | age |
+----+-------+------+
| 16 | ba | 28 |
| 17 | jiu | 29 |
| 18 | ershi | 210 |
+----+-------+------+
# 插入name冲突记录,失败,id增加
mysql> insert into for_update(name, age) values('ershi',210);
ERROR 1062 (23000): Duplicate entry 'ershi' for key 'for_update.name'
# 插入新记录,成功
mysql> insert into for_update(name, age) values('ershiyi',211);
Query OK, 1 row affected (0.00 sec)
# id=20,跳过19
mysql> select * from for_update;
+----+---------+------+
| id | name | age |
+----+---------+------+
| 16 | ba | 28 |
| 17 | jiu | 29 |
| 18 | ershi | 210 |
| 20 | ershiyi | 211 |
+----+---------+------+
# 插入id冲突记录,失败,id不自增
mysql> insert into for_update(id, name, age) values(20, 'ershiyi',211);
ERROR 1062 (23000): Duplicate entry '20' for key 'for_update.PRIMARY'
# 插入一条记录,成功,id没有跳跃
mysql> insert into for_update(name, age) values('ershier',212);
Query OK, 1 row affected (0.00 sec)
mysql> select * from for_update;
+----+---------+------+
| id | name | age |
+----+---------+------+
| 16 | ba | 28 |
| 17 | jiu | 29 |
| 18 | ershi | 210 |
| 20 | ershiyi | 211 |
| 21 | ershier | 212 |
+----+---------+------+
利用自增id冲突,更新数据:根据上面的情况,在执行 insert into...on duplicate key update 语句时,指定 id 的值。有冲突会更新,此时更新不会导致子增id增加。
# id 自增主键, name 唯一。
# 原始记录
mysql> select * from for_update;
+----+-------+------+
| id | name | age |
+----+-------+------+
| 12 | disi | 25 |
| 13 | diliu | 16 |
| 15 | qi | 27 |
+----+-------+------+
# 更新id=15的记录,并且value的 id 字段指定为 15
mysql> insert into for_update(id, name, age) values(15, 'qi', 36) on duplicate
key update id =values(id), name=values(name), age=values(age);
# 记录更新age=36
mysql> select * from for_update;
+----+-------+------+
| id | name | age |
+----+-------+------+
| 12 | disi | 25 |
| 13 | diliu | 16 |
| 15 | qi | 36 |
+----+-------+------+
# 插入一条新记录
mysql> insert into for_update(name, age) values('ba',28);
# 自增 id=16 没有发生跳跃
mysql> select * from for_update;
+----+-------+------+
| id | name | age |
+----+-------+------+
| 12 | disi | 25 |
| 13 | diliu | 16 |
| 15 | qi | 36 |
| 16 | ba | 28 |
+----+-------+------+
2、replace into
主键(PRIMARY KEY)或者唯一索引(unique key)冲突时,先删除此记录,再重新插入。字段不全设置为默认值。支持批量。
注意:同上猜测 唯一值(unique)也会冲突。
replace into users(id, job, age) VALUES (1, 'job111', 111),(2, 'job222', 222);
3、update...set...case...when...where
较麻烦。支持批量。当id=1时,job=‘job11’。当id=2时,job=‘job12'。
update users
set job = case id
when 1 then 'job11'
when 2 then 'job12'
end,
age = case id
when 1 then 11
when 2 then 12
end
where id IN (1, 2);
GORM支持的批量更新
业务背景
之前备份的一批数据,现在要重新写入数据库,并且覆盖当前记录。
处理方法
将之前的数据软删除
tx.Where("my_id = ?", myId).Delete(&Mod)
冲突更新
GORM支持MySQL的 insert into...on duplicate key update 语句,插入冲突时更新记录,支持批量。
// 在冲突时,更新除主键以外的所有列到新值。
db.Clauses(clause.OnConflictUpdateAll: true).Create(&users)
除次以外,GORM还提供冲突部分更新、自定义冲突字段的功能。
// 在`id`冲突时,将列更新为新值
db.Clauses(clause.OnConflict
Columns: []clause.ColumnName: "id",
DoUpdates: clause.AssignmentColumns([]string"name", "age"),
).Create(&users)
// 在`id`冲突时,将列更新为默认值
db.Clauses(clause.OnConflict
Columns: []clause.ColumnName: "id",
DoUpdates: clause.Assignments(map[string]interface"role": "user"),
).Create(&users)
注意
如果冲突不来自自增ID,冲突更新时,ID会增加,产生ID跳跃现象。
PostgreSql INSERT 插入数据判断数据是否存在,存在则更新,不存在则插入
PostgreSql 使用INSERT INTO table_name(id,value) VALUES (1,1) ON CONFLICT(id) DO ....
语法(ON CONFLICT可以接多个字段,但必须存在唯一索引)
在INSERT INTO操作时当唯一键冲突可以做一些解决冲突的处理,一般有如下3种处理场景
-
当唯一键冲突时,不做处理
ON CONFLICT(id) DO NOTHING
-
当唯一键冲突时,value列 +1
ON CONFLICT (id) DO UPDATE SET value = table.value + 1
-
当唯一键冲突时,value设置为insert 时的value
ON CONFLICT (id)DO UPDATE SET value = EXCLUDED.value
以上是关于MySQLGORM插入数据,存在则覆盖之前的数据的主要内容,如果未能解决你的问题,请参考以下文章