1. 程式人生 > >mysql replace into 的使用情況

mysql replace into 的使用情況

replace into的存在的幾種情況

  • 當表存在主鍵並且存在唯一鍵的時候
    • 如果只是主鍵衝突
複製程式碼
mysql> select * from auto;
+----+---+------+---------+
| id | k | v    | extra   |
+----+---+------+---------+
|  2 | 2 | 2    | extra 2 |
|  3 | 3 | 3    | extra 3 |
|  4 | 1 | 1-1  | NULL    |
+----+---+------+---------+
3 rows in set (0.00 sec)

mysql> 
mysql> show create table auto\G
*************************** 1. row ***************************
       Table: auto
Create Table: CREATE TABLE `auto` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `k` int(10) unsigned NOT NULL,
  `v` varchar(100) DEFAULT NULL,
  `extra` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
複製程式碼

這裡我們插入一條主鍵已經存在的4的資料

複製程式碼
mysql> replace into auto(id,k)values(4,5);
Query OK, 2 rows affected (0.01 sec)

mysql> select * from auto;
+----+---+------+---------+
| id | k | v    | extra   |
+----+---+------+---------+
|  2 | 2 | 2    | extra 2 |
|  3 | 3 | 3    | extra 3 |
|  4 | 5 | NULL | NULL    |
+----+---+------+---------+
3 rows in set (0.00 sec)

mysql> show create table auto \G
*************************** 1. row ***************************
       Table: auto
Create Table: CREATE TABLE `auto` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `k` int(10) unsigned NOT NULL,
  `v` varchar(100) DEFAULT NULL,
  `extra` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
複製程式碼

 發現,auto_increment並沒有+1,而是針對原來的那一條id=4的記錄進行了update,因為沒有指定其他列(v,extra)的值,所以,update的時候都使用了預設值.

  • 如果主鍵跟唯一鍵都衝突並且在同一行裡
複製程式碼
mysql> select * from auto;
+----+---+------+---------+
| id | k | v    | extra   |
+----+---+------+---------+
|  2 | 2 | 2    | extra 2 |
|  3 | 3 | 3    | extra 3 |
|  4 | 5 | NULL | NULL    |
|  5 | 6 | 6    | NULL    |
+----+---+------+---------+
4 rows in set (0.00 sec)

mysql> show create table auto \G
*************************** 1. row ***************************
       Table: auto
Create Table: CREATE TABLE `auto` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `k` int(10) unsigned NOT NULL,
  `v` varchar(100) DEFAULT NULL,
  `extra` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> 
mysql> 
mysql> replace into auto(id,k,extra)values(5,6,77);
Query OK, 2 rows affected (0.01 sec)

mysql> select * from auto;
+----+---+------+---------+
| id | k | v    | extra   |
+----+---+------+---------+
|  2 | 2 | 2    | extra 2 |
|  3 | 3 | 3    | extra 3 |
|  4 | 5 | NULL | NULL    |
|  5 | 6 | NULL | 77      |
+----+---+------+---------+
4 rows in set (0.00 sec)

mysql> show create table auto \G
*************************** 1. row ***************************
       Table: auto
Create Table: CREATE TABLE `auto` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `k` int(10) unsigned NOT NULL,
  `v` varchar(100) DEFAULT NULL,
  `extra` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
複製程式碼

我們發現,auto_increment也並沒有+1,而是針對原來的那一條id=6的記錄進行了update,因為沒有指定其他列(v)的值,所以,update的時候都v使用了預設值變成了null

  • 如果主鍵跟唯一鍵都衝突不在同一行,對應2條記錄呢

我們來看下:

複製程式碼
mysql> show create table auto \G
*************************** 1. row ***************************
       Table: auto
Create Table: CREATE TABLE `auto` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `k` int(10) unsigned NOT NULL,
  `v` varchar(100) DEFAULT NULL,
  `extra` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> select * from auto;
+----+---+------+---------+
| id | k | v    | extra   |
+----+---+------+---------+
|  2 | 2 | 2    | extra 2 |
|  3 | 3 | 3    | extra 3 |
|  4 | 5 | NULL | NULL    |
|  6 | 6 | 66   | NULL    |
+----+---+------+---------+
4 rows in set (0.00 sec)

mysql> replace into auto(id,k,v)values(6,2,88);
Query OK, 3 rows affected (0.03 sec)
複製程式碼

像上面的,主鍵id=6對應一條記錄,唯一索引k=2對應id=2的另外一條記錄,所以我們當前插入的記錄就會跟2行資料有衝突,我們replace into 看看會有什麼結果

複製程式碼
mysql> replace into auto(id,k,v)values(6,2,88);
Query OK, 3 rows affected (0.03 sec)

mysql> select * from auto;
+----+---+------+---------+
| id | k | v    | extra   |
+----+---+------+---------+
|  3 | 3 | 3    | extra 3 |
|  4 | 5 | NULL | NULL    |
|  6 | 2 | 88   | NULL    |
+----+---+------+---------+
3 rows in set (0.00 sec)

mysql> show create table auto \G
*************************** 1. row ***************************
       Table: auto
Create Table: CREATE TABLE `auto` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `k` int(10) unsigned NOT NULL,
  `v` varchar(100) DEFAULT NULL,
  `extra` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
複製程式碼

我們發現auto_increment並沒有+1,MySQL把原來的id=6的這條記錄上進行uppdate,但是發現唯一索引k出現了衝突,所以就把對應衝突的那條資料刪除,再進行更新,由於沒有指定更新欄位extra的資料,所以就把extra更新為預設資料

  • 如果僅僅是唯一鍵衝突呢?
複製程式碼
mysql> select * from auto;
+----+---+------+---------+
| id | k | v    | extra   |
+----+---+------+---------+
|  2 | 2 | 2    | extra 2 |
|  3 | 3 | 3    | extra 3 |
|  4 | 5 | NULL | NULL    |
|  5 | 6 | NULL | 77      |
+----+---+------+---------+
4 rows in set (0.00 sec)

mysql> show create table auto \G
*************************** 1. row ***************************
       Table: auto
Create Table: CREATE TABLE `auto` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `k` int(10) unsigned NOT NULL,
  `v` varchar(100) DEFAULT NULL,
  `extra` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> 
mysql> replace into auto(k,v)values(6,66);
Query OK, 2 rows affected (0.04 sec)

mysql> select * from auto;
+----+---+------+---------+
| id | k | v    | extra   |
+----+---+------+---------+
|  2 | 2 | 2    | extra 2 |
|  3 | 3 | 3    | extra 3 |
|  4 | 5 | NULL | NULL    |
|  6 | 6 | 66   | NULL    |
+----+---+------+---------+
4 rows in set (0.00 sec)

mysql> show create table auto \G
*************************** 1. row ***************************
       Table: auto
Create Table: CREATE TABLE `auto` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `k` int(10) unsigned NOT NULL,
  `v` varchar(100) DEFAULT NULL,
  `extra` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
複製程式碼

這時候,我們發現,,auto_increment已經+1了。MySQL這時候的執行步驟是,首先往表裡面插入一條資料,這時候auto_increment+1,但是在插入的時候發現唯一索引的k衝突了,然後把衝突的這條資料刪除,然後重新插入,對於沒有指定其他列(extra)的值,如extra都使用了預設值變成了null

現在我們可以下結論了:

  1. 當replace into 記錄只與主鍵衝突的時候,auto_increment不會增加,它會對與主鍵衝突的那一條記錄進行更新,沒有指定的列將會被更新為預設值
  2. 當replace into 記錄與主鍵跟唯一索引同時衝突的時候,auto_increment不會增加
    1. 如果衝突的主鍵和索引在同一行記錄,則replace into只做更新,對於沒有指定值的其他列,將會被更新為預設值,
    2. 如果衝突的主鍵和索引分別對應2行資料,則MySQL將會刪除唯一索引的那一行記錄,更新對應主鍵的那一行記錄。
  3. 當replace into 記錄只與唯一索引進行衝突的時候,auto_increment + 1,再對資料進行更新。
  • 最後我們可以對總結分析下,MySQL對replace into的操作是首先是insert操作,如果insert失敗,則對insert失敗的這條記錄進行update,如果update還是失敗,則會進行delete操作之後再update。
  • 具體流程是這樣的:insert記錄,發現主鍵衝突,則update這一行,update的時候發現存在唯一鍵衝突,則delete對應的唯一鍵的行後再進行update。如果insert成功,auto_increment自然+1了,然後對這條記錄進行update,update的時候發現存在唯一鍵衝突,則delete對應的唯一鍵的行後再進行update。