|
|
|
PHP Generate ID อย่างไรไม่ให้ คีย์ซ้ำกัน โดยไม่ใช้ AUTO_INCREMENT ของ MySQL #2 ใช้ PHP Write/Read/LOCK_EX |
|
|
|
|
|
|
|
จากความเดิมตอนที่แล้ว ตามลิ้งนี้นะครับ
https://www.thaicreate.com/php/forum/126598.html
วันนี้เที่ยงๆ ว่างๆหน่อยเลยเอา อีกวิธีการ Generate KEY ID โดย PHP อย่างไรไม่ให้เกิดคีย์ซ้ำกัน
ความเดิมตอนที่แล้ว
วิธีการทำผมขอยกมานำเสนอ 2 วิธีได้แก่
1.) ใช้ semaphore ของ PHP ซึ่งจะมีตั้งแต่ PHP เวอร์ชั่น 4 ขึ้นไปครับ
2.) ใช้การเขียนไฟล์แบบ Exclusive คือ LOCK ไฟล์ให้เขียนเฉพาะ Thread ปัจจุบันให้เสร็จก่อนแล้วค่อยให้ Thread อื่นๆทำงาน โดยการจัด Queue (คิว) ลำดับก่อนหลัง (First in first out)
สำหรับวิธีที่ 2 นี้จะใช้ความสามารถของ การเขียน/อ่านไฟล์ ของ PHP ที่เราสามารถกำหนดได้ว่าจะให้ทำงานแบบ Exclusive ไหม หรือทำงานแบบ First In First Out (FIFO) หาก Thread ไหนเข้ามาทำงานก่อนก็จะต้องทำงานใน Thread ปัจจุบันให้เสร็จ แล้ว Thread อื่นๆก็เข้าคิวรอ จนกว่า Thread ปัจจุบันจะทำงานเสร็จ ซึ่งผมได้เขียนโค้ดเป็นตัวอย่างให้ ดังนี้ครับ
Code (PHP)
<?php
//---- Set ค่านี้เอาไว้สำหรับการเรียกใช้ Function date ของ PHP จะได้ไม่เกิด Warning
//---- ในกรณีที่ php.ini ไม่ได้ตั้งค่าเวลาของ Time zone เอาไว้
date_default_timezone_set('Asia/Bangkok');
/***
* Defined function สำหรับการสร้าง ID
* @Describe สำหรับการสร้าง ID เราจะทำการ LOCK_EX ไฟล์ที่กำลังทำงานอยู่เพื่อให้ Thread อื่นๆรอ
* จนกว่า Thread ปัจจุบันทำงานเสร็จก่อนแล้วค่อยให้ Thread ลำดับถัดไปเข้ามาทำงานได้
*
**/
function getId(){
//---- เปิดไฟล์ ด้วย Mode r+ คือ เปิดไฟล์สำหรับ อ่านและเขียน และชี้ Pointer ของไฟล์ไปยังตำแหน่งเริ่มต้น
$handle = fopen(dirname(__FILE__) . '/keyId.txt', 'r+');
$keyId = null;
if($handle){
//---- Exclusive lock file (First In First Out)
flock($handle, LOCK_EX);
fseek($handle, 0);
$curKeyId = trim(fread($handle, 1024));
$curKeyId = (strlen($curKeyId) === 0 ? 1 : intval($curKeyId));
//---- สร้าง ID โดยมีรูปแบบ ปี 2 หลักและเดือน 2 หลัก-เลข Running 7 หลัก ยกตัวอย่างเช่น 1703-0000001
$keyId = sprintf((date('ym') . '-%07d'), $curKeyId);
//---- เพิ่มคีย์ ID ไปทีล่ะ 1 และเขียนลงไฟล์เอาไว้เพื่อรอการสร้างลำดับต่อไป
$curKeyId++;
ftruncate($handle, 0);
fwrite($handle, $curKeyId);
//---- หลังจากเขียนไฟล์เสร็จแล้ว แนะนำให้เรียก fflush ด้วยเพื่อไม่ต้องรอจังหวะ OS เขียนข้อมูลจาก Memory ลงไฟล์จริงๆ
fflush($handle);
//---- ปลดล็อคการทำงานกับไฟล์ เพราะก่อนหน้าเรา Lock การเขียนไฟล์ไว้แบบ Exclusive
flock($handle, LOCK_UN);
fclose($handle);
}
return $keyId;
}
//---- ID ที่เราได้จากการ Generate เขียนลงไฟล์ (ทดสอบดูเฉยๆนะครับ)
//---- เพราะเขียนลงไฟล์ไว้ เพื่อที่จะใช้ AB (Apache Benchmart) ในการยิงทดสอบ เพื่อจำรองการทำงานเมื่อมี Concerrent จำนวนหนึ่งเข้ามา
//---- Script ที่เราเขียนสร้าง ID ไม่ช้ำกันจริง
$handle = fopen(dirname(__FILE__) . '/genId.txt', 'a');
fwrite($handle, getId() . "\n");
fclose($handle);
?>
จาก Script ด้านบน เรามาทำการทดสอบดูว่าสิ่งที่เราเขียนไปนั้นมัน Work จริงๆ เพื่อ Make sure ก่อนนำไปใช้งาน
สำหรับวิธีการทดสอบนั้น ผมจะแนะนำให้ใช้ AB (Apache Benchmart) ในการยิงทดสอบ
ในที่นี้จะพูดถึง OS Window
โดยก่อนอื่นหากเราลง Apache ที่เครื่องอยู่แล้วให้เข้าไปยังพาร์ท ที่เรา Install Apache แล้วเข้าไปยัง Folder bin
ใช้คำสั่งต่อนี้ไปนี้ในการยิงทดสอบ
ab -n 100 -c 100 localhost/testGenerateIdByFile.php
n คือ จำนวน Request ที่เราต้องการส่งเข้าไป ตัวอย่างนี้ใช้จำนวน 100 Request
c คือ จำนวน Concerrent หรือจำรองจำนวน ผู้ใช้งาน ต่อ 1 Request
หมายเหตุ: ค่า C จะต้องไม่มากกว่า ค่า N นะครับไม่งั้น AB จะฟ้อง Error
Tag : PHP, MySQL
|
|
|
|
|
|
Date :
2017-03-01 12:46:00 |
By :
takky12345 |
View :
2094 |
Reply :
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Date :
2017-03-01 15:40:41 |
By :
mr.win |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
สุดยอด
|
|
|
|
|
Date :
2017-04-11 17:06:15 |
By :
tkaj_krit |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Load balance : Server 05
|