Đôi khi thao tác với cơ sở dữ liệu, chúng ta cần phải thực hiện 1 số thao tác định sẵn mỗi khi dữ liệu trong 1 bảng thay đổi. Trong MySQL Server, Microsoft SQL Server hiện nay có hỗ trợ Trigger, một phương thức được dựng sẵn được tự động thực thi khi một sự kiện được xảy ra.
MySQL Pham Minh Tri 2017-06-09 23:40:51

Giới thiệu

Trigger là một phương thức được lưu trữ sẵn, nó tự động thực thi khi một sự kiện nào đó xảy ra. Các sự kiện đó có thể là một trong các sự kiện sau:

  • 1 câu lệnh thao tác dữ liệu (DELETE, INSERT, hoặc UPDATE).
  • 1 câu lệnh định nghĩa dữ liệu (CREATE, ALTER, hoặc DROP).
  • 1 hoạt động dữ liệu (SERVERERROR, LOGON, LOGOFF, STARTUP, hoặc SHUTDOWN).

Tiền đề bài viết

Hãy mở đầu cho bài viết này bằng các vấn đề thực tế từ 1 trang web chia sẻ các bài viết về công nghệ, cho phép người dùng tạo và chia sẻ bài viết của họ như sau:

  • Khi người dùng đăng 1 bài viết, chúng ta tạo 1 record mới trong bảng articles, nhưng đồng thời cần phải đưa id của bài viết mới này vào bảng articles_preview để chờ các admin kiểm tra nội dung của bài viết trước khi đăng lên trang chủ.
  • Chúng ta cần phải quản lý thời điểm mà người dùng tạo bài viết hoặc lần cập nhật bài viết gần nhất của họ. Như vậy, mỗi record trong bảng articles cần có thêm các trường là created_at updated_at để lưu trữ thời điểm mà người dùng tạo bài viết hay cập nhật bài viết. Đồng thời giá trị của các trường này cần được tự động thay đổi mỗi khi người dùng thực hiện các thao tác tạo mới và cập nhật.

Nhìn chung, các vấn đề trên xuất phát từ việc chúng ta cần phải thực hiện 1 số thao tác định sẵn mỗi khi dữ liệu trong 1 bảng thay đổi. Các thao tác này có thể được thực hiện bằng tay với 1 tần suất liên tục trong 1 khoảng thời gian dài, và làm hao tốn công sức cũng như tài nguyên hệ thống cũng như phải chấp nhận những độ trễ, sai sót không đáng có đến từ con người.

Chúng ta sẽ tiếp cận các giải pháp cho vấn đề này theo hướng tự động, giao lại các vấn đề này cho máy tính xử lý, thông qua các ngôn ngữ lập trình, ngôn ngữ truy vấn.

Tiếp cận

Vấn đề tự động thực hiện 1 số thao tác định sẵn khi có sự thay đổi trên 1 bảng của cơ sở dữ liệu có thể được xử lý thông qua 2 cách tiếp cận chính như sau:

  • Sử dụng các ngôn ngữ lập trình cung cấp khả năng giao tiếp với với hệ quản trị cơ sở dữ liệu như PHP, C/C++, C#, NodeJS…
  • Sử dụng các cú pháp được hệ quản trị cơ sở dữ liệu cung cấp để hỗ trợ cho vấn đề này. Cụ thể ở đây là Trigger trong MySQL.

Ở cách tiếp cận đầu tiên, cho phép chúng ta thực hiện các thao tác phức tạp mà 1 ngôn ngữ lập trình bậc cao có thể cung cấp, tuy nhiên lại đánh đổi về hiệu năng do việc thông qua các lớp giao tiếp với hệ quản trị cơ sở dữ liệu và đòi hỏi ngôn ngữ này phải trực tiếp quản lý được (hoặc trung gian thông qua) các thao tác truy cập đến cơ sở dữ liệu. Dưới đây là mô hình và đoạn code bằng PHP (Laravel 5.4) được dùng để xử lý vấn đề đầu tiên ở trên:

php-mysql-model

<?php

function new_post(Request $request) {
  // Get request's body
  $body = json_decode($request->getContent(), true);

  // Insert new post into articles table & retrieve its id
  $id = DB::table('articles')->insertGetId($body);

  // Insert new post's id into articles_preview table
  DB::table('articles_preview')->insert([
    'article_id' => $id
  ]);
}

Ở cách tiếp cận thứ 2, cho phép chúng ta thực hiện các thao tác này ở mức độ cơ sở dữ liệu, từ đó đưa ra 1 giải pháp tự nhiên và cho phép hiệu năng ở mức cao nhất mà hệ quản trị cơ sở dữ liệu có thể cung cấp. Tuy nhiên, phương pháp này lại bị giới hạn bởi các cú pháp truy vấn mà hệ quản trị cơ sở dữ liệu đó cho phép.

Trong bài viết này, chúng ta sẽ tìm hiểu về Trigger trong MySQL.

Giải pháp sử dụng Trigger trong MySQL

Cấu trúc câu lệnh Trigger

CREATE TRIGGER [trigger_name] [BEFORE | AFTER] [INSERT | DELETE | UPDATE] ON [table_name]
FOR EACH
	[sql_statements]

Trong đó:

CREATE TRIGGER là câu lệnh dùng để khai báo Trigger.

