Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Lặp lại cho đến khi mật mã là duy nhất

Nói một cách chính xác, việc kiểm tra tính duy nhất của bạn sẽ không đảm bảo tính duy nhất khi tải đồng thời. Vấn đề là bạn kiểm tra tính duy nhất trước (và riêng biệt với) nơi bạn chèn một hàng để "xác nhận" mật mã mới tạo của bạn. Một quá trình khác có thể làm điều tương tự, cùng một lúc. Đây là cách diễn ra ...

Hai quy trình tạo ra cùng một mật mã. Mỗi người bắt đầu bằng cách kiểm tra tính duy nhất. Vì cả hai quy trình đều chưa (chưa) chèn một hàng vào bảng, nên cả hai quy trình sẽ không tìm thấy mật mã phù hợp trong cơ sở dữ liệu và do đó, cả hai quy trình sẽ giả định rằng mã là duy nhất. Bây giờ, khi mỗi quy trình tiếp tục công việc của chúng, cuối cùng chúng sẽ cả hai chèn một hàng vào các tệp files bảng sử dụng mã đã tạo - và do đó bạn nhận được một bản sao.

Để giải quyết vấn đề này, bạn phải thực hiện kiểm tra và thực hiện chèn trong một thao tác "nguyên tử". Sau đây là giải thích về cách tiếp cận này:

Nếu bạn muốn mật mã là duy nhất, bạn nên xác định cột trong cơ sở dữ liệu của mình là UNIQUE . Điều này sẽ đảm bảo tính duy nhất (ngay cả khi mã php của bạn không) bằng cách từ chối chèn một hàng có thể gây ra mật mã trùng lặp.

CREATE TABLE files (
  id int(10) unsigned NOT NULL auto_increment PRIMARY KEY,
  filename varchar(255) NOT NULL,
  passcode varchar(64) NOT NULL UNIQUE,
)

Bây giờ, hãy sử dụng SHA1() của mysql và NOW() để tạo mật mã của bạn như là một phần của câu lệnh chèn. Kết hợp điều này với INSERT IGNORE ... ( tài liệu ), và lặp lại cho đến khi một hàng được chèn thành công:

do {
    $query = "INSERT IGNORE INTO files 
       (filename, passcode) values ('whatever', SHA1(NOW()))";
    $res = mysql_query($query);
} while( $res && (0 == mysql_affected_rows()) )

if( !$res ) {
   // an error occurred (eg. lost connection, insufficient permissions on table, etc)
   // no passcode was generated.  handle the error, and either abort or retry.
} else {
   // success, unique code was generated and inserted into db.
   // you can now do a select to retrieve the generated code (described below)
   // or you can proceed with the rest of your program logic.
}

Lưu ý: Ví dụ trên đã được chỉnh sửa để giải thích cho những quan sát tuyệt vời được đăng bởi @martinstoeckli trong phần nhận xét. Các thay đổi sau đã được thực hiện:

  • đã thay đổi mysql_num_rows() ( tài liệu ) thành mysql_affected_rows() ( tài liệu ) - num_rows không áp dụng cho các lần chèn. Đồng thời xóa đối số thành mysql_affected_rows() , vì hàm này hoạt động ở cấp độ kết nối chứ không phải cấp độ kết quả (và trong mọi trường hợp, kết quả của một lần chèn là boolean, không phải số tài nguyên).
  • đã thêm kiểm tra lỗi trong điều kiện vòng lặp và thêm kiểm tra lỗi / thành công sau khi thoát khỏi vòng lặp. Việc xử lý lỗi rất quan trọng, vì nếu không có nó, các lỗi cơ sở dữ liệu (như mất kết nối hoặc các vấn đề về quyền), sẽ khiến vòng lặp quay mãi mãi. Cách tiếp cận được hiển thị ở trên (sử dụng IGNOREmysql_affected_rows() và thử nghiệm $res riêng cho các lỗi) cho phép chúng tôi phân biệt các "lỗi cơ sở dữ liệu thực" này với vi phạm ràng buộc duy nhất (là một điều kiện không lỗi hoàn toàn hợp lệ trong phần logic này).

Nếu bạn cần lấy mật mã sau khi nó đã được tạo, chỉ cần chọn lại bản ghi:

$res = mysql_query("SELECT * FROM files WHERE id=LAST_INSERT_ID()");
$row = mysql_fetch_assoc($res);
$passcode = $row['passcode'];

Chỉnh sửa :đã thay đổi ví dụ trên để sử dụng hàm mysql LAST_INSERT_ID() , chứ không phải là chức năng của PHP. Đây là một cách hiệu quả hơn để thực hiện điều tương tự và mã kết quả là gọn gàng hơn, rõ ràng hơn và ít lộn xộn hơn.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm cách nào để chọn hàng dữ liệu đầu tiên và cuối cùng từ kết quả mysql?

  2. Đổi tên một cột trong MySQL

  3. T_ENCAPSED_AND_WHITESPACE không mong muốn, gặp lỗi T_STRING hoặc T_VARIABLE hoặc T_NUM_STRING

  4. Làm thế nào để tạo một chỉ mục duy nhất 'hai mặt' trên hai trường?

  5. MySQL chuyển đổi chuỗi ngày thành dấu thời gian Unix