Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Ulangi hingga kode sandi unik

Sebenarnya, pengujian Anda untuk keunikan tidak akan menjamin keunikan di bawah beban bersamaan. Masalahnya adalah Anda memeriksa keunikan sebelum (dan terpisah dari) tempat Anda menyisipkan baris untuk "mengklaim" kode sandi yang baru dibuat. Proses lain dapat melakukan hal yang sama, pada waktu yang sama. Begini caranya...

Dua proses menghasilkan kode sandi yang sama persis. Mereka masing-masing mulai dengan memeriksa keunikan. Karena tidak ada proses yang (belum) menyisipkan baris ke tabel, kedua proses tidak akan menemukan kode sandi yang cocok dalam database, sehingga kedua proses akan menganggap bahwa kode tersebut unik. Sekarang saat proses masing-masing melanjutkan pekerjaan mereka, pada akhirnya mereka akan berdua menyisipkan baris ke files tabel menggunakan kode yang dihasilkan -- dan dengan demikian Anda mendapatkan duplikat.

Untuk menyiasatinya, Anda harus melakukan pemeriksaan, dan melakukan penyisipan dalam satu operasi "atom". Berikut adalah penjelasan dari pendekatan ini:

Jika Anda ingin kode sandi unik, Anda harus mendefinisikan kolom di database Anda sebagai UNIQUE . Ini akan memastikan keunikan (bahkan jika kode php Anda tidak) dengan menolak untuk menyisipkan baris yang akan menyebabkan duplikat kode sandi.

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

Sekarang, gunakan SHA1() mysql dan NOW() untuk membuat kode sandi Anda sebagai bagian dari pernyataan sisipan. Gabungkan ini dengan INSERT IGNORE ... (dokumen ), dan ulangi hingga baris berhasil dimasukkan:

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.
}

Catatan: Contoh di atas telah diedit untuk memperhitungkan pengamatan luar biasa yang diposting oleh @martinstoeckli di bagian komentar. Perubahan berikut telah dibuat:

  • mengubah mysql_num_rows() (dokumen ) ke mysql_affected_rows() (dokumen ) -- num_rows tidak berlaku untuk sisipan. Juga menghapus argumen ke mysql_affected_rows() , karena fungsi ini beroperasi pada tingkat koneksi, bukan tingkat hasil (dan bagaimanapun juga, hasil penyisipan adalah boolean, bukan nomor sumber daya).
  • menambahkan pengecekan error dalam kondisi loop, dan menambahkan tes untuk error/sukses setelah loop keluar. Penanganan kesalahan itu penting, karena tanpanya, kesalahan basis data (seperti koneksi yang hilang, atau masalah izin), akan menyebabkan loop berputar selamanya. Pendekatan yang ditunjukkan di atas (menggunakan IGNORE , dan mysql_affected_rows() , dan menguji $res secara terpisah untuk kesalahan) memungkinkan kami untuk membedakan "kesalahan basis data nyata" ini dari pelanggaran batasan unik (yang merupakan kondisi non-kesalahan yang sepenuhnya valid di bagian logika ini).

Jika Anda perlu mendapatkan kode sandi setelah dibuat, cukup pilih catatan lagi:

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

Sunting :mengubah contoh di atas untuk menggunakan fungsi mysql LAST_INSERT_ID() , daripada fungsi PHP. Ini adalah cara yang lebih efisien untuk mencapai hal yang sama, dan kode yang dihasilkan lebih bersih, lebih jelas, dan tidak berantakan.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana cara menegakkan batasan kunci asing dari tabel yang tidak terkait di Mysql?

  2. tempatkan beberapa hasil dalam satu larik

  3. Cara Memperbarui Banyak Kolom di MySQL

  4. Tampilkan tabel dengan LIKE dan NOT REGEXP

  5. PDO dengan INSERT INTO melalui pernyataan yang disiapkan