传统做法

先查询数据、再判断是否存在,存在则执行更新,不存在则执行插入。

传统做法存在的问题

  • 并发请求可能会出现数据重复插入
  • 效率低
  • 无法保证数据的唯一性
  • 代码量比较大

    使用MySQL唯一索引

    接下来演示如何通过 MySQL 唯一索引实现存在则更新、不存在则插入。

    创建测试表

    创建 progress 进度表,要求 resource_id 不能重复,使用 unique index (resource_id) 声明唯一索引。
    1. create table progress (
    2. progress_id bigint unsigned auto_increment primary key,
    3. resource_id bigint unsigned not null comment '环节id',
    4. rate decimal(8, 2) default 0 not null comment '进度百分比(0~100)',
    5. unique index (resource_id)
    6. ) comment '进度表';
    如果建表的时候没有创建唯一索引,后期也可以通过语句创建唯一索引:
    1. create unique index progress_uindex on progress (resource_id)

    测试插入数据

    插入数据,成功: ```sql mysql> insert into progress(resource_id, rate) VALUES (1, 50); Query OK, 1 row affected (0.01 sec)

mysql> select * from progress; +——————-+——————-+———-+ | progress_id | resource_id | rate | +——————-+——————-+———-+ | 5 | 1 | 50.00 | +——————-+——————-+———-+ 1 row in set (0.00 sec)

  1. 尝试插入重复数据,报错,可以看到唯一索引起作用了:
  2. ```sql
  3. mysql> insert into progress(resource_id, rate) VALUES (1, 50);
  4. ERROR 1062 (23000): Duplicate entry '1' for key 'progress.resource_id'

测试存在则更新、不存在则插入

使用 MySQL 的 on duplicate key update 语句实现:

  1. mysql> insert into progress(resource_id, rate) VALUES (1, 100) on duplicate key update rate = 100;
  2. Query OK, 2 rows affected, 1 warning (0.00 sec)
  3. mysql> select * from progress;
  4. +-------------+-------------+--------+
  5. | progress_id | resource_id | rate |
  6. +-------------+-------------+--------+
  7. | 5 | 1 | 100.00 |
  8. +-------------+-------------+--------+
  9. 1 row in set (0.00 sec)