رویدادها در MySQL
بسم
الله الرحمن الرحیم
رویدادهای MySQL در
نسخه 5.1.6 به
MySQL اضافه
شدن و راه دیگری رو برای کارهای زمانبندی
شده و یا Cron Job پیشنهاد
می دن. از
رویداد ها می شه برای پشتیبان گیری، حذف
رکوردهای قدیمی و به درد نخور، جمع آوری
اطلاعات برای گزارشدهی و … استفاده
کرد. برخلاف
trigger های
استاندارد که در شرایط خاص ای که تعیین
می شن، اجرا می شن، یک رویداد چیزیه که
باگذشت زمان اجرا می شن و گاهی اوقات هم
بهشون به عنوان trigger های
زمانی (Temporal Trigger) اشاره
می شه. رویداد
ها رو می شه طوری زمانبندی کرد که یا
یکبار اجرا بشن و یا طی زمان های مشخصی
چندین بار در همان مواقع اجرا کنید.
در
این مقاله مواردی که برای شروع کار با
رویدادها نیاز دارید، بهتون توضیح داده
خواهد شد. مثل
راهاندازی زمانبند رویداد (event
scheduler)، افزودن
رویداد ها که یکبار و یا چندین بار اجرا
بشن، مشاهده رویدادهای موجود و نیز ویرایش
رویدادها.
همینطور
مثالی رو درباره نحوه استفاده از رویدادهای
MySQL برای
ایجاد بلاگ که دارای پست های زمانبندی
شده هست رو هم به صورت عملی بررسی خواهیم
کرد.
راهاندازی
زمانبند رویداد (Event Scheduler)
زمانبند
رویداد MySQL پروسه
ایه که پشت صحنه اجرا می شه و مدام دنبال
رویدادها برای اجرا هست. قبل
از اینکه بتونید رویدادی رو زمانبندی و
یا ایجاد کنید، نیاز دارید که زمانبند
رویداد رو فعال کنید که برای این کار می
تونیم از دستور زیر استفاده کنیم:
mysql> SET GLOBAL
event_scheduler = ON;
همینطور،
برای غیرفعال کردن همه رویدادها می
تونیم از دستور زیر استفاده کنیم:
mysql> SET GLOBAL
event_scheduler = OFF;
پس
از فعالسازی زمانبند رویداد MySQL،
وضعیتشو در لیست پروسههای MySQL
می تونیم با استفاده
از دستور SHOW PROCESSLIST ببینیم:
mysql> SHOW PROCESSLIST\G
...
Id : 37
User :
event_scheduler
Host : localhost
db : NULL
Command : Daemon
Time : 5
State : Waiting on
empty queue
Info : NULL
کار
با رویدادها
نکته
مهمی که برای کار با رویدادها باید توجه
کنید اینه که رویدادی که ایجاد می شه فقط
می تونه عملیاتی رو اجرا کنه که کاربر
MySQL ای که
اون رویداد رو ایجاد کرده و مجاز به انجام
هر عملیاتی که باشه اون رویداد هم به
همونها محدود خواهد بود. و
همچنین محدودیتهای دیگه ای که شامل
رویدادها می شن به شرح زیر هست:
- اسامی رویدادها محدود به 64 کارارکتر هستن.
- از نسخه MySQL 5.1.8 ، اسامی رویدادها حساسیت به حروف بزرگ و کوچیک ندارند. همینطور هر رویدادی باید اسم یکتایی داشته باشه بدون در نظر گرفتن بزرگی یا کوچکی بودن اسم رویداد.
- رویدادها توسط رویدادهای دیگه نمی تونن ایجاد، ویرایش و یا حذف بشن.
- هنگام تعیین رویداد زمانی، نمی تونید به تابع های ذخیره شده و توابع تعریف شده توسط کاربر رفرنس ای داشته باشید.
ایجاد
رویدادها
دستور
زیر رویدادی به است myevent رو
برای ما ایجاد می کنه:
DELIMITER |
CREATE EVENT myevent
ON SCHEDULE AT
CURRENT_TIMESTAMP + INTERVAL 1 HOUR
DO
BEGIN
UPDATE mytable SET
mycol = mycol + 1;
END |
DELIMITER ;
این
رویداد فقط برای یکبار و یک ساعت پس از
زمانی که ایجاد شده اجرا خواهد شد.
کوئری یا کوئری های
مورد نظر بین دستورات BEGIN و
END قرار می
گیرن و در زمان مشخص شده اجرا خواهند شد.
نکتهای
که در این تکه کد هست اینه که بدون استفاده
از delimiter های
ابتدایی و پایانی و همینطور بدون استفاده
از کلمات BEGIN و
END هم میشد
رویداد رو ایجاد کرد که در اینصورت کدمون
به شکل زیرتغییر می کرد.
اما
دلیلی که باعث شده این موارد رو به کدمون
اضافه کنیم اینه که در صورتی که بخواهیم
چندین کوئری رو اجرا کنیم در اینصورت باید
از BEGIN و
END استفاده
کرده و کوئری هامون رو در بینشون قرار
بدیم و در حقیقت در صورتی که بخواهیم فقط
یک کوئری اجرا بشه قرار دادن این موارد
که در کد فوق هم قرار داده شده بیمعنی
هست.
اما
مشکلی ای که وجود داره اینه که ما در کوئری
مون نیاز داریم که سمیکولن (;)
رو در انتها برای
نشون دادن اتمام کوئری، نیاز هست که قرار
بدیم و در برنامههای کلایت که برای کار
با mysql هست
این موضوع اینگونه برداشت خواهد شد که
پایان کدمون هست و دستورات اجرا می شن و
در حالی که اینطور نیست و ممکنه چند کوئری
داشته باشیم که باعث می شه همون اولی اجرا
بشه و برای حل این مشکل از delimiter
که در کد اولمون هم
ازش استفاده شده، می تونیم استفاده کنیم.
که
برای تعیین delimiter می
تونیم از همین کلمه در ابتدای کدمون
استفاده کنیم و سپس اسمی رو براش در نظر
میگیریم که در مثال فوق کاراکتر پایپ (
| ) تعیین شده و پس
از دستور END اسم
مورد نظر رو تکرار کرده و در پایان کدمون
رو هم با delimiter و
سمیکولن ( ; ) می
بندیم.
ولی
همونطور که گفته شد، در صورتی که فقط یک
کوئری برای اجرا دارید از کد مشابهی مثل
زیر استفاده کنید بهتر خواهد بود:
CREATE EVENT myevent
ON SCHEDULE AT
CURRENT_TIMESTAMP + INTERVAL 1 HOUR
DO UPDATE mytable SET
mycol = mycol + 1;
برای
مشاهده لیستی از رویدادهای موجود می تونیم
از دستور SHOW EVENTS استفاده
کنیم:
mysql> SHOW EVENTS\G
***************************
1. row ***************************
Db
: mysql
Name
: myevent
Definer
: root@localhost
Time zone
: SYSTEM
Type
: ONE TIME
Execute at
: 2012-08-09 06:34:22
Interval value
: NULL
Interval field
: NULL
Starts
: NULL
Ends
: NULL
Status
: ENABLED
Originator
: 0
character_set_client :
utf8
collation_connection :
utf8_general_ci
Database Collation :
latin1_swedish_ci
1 row in set (0.01 sec)
بعد
از اینکه رویدادی منقضی میشه، به طور
اتوماتیک رویداد مربوطه حذف می شه، مگر
اینکه بطور صریح اعلام کرده باشید که حذف
نشه و برای این منظور می شه از دستور ON
COMPLITION استفاده کرد.
به مثال زیر دقت
کنید:
CREATE EVENT myevent
ON SCHEDULE AT
CURRENT_TIMESTAMP + INTERVAL 1 HOUR
ON COMPLETION PRESERVE
DO UPDATE mytable SET
mycol = mycol + 1;
در
این مثال، حتی با وجودیکه رویداد منقضی
میشه ولی رویداد حذف نخواهد شد و در
دیتابیس نگهداری می شه که این اجازه رو
به ما می ده که بعداً بتونیم ویرایشش کنیم
که دوباره رویداد رو اجرا کنیم و یا مثلاً
دوست داشته باشیم به عنوان مرجع نگهش
داریم.
برای
حذف دائمی رویداد، بطور دستی می شه از
دستور DROP EVENT استفاده
کرد:
DROP EVENT myevent;
برای
تعیین اینکه رویدادی چندین بار بطور
پشتسرهم اجرا بشه می تونیم از EVERY
استفاده کنیم:
CREATE EVENT myevent
ON SCHEDULE EVERY 1 HOUR
DO UPDATE mytable SET
mycol = mycol + 1;
و
همینطور بجای اینکه رویدادی داشته باشیم
که بجای اینکه یکبار و یا همیشه اجرا بشه،
می تونیم رویدادی داشته باشیم که چندین
بار ولی در طی یک مدت زمان مشخصی اجرا بشه
و برای این کار می تونیم از دستورات START
و END استفاده
کنیم:
CREATE EVENT myevent
ON SCHEDULE EVERY 1 HOUR
STARTS CURRENT_TIMESTAMP
+ INTERVAL 1 DAY
ENDS CURRENT_TIMESTAMP +
INTERVAL 1 YEAR
DO UPDATE mytable SET
mycol = mycol + 1;CREATE EVENT myevent
ON SCHEDULE EVERY 1 HOUR
STARTS CURRENT_TIMESTAMP
+ INTERVAL 1 DAY
ENDS CURRENT_TIMESTAMP +
INTERVAL 1 YEAR
DO UPDATE mytable SET
mycol = mycol + 1;
در
این مثال، رویداد از فردا شروع شده و تا
پایان ۱ سال، بطور مدارم هر ساعت یکبار
اجرا خواهد شد.
همینطور
برای تعیین زمان می شه از دستورات YEAR,
MONTH, WEEK, DAY, HOUR, MINUTE , SECOND و
… استفاده کرد.
آپدیت
رویدادها
در
صورتی که تمایل به تغییر رفتار رویدادی
دارید، بجای حذف و ایجاد مجدد رویداد، می
شه رفتار رویداد رو توسط دستور ALTER
EVENT تغییر داد.
به عنوان مثال،
برای تغییر زمان رویداد قبلی که هر ماه
اجرا بشه و همینطور زمانی در آینده در
ساعت ۱ صبح اجرا بشه، می تونیم از دستور
زیر واسه این کار استفاده کرد:
ALTER EVENT myevent
ON SCHEDULE EVERY 1
MONTH
STARTS '2011-12-01
01:00:00';
برای
تغییر رویداد که کوئری های دیگه ای رو
اجرا کنه:
delimiter |
ALTER EVENT myevent
DO
BEGIN
INSERT INTO mystats
(total)
SELECT COUNT(*)
FROM sessions;
TRUNCATE sessions;
END |
delimiter;
و
برای تغییر نام رویداد می شه از دستور
RENAME برای
این کار استفاده کرد:
ALTER EVENT myevent
RENAME TO yourevent;
ارسال
مطالب بلاگ بصورت زمانبدی شده
مثال
عملی که می شه از رویداد ها درش استفاده
کرد، اینه که فرض کنید بلاگی دارید و
میخواهید که مطالب زمانبندی شده درش
ارسال کنید و این مطالب در زمان مشخص شده
در آینده تو بلاگ منتشر بشن. یه
راهش اینکه که در جدول مربوطه تو دیتابیس
دو ستون یکی برای زمان انتشار و یکی هم چک
باکسی باشه که نمایش داده شدن یا نشدن
مطلب رو تعیین کنه، که از اونور هم اسکریپتی
رو هر ۱ دقیقه یک بار توسط Crontab/cronJob
اجرا کنیم و در
صورتی که زمان حال با زمان ای که تعیین
شده برابر یا بزرگتر بود، در اینصورت تیک
منتشر کردن مطلب رو در دیتابیس بزنیم، که
متأسفانه راه موثری به نظر نمی رسه.
راه دیگه که می شه
به این هدف رسید، استفاده از رویدادهای
MySQL هست
که در زمان تعیین شده اجرا و مطلب مربوطه
رو منتشر می کنه.
فرم
ارسال مطلب بلاگ می تونه چک باکسی داشته
باشه به این منظور که آیا پست باید در
زمانی در آینده منتشر بشه یا خیر و کادر
دیگری هم برای وارد کردن زمان و تاریخی
که مطلب بایستی منتشر بشه. اسکریپتی
هم که محتوای پست شده رو دریافت می کنه
مسئول رسیدگی به ثبت اطلاعات تو دیتابیس
هست به همراه اینکه اگه مطلب قراره زمانی
در آینده منتظر بشه، رویدادی برای کار
مورد نظر ما ایجاد کنه. کد
مربوط به این کار، چیزی مثل این می تونه
باشه:
<?php
// establish database
connection and filter incoming data
// ...
// insert blog post with
pending status, get id assigned to post
$query = "INSERT INTO
blog_posts (id, title, post_text, status)
VALUES (NULL, :title,
:postText, 'pending')";
$stm = $db->prepare($query);
$stm->execute(array(":title"
=> $title, ":postText" => $text));
$id = $db->lastInsertId();
// is this a future post?
if
(isset($_POST["schedule"], $_POST["time"])) {
$scheduleDate =
strtotime($_POST["time"]);
$query = "CREATE
EVENT publish_:id
ON SCHEDULE AT
FROM_UNIXTIME(:scheduleDate)
DO
BEGIN
UPDATE blog_posts
SET status = 'published' WHERE id = :id;
END";
$stm =
$db->prepare($query);
$stm->execute(array(":id" => $id, ":scheduleDate"
=> $scheduleDate));
}
// this is not a future
post, publish now
else {
$query = "UPDATE
blog_posts SET status = 'published' WHERE id = :id";
$stm =
$db->prepare($query);
$stm->execute(array(":id" => $id));
}
وقتی
مطلب تو دیتابیس ذخیره می شه، مطلب به
عنوان وضعیت «در
انتظار» خواهد
بود. این
به ما این امکان رو می ده که اگه پست قراره
در آینده منتشر بشه، از طریق رویدادها
بشه این کارو انجام داد، در غیراینصورت
اگه قراره فوراً مطلب منتشر بشه که همون
لحظه وضعیت مطلب رو تغییر می دیم و مطلب
هم منتشر می شه.
و
اگه قرار بود مطلب رو بعداً ویرایش کنید،
می تونید رویداد رو توسط دستور DROP
EVENT IF EXISTS حذف و با
زمان مناسب دوباره رویدادی رو برای این
منظور ایجاد کنید.
کلام
آخر :-)
حال بایستی درک
بهتری از اینکه رویدادها تو MySQL
چیکار می کنن، داشته
باشید. و
همچنین نحوه ایجاد رویدادها و مدیریتشون
رو. از
اونجایی که رویدادها جایگزینی برای
crontab/cronjob و
یا عملیاتی که زمانبندی شده می باشن،
نیستن، چرا که رویدادها نمی تونن کدهای
خارجی مثل کدهای php رو
اجرا کنن، اما جایگزین مناسبی برای عملیاتی
که وابسته به زمان هستن که مربوط به دیتابیس
MySQL می شن،
می تونن باشن.
نکته پایانی هم
اینکه تو سایت خود mysql (لینک
های منبع) اطلاعات
کاملتری راجع به رویداد ها هست که در صورتی
که مایل هستید با رویداد ها کار کنید و یا
اطلاعات بیشتری ازشون داشته باشید، توصیه
می شه حتماً یه نگاهی بهشون بندازین.
:)