Tôi khuyên bạn nên sử dụng INSERT...ON DUPLICATE KEY UPDATE
.
Nếu bạn sử dụng INSERT IGNORE
, thì hàng sẽ không thực sự được chèn nếu nó dẫn đến một khóa trùng lặp. Nhưng câu lệnh sẽ không tạo ra lỗi. Thay vào đó, nó tạo ra một cảnh báo. Những trường hợp này bao gồm:
- Chèn một khóa trùng lặp vào các cột có
PRIMARY KEY
hoặcUNIQUE
hạn chế. - Chèn NULL vào cột có
NOT NULL
ràng buộc. - Chèn một hàng vào bảng được phân vùng, nhưng các giá trị bạn chèn không ánh xạ tới một phân vùng.
Nếu bạn sử dụng REPLACE
, MySQL thực sự thực hiện DELETE
theo sau là INSERT
bên trong, có một số tác dụng phụ không mong muốn:
- ID tăng tự động mới được cấp phát.
- Các hàng phụ thuộc có khóa ngoại có thể bị xóa (nếu bạn sử dụng khóa ngoại xếp tầng) hoặc ngăn
REPLACE
. - Kích hoạt kích hoạt trên
DELETE
được thực thi một cách không cần thiết. - Các tác dụng phụ cũng được truyền sang các bản sao.
sửa chữa: cả REPLACE
và INSERT...ON DUPLICATE KEY UPDATE
là những phát minh độc quyền, phi tiêu chuẩn dành riêng cho MySQL. ANSI SQL 2003 định nghĩa một MERGE
câu lệnh có thể giải quyết cùng một nhu cầu (và hơn thế nữa), nhưng MySQL không hỗ trợ MERGE
tuyên bố.
Một người dùng đã cố gắng chỉnh sửa bài đăng này (chỉnh sửa đã bị người kiểm duyệt từ chối). Chỉnh sửa đã cố gắng thêm một xác nhận quyền sở hữu rằng INSERT...ON DUPLICATE KEY UPDATE
khiến id tăng tự động mới được cấp phát. Đúng là id mới được tạo , nhưng nó không được sử dụng trong hàng đã thay đổi.
Xem phần trình diễn bên dưới, được thử nghiệm với Máy chủ Percona 5.5.28. Biến cấu hình innodb_autoinc_lock_mode=1
(mặc định):
mysql> create table foo (id serial primary key, u int, unique key (u));
mysql> insert into foo (u) values (10);
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 10 |
+----+------+
mysql> show create table foo\G
CREATE TABLE `foo` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`u` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u` (`u`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
mysql> insert into foo (u) values (10) on duplicate key update u = 20;
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 20 |
+----+------+
mysql> show create table foo\G
CREATE TABLE `foo` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`u` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u` (`u`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
Phần trên chứng tỏ rằng câu lệnh IODKU phát hiện bản sao và gọi bản cập nhật để thay đổi giá trị của u
. Lưu ý AUTO_INCREMENT=3
cho biết một id đã được tạo, nhưng không được sử dụng trong hàng.
Trong khi REPLACE
xóa hàng ban đầu và chèn một hàng mới, tạo ra và lưu trữ một id tăng tự động mới:
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 20 |
+----+------+
mysql> replace into foo (u) values (20);
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 3 | 20 |
+----+------+