Hàm LAST_INSERT_ID () của MySql có được đảm bảo là chính xác không?


36

Khi tôi thực hiện một hàng duy nhất INSERTcho một bảng có một AUTO_INCREMENTcột tôi muốn sử dụng LAST_INSERT_ID()hàm để trả về AUTO_INCREMENTgiá trị ed mới được lưu trữ cho hàng đó.

Vì nhiều nhà phát triển và quản trị viên Microsoft SQL Server chắc chắn nhận thức được chức năng tương đương trong SQL Server ( SCOPE_IDENTITY@@IDENTITY) không có vấn đề gì .

Tôi biết trạng thái tài liệu MySQL:

ID được tạo được duy trì trong máy chủ trên cơ sở mỗi kết nối . Điều này có nghĩa là giá trị được hàm trả về cho một máy khách nhất định là AUTO_INCREMENTgiá trị đầu tiên được tạo cho câu lệnh gần đây nhất ảnh hưởng đến một AUTO_INCREMENTcột bởi máy khách đó . Giá trị này không thể bị ảnh hưởng bởi các khách hàng khác, ngay cả khi họ tạo ra AUTO_INCREMENTcác giá trị của riêng họ. Hành vi này đảm bảo rằng mỗi khách hàng có thể truy xuất ID riêng của mình mà không cần quan tâm đến hoạt động của các khách hàng khác và không cần khóa hoặc giao dịch.

(nguồn)

và thậm chí đi xa để nói:

Sử dụng LAST_INSERT_ID()AUTO_INCREMENTcột đồng thời từ nhiều khách hàng là hoàn toàn hợp lệ.

(nguồn)

Có bất kỳ rủi ro hoặc kịch bản đã biết nào có thể khiến LAST_INSERT_ID()không trả lại giá trị chính xác không?

Tôi đang sử dụng MySQL 5.5 trên CentOS 5.5 x64 và Fedora 16 x64 và công cụ InnoDB.

Câu trả lời:


35

Một vài lưu ý tôi muốn chỉ ra khi sử dụng LAST_INSERT_ID:

  1. Tôi biết bạn đã đề cập đến chèn một hàng. Nhưng khi thực hiện chèn nhiều hàng, LAST_INSERT_ID()sẽ trả về giá trị của hàng đầu tiên được chèn (không phải cuối cùng).

  2. Nếu chèn thất bại, LAST_INSERT_ID()sẽ không được xác định. Điều tương tự cũng đúng đối với các giao dịch tự động quay lại (do lỗi).

  3. Nếu bạn thực hiện chèn vào một giao dịch thành công và bạn vẫn phát hành một ROLLBACK, LAST_INSERT_ID()sẽ bị bỏ lại như trước khi quay lại.

  4. một vài cảnh báo khi sử dụng AUTO_INCREMENTLAST_INSERT_IDsao chép dựa trên câu lệnh. Việc đầu tiên khi được sử dụng trong một kích hoạt hoặc chức năng. Thứ hai là kịch bản ít phổ biến hơn trong đó cột auto_increment của bạn là một phần của khóa chính tổng hợp và không phải là cột đầu tiên trong khóa.


7

Để mở rộng hơn nữa về điểm số 2 trong câu trả lời do DTest đưa ra:

Trên các phiên bản của MySQL mà tôi đã sử dụng, đó là một ý tưởng tốt để explicity thiết lập lại giá trị của LAST_INSERT_ID trước mỗi khối mã nơi bạn có kế hoạch để thực hiện một chèn.

Điều này có thể được thực hiện như vậy:

-- initialize the LAST_INSERT_ID to some flag value:
SELECT LAST_INSERT_ID( some_flag_init_value_of_your_choice );
-- perform the insert  
INSERT INTO ttt (ccc) VALUES (vvv);
-- retrieve the id of the inserted row:  
SELECT LAST_INSERT_ID();

Sau khi chuỗi câu lệnh trên được thực thi, bạn sẽ biết liệu phần chèn có ảnh hưởng gì hay không bằng cách kiểm tra xem LAST_INSERT_ID có được đặt thành "some_flag_init_value_of_your_choice" khi kết thúc thực hiện hay không.

Nếu không, bạn có thể kết thúc với tình huống có vấn đề sau:

INSERT INTO ttt ( ccc ) VALUES ( 'a' );    -- assume this succeeds.
SELECT LAST_INSERT_ID();                   -- this will return the unique id of the new row with value 'a'.
INSERT INTO ttt ( ccc ) VALUES ( 'b' );    -- assume this FAILS.
SELECT LAST_INSERT_ID();                   -- this will STILL RETURN the unique id of the row with 'a'.

Vì lần chèn thứ hai không thành công , bạn có thể đã mong đợi rằng cuộc gọi thứ hai đến LAST_INSERT_ID sẽ trả về NULL hoặc nó sẽ tạo ra một tập kết quả trống (hàng không). Việc nó vẫn trả về một định danh số nguyên hợp lệ có thể khiến bạn lầm tưởng rằng lần chèn thứ hai THÀNH CÔNG khi không.

Mọi thứ trở nên NGAY LẬP TỨC khi bạn xem xét rằng LAST_INSERT_ID sẽ tiếp tục duy trì và lặp lại id duy nhất thành công cuối cùng ngay cả khi các câu lệnh chèn thất bại tiếp theo đang nhắm mục tiêu các bảng khác với bảng tạo ra id duy nhất thành công cuối cùng. Nói cách khác, bạn chèn vào bảng TA và nhận id là 5, sau đó bạn chèn vào TB (nhưng không thành công), nhưng bạn vẫn thấy 5. Dựa vào đó, bạn nghĩ rằng bạn vừa tạo một hàng mới trong TA với id là 5 một hàng mới trong TB với id là 5, trong khi thực tế không tồn tại bất kỳ hàng nào trong TB với id 5, hoặc tồn tại một hàng như vậy nhưng thực tế nó không liên quan gì đến bất kỳ mã nào bạn chỉ chạy.


2
Ở nơi đầu tiên, bạn không nên sử dụng sự tồn tại của last_insert_id()phán đoán nếu một truy vấn đã thành công. Rốt cuộc, đó là Id được chèn cuối cùng, giữ các giá trị bạn cần khi bạn đã biết mình đã thành công.
Pacerier
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.