[trigger_name] là tên của Trigger.

[BEFORE | AFTER] MySQL cung cấp 2 thời điểm để Trigger được kích hoạt khi có sự thay đổi dữ liệu trên bảng là trước (BEFORE) hoặc sau (AFTER) khi dữ liệu thay đổi.

[INSERT | DELETE | UPDATE] Trigger được kích hoạt khi 1 trong 3 thao tác chính là INSERT, DELETE, UPDATE xảy ra trên bảng.

[table_name] là tên của bảng sử dụng Trigger. Khi 1 trong 3 thao tác INSERT, DELETE, UPDATE được Trigger xác định xảy ra trên bảng này, Trigger đó sẽ được kích hoạt.

FOR EACH khai báo phần thân của Trigger, kể từ câu lệnh này trở đi, chúng ta định nghĩa những thao tác mà Trigger này sẽ thực hiện khi được kích hoạt.

Ví dụ (Trigger thực hiện việc thêm id của bài viết mới vào bảng articles):

CREATE TRIGGER pre_check_post AFTER INSERT ON articles
FOR EACH ROW
    INSERT INTO articles_review (article_id)
    VALUES (NEW.id);

Môi trường thực nghiệm

  • Windows 10.
  • MySQL Community 5.*.
  • MySQL Workbench 6.*.

Tạo dữ liệu mẫu

Hướng dẫn sử dụng MySQL Workbench 6 để chạy các câu lệnh SQL:

  • Khởi chạy MySQL Workbench.
  • Kết nối đến MySQL.

Đầu tiên tạo 1 kết nối tới MySQL.

workbench_connect_1

Nhập địa chỉ IP, Port, Username và Password (nếu có).

workbench_connect_2

Và kết quả:

workbench_connect_3

  • Mở tab mới để chạy các câu lệnh SQL.

workbench_query_1

  • Copy các câu lệnh SQL cần chạy vào Query Tab, nhấn Ctrl+Shift+Enter để chạy tất cả câu lệnh SQL trong tab, hoặc nhấn Ctrl+Enter để chạy chỉ những câu lệnh được chọn.

workbench_query_2

Tạo database & các bảng

CREATE DATABASE IF NOT EXISTS trigger_example;

USE trigger_example;

CREATE TABLE IF NOT EXISTS articles (
    id int(10) NOT NULL AUTO_INCREMENT,
    title varchar(255) NOT NULL,
    content mediumtext NOT NULL,
    author varchar(255) NOT NULL,
    status tinyint(1) DEFAULT 0 NOT NULL,
    created_at timestamp NOT NULL DEFAULT NOW(),
    updated_at timestamp NOT NULL DEFAULT NOW() ON UPDATE NOW(),
    PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS articles_preview (
    id int(10) NOT NULL AUTO_INCREMENT,
    article_id int(10) NOT NULL,
    inserted_at timestamp NOT NULL DEFAULT NOW(),
    PRIMARY KEY (id)
);

Tạo Trigger

USE trigger_example;

CREATE TRIGGER pre_check_post AFTER INSERT ON articles
FOR EACH ROW
    INSERT INTO articles_preview(article_id)
    VALUES (NEW.id);

Thêm dữ liệu mới vào bảng articles

USE trigger_example;

INSERT INTO articles (title, content, author)
VALUES (
    'IPHONE 7',
    'iPhone 7 dramatically improves the most important aspects of the iPhone experience. It introduces advanced new camera systems. The best performance and battery life ever in an iPhone. Immersive stereo speakers. The brightest, most colorful iPhone display. Splash and water resistance. And it looks every bit as powerful as it is. This is iPhone 7.',
    'User 1'
);

INSERT INTO articles (title, content, author)
VALUES (
    'Galaxy S7',
    'The Galaxy S7 is an evolution of the prior years model, with upgraded hardware, design refinements, and the restoration of features removed from the Galaxy S6, such as IP certification for water and dust resistance, as well as expandable storage. As with the S6, the S7 is produced in a standard model with a display size of 5.1-inch (130 mm), as well as an Edge variant whose display is curved along the wide sides of the screen. Unlike the S6, the S7 Edge also utilizes a larger 5.5-inch (140 mm) display rather than matching the screen size of the base models.',
    'User 2'
);

Kiểm tra kết quả

Sau khi thực hiện thực hiện thêm dữ liệu mới vào bảng articles. Chúng ta kiểm tra dữ liệu của bảng articles_preview bằng câu lệnh SELECT.

SELECT * FROM trigger_example.articles_preview

Kết quả:

workbench_result_1

Như vậy, mỗi khi ta thực hiện INSERT dữ liệu mới vào bảng articles, thì id của bài viết mới đã tự động được thêm vào bảng articles_preview.

Download mã nguồn

Các bạn có thể download mã nguồn của bài viết tại đây.

Kết luận

MySQL cung cấp Trigger như 1 giải pháp ở tầng cơ sở dữ liệu cho vấn đề tự động thực hiện 1 số thao tác xử lý dữ liệu định sẵn khi có sự thay đổi dữ liệu trong 1 bảng. Trigger được thực hiện bởi hệ quản trị cơ sở dữ liệu và không phụ thuộc vào ngôn ngữ lập trình, cũng như cho phép hiệu năng ở mức độ cao nhất.