2010-05-07 34 views
32

Một đồng nghiệp vừa mới làm cho tôi biết về một hành vi MySQL rất lạ.Tại sao tăng tự động MySQL tăng lên khi chèn không thành công?

Giả sử bạn có một bảng có trường auto_increment và một trường khác được đặt thành duy nhất (ví dụ: trường tên người dùng). Khi cố gắng chèn một hàng với một tên người dùng đã có trong bảng chèn không thành công, như mong đợi. Tuy nhiên, giá trị auto_increment được tăng lên khi bạn có thể nhìn thấy khi bạn chèn một mục nhập mới hợp lệ sau một vài lần thử không thành công.

Ví dụ, khi mục cuối cùng của chúng tôi trông như thế này ...

ID: 10 
Username: myname 

... và chúng tôi cố gắng năm mục mới với giá trị cùng tên người dùng trên chèn tiếp theo của chúng tôi, chúng tôi sẽ đã tạo ra một dòng mới như vậy:

ID: 16 
Username: mynewname 

trong khi đây không phải là một vấn đề lớn trong bản thân nó có vẻ như một vector tấn công rất ngớ ngẩn để giết một bảng vì lũ lụt nó với yêu cầu chèn thất bại, như MySQL Reference Manual bang:

"Hành vi của cơ chế tăng tự động không được xác định nếu [...] giá trị lớn hơn số nguyên tối đa có thể được lưu trữ trong loại số nguyên được chỉ định."

Hành vi này có được mong đợi không?

+6

vector tấn công của bạn dường như là một vấn đề không. Nếu bạn có thể tràn ngập nó với các yêu cầu chèn không thành công, bạn có thể không đồng thời làm ngập nó với các yêu cầu không thành công không? –

+0

bạn có thể tạo mã ** sao chép thay vì giải thích thủ công không? –

+4

@martin smith: Trong khi đó là sự thật tôi nghĩ rằng một sự đột biến đột ngột của người dùng mới sẽ rõ ràng hơn một sự gia tăng im lặng trong auto_increment mà có thể rất tốt rơi bên lề nếu không được kiểm tra. – Sorcy

Trả lời

23

InnoDB là một công cụ giao dịch.

Điều này có nghĩa rằng trong các tình huống sau:

  1. Session A chèn kỷ lục 1
  2. Session B chèn kỷ lục 2
  3. Session A cuộn lại

, thì hoặc là một khả năng của một khoảng cách hoặc session B sẽ khóa cho đến session A đã cam kết hoặc quay trở lại.

InnoDB nhà thiết kế (như hầu hết các nhà thiết kế động cơ giao dịch khác) đã chọn để cho phép những khoảng trống.

Từ documentation:

Khi truy cập vào bộ đếm tự động tăng, InnoDB sử dụng một bảng cấp đặc biệt khóa AUTO-INC rằng nó giữ đến cuối báo cáo kết quả hiện tại SQL, chưa kết thúc giao dịch . Chiến lược khóa phát hành đặc biệt được giới thiệu để cải thiện đồng thời cho chèn vào một bảng có chứa một AUTO_INCREMENT cột

...

InnoDB sử dụng trong bộ nhớ tự động tăng truy cập miễn là chạy máy chủ. Khi máy chủ dừng lại và khởi động lại, InnoDB khởi tạo lại bộ đếm cho mỗi bảng cho số INSERT đầu tiên vào bảng, như được mô tả trước đó.

Nếu bạn sợ cột id quấn quanh, hãy làm cho nó BIGINT (dài 8 byte).

+1

Câu trả lời của bạn đã giúp tôi giải quyết vấn đề của chính mình. Cảm ơn bạn. có cách nào để vượt qua hành vi này của InnoDB liên quan đến autoincrement? – Aufwind

+0

cùng câu hỏi với tên Aufwind. –

+1

@Ankit: vui lòng đăng câu hỏi đó dưới dạng một câu hỏi khác và đặt liên kết tại đây. – Quassnoi

4

Nếu không biết chính xác nội bộ, tôi sẽ nói có, tự động tăng NÊN cho phép bỏ qua các giá trị làm lỗi chèn. Cho phép nói rằng bạn đang làm một giao dịch ngân hàng, hoặc nơi mà toàn bộ giao dịch và nhiều hồ sơ đi như một tất cả hoặc không có gì. Nếu bạn thử chèn của bạn, nhận được một ID, sau đó đóng dấu tất cả các chi tiết tiếp theo với ID giao dịch đó và chèn các bản ghi chi tiết, bạn cần phải đảm bảo tính độc đáo đủ điều kiện của bạn. Nếu bạn có nhiều người đóng sầm cơ sở dữ liệu, họ cũng sẽ cần phải đảm bảo họ nhận được ID giao dịch của chính họ để không xung đột với bạn khi giao dịch của họ được cam kết. Nếu một cái gì đó thất bại trên giao dịch đầu tiên, không có hại gì được thực hiện, và không có yếu tố lơ lửng ở hạ lưu.

+0

việc sử dụng tính năng skkiping này của tăng tự động nhưng tôi muốn biết đây có phải là cách để chặn skkiping này –

+2

@Ankit, không, bạn không thể dừng bỏ qua. Tiêu đề tệp theo dõi ID cuối cùng được gán luôn là số gia số. Nếu có sự cố và 10 người đang tham gia giao dịch và 3 lần hủy, bạn sẽ không bao giờ muốn chèn lấp giao dịch bị hủy bỏ như vậy chỉ để sử dụng ID. – DRapp

+0

thanx để thanh toán bù trừ dout –

-1

Tôi biết rằng đây là một bài viết cũ nhưng vì tôi cũng không thể tìm thấy câu trả lời đúng, tôi thực sự đã tìm ra cách để làm điều này. Bạn phải bọc truy vấn của mình trong câu lệnh if. Nó thường chèn truy vấn hoặc chèn và trên querys trùng lặp mess lên tổ chức auto increment trật tự như vậy cho chèn thường xuyên sử dụng:

và thay vì CHÈN VÀ ON DUPLICATE sử dụng một UPDATE SET ĐÂU QUERY trong hoặc bên ngoài một câu lệnh if không quan trọng và một REPLACE vÀO QUERY cũng dường như để làm việc

+2

Tôi đang downvoting câu trả lời này vì nó không áp dụng được. Có, bạn có thể kiểm tra xem bản ghi có tồn tại hay không trước khi thử chèn, nhưng điều đó hoàn toàn nằm bên cạnh điểm. – Mave

Các vấn đề liên quan