2.2.1. Mô hình tổng quát của CSDL tích cực:
Mô hình được sử dụng để chỉ rõ các quy tắc của cơ sở dữ liệu tích cực được tham chiếu đến như là mô hình ECA (Event-Condition-Active). Một quy tắc trong mô hình ECA có 3 thành phần:
a. Sự kiện (Event) làm kích hoạt quy tắc: các sự kiện này thường là các thao tác cập nhật cơ sở dữ liệu được áp dụng một cách tường minh đối với cơ sở dữ liệu. Tuy nhiên, trong mô hình tổng quát chúng cũng có thể là các sự kiện thời gian hoặc là các dạng sự kiện ngoài khác.
b. Điều kiện (Condition) xác định hành động của quy tắc có thể được thực hiện hay không: mỗi khi sự kiện kích hoạt có mặt, một điều kiện được chọn
có thể được tính giá trị. Nếu không có điều kiện nào được chỉ rõ, hành động sẽ được thực hiện sự kiện xảy ra. Nếu điều kiện được chỉ rõ, đầu tiên nó được tính giá trị và chỉ khi nó tính giá trị là đúng (true) thì hành động của quy tắc sẽ được thực hiện.
c. Hành động (Action) thực hiện: Hành động thường là một dãy lệnh SQL nhưng nó cũng có thể là một giao tác cơ sở dữ liệu hoặc một chương trình bên ngoài sẽ được thực hiện một cách tự động.
Hãy xem một vài ví dụ minh họa khái niệm này. Có hai quan hệ NHÂN VIÊN và ĐƠN VỊ. Mỗi nhân viên có một tên (tenNV), mã số (masoNV), lương, mã số đơn vị (masoDV) là khóa ngoài tham chiếu đến DONVI, và mã số người giám sát (MasoNGS) là khóa ngoài đệ quy đến NHANVIEN. Với ví dụ này, chúng ta giả thiết rằng masoNV có thể cho phép có giá trị null, chỉ ra rằng nhân viên có thể tạm thời chưa được đăng ký vào đơn vị nào. Mỗi đơn vị có một tên (TenDV), một mã số (MasoDV), tổng lương của tất cả các nhân viên đăng ký vào đơn vị (Tongluong) và một người quản lý (MasoNQL) là khóa ngoài đến NHANVIEN.
Chú ý rằng thuôc tính Tongluong thực chất là một thuộc tính suy diễn được, giá trị của nó là tổng lương của tất cả các nhân viên đăng ký vào một đơn vị cụ thể. Việc duy trì giá trị đúng của một thuộc tính suy diễn được như vậy có thể được thực hiện thông qua một luật tích cực. Trước tiên chúng ta phải xác định các sự kiện có thể gây ra một thay đổi giá trị của Tongluong, đó là các sự kiện sau:
[1]. Chèn vào một hoặc nhiều bộ giá trị nhân viên mới [2]. Thay đổi lương của một hoặc nhiều nhân viên có sẵn
[3]. Thay đổi việc đăng ký của các nhân viên có sẵn từ đơn vị này sang đơn vị khác.
[4]. Loại bỏ một hoặc nhiều bộ giá trị nhân viên.
Trong trường hợp sự kiện 1, chúng ta chỉ cần tính lại Tongluong nếu nhân viên mới được ghi tức khắc vào một đơn vị - nghĩa là giá trị của thuộc tính MasoNV đối với bộ nhân viên mới là khác null (giả thiết null là cho phép đối
với MasoNV). Như vậy điều đó sẽ là điều kiện để kiểm tra. Một điều kiện tương tự có thể sẽ được kiểm tra cho sự kiện 2 (và 4) để xác định xem có phải là nhân viên mà lương của anh ta bị thay đổi (hoặc bị xóa) hiện tại đã được đăng ký vào một đơn vị hay không. Với sự kiện 3, chúng ta luôn luôn thực hiện một hành động để duy trì giá trị của Tongluong một cách đúng đắn, như vậy là không cần điều kiện nào (hành động luôn luôn được thực hiện).
Hành động đối với các sự kiện 1, 2 và 4 là cập nhật một cách tự động giá trị của Tongluong đối với đơn vị của nhân viên để phản ánh việc lương của nhân viên vừa mới được thêm, xóa hoặc cập nhật. Trong trường hợp của sự kiện 3, cần một hành động đúp: một để cập nhật Tongluong của đơn vị cũ của nhân viên và hành động khác để cập nhật Tongluong của đơn vị mới của nhân viên.
Bốn active rules R1, R2, R3 và R4 tương ứng với tình trạng ở trên có thể được chỉ ra trong ký hiệu của hệ quản trị cơ sở dữ liệu Oracle. Chúng ta hãy xét quy tắc R1 để minh họa cú pháp của việc tạo ra các luật tích cực trong Oracle. Lệnh CREATE TRIGGER chỉ rõ tên của một trigger (hoặc các luật tích cực) – Tongluong1 cho R1. Mệnh đề AFTER chỉ ra rằng quy tắc sẽ được kích hoạt sau sự kiện kích hoạt quy tắc xảy ra. Các sự kiện kích hoạt – ví dụ như chèn một nhân viên mới ở trong ví dụ này – được chỉ ra sau từ khóa AFTER. Mệnh đề ON chỉ rõ quan hệ mà trên đó quy tắc được chỉ ra – NHÂN VIÊN đối với R1. Các từ khóa tùy chọn FOR EACH ROW chỉ ra rằng quy tắc sẽ được kích hoạt một lần với mỗi một hàng bị ảnh hưởng bởi sự kiện kích hoạt. Mệnh đề tùy chọn WHEN được sử dụng để chỉ ra điều kiện nào cần kiểm tra sau khi quy tắc được kích hoạt nhưng trước khi hành động được thực hiện. Cuối cùng, hành động cần làm được chỉ ra như một khối PL/SQL, khối này thường chứa một hoặc nhiều lệnh SQL hoặc các lời gọi để thực hiện các thủ tục bên ngoài.
R1: CREATE TRIGGER Tongluong1 AFTER INSERT ON NHÂNVIÊN FOR EACH ROW
WHEN (NEW.MasoDV IS NOT NULL) UPDATE ĐƠNVỊ
SET Tongluong = Tongluong + NEW.Luong WHERE MasoDV = NEW.MasoDV;
R2: CREATE TRIGGER Tongluong2
AFTER UPDATE OF Luong ON NHÂNVIÊN FOR EACH ROW
WHEN (NEW.MasoDV IS NOT NULL) UPDATE ĐƠNVỊ
SET Tongluong = Tongluong + NEW.Luong – OLD.Luong WHERE MasoDV = NEW.MasoDV;
R3: CREATE TRIGGER Tongluong3
AFTER UPDATE OF DNO ON NHÂNVIÊN FOR EACH ROW
BEGIN
UPDATE ĐƠNVỊ
SET Tongluong = Tongluong + NEW.Luong WHERE MasoDV = NEW.MasoDV;
UPDATE ĐƠNVỊ
SET Tongluong = Tongluong - OLD.Luong WHERE MasoDV = OLD.MasoDV;
END;
R4: CREATE TRIGGER Tongluong4 AFTER DELETE ON NHÂNVIÊN FOR EACH ROW
WHEN (OLD.MasoDV IS NOT NULL) UPDATE ĐƠNVỊ
SET Tongluong = Tongluong - OLD.Luong WHERE MasoDV = OLD.MasoDV;
Bốn trigger (các quy tắc tích cực) R1, R2, R3 và R4 minh họa một số tính chất của các quy tắc tích cực. Trước tiên, các sự kiện cơ bản có thể chỉ ra để kích hoạt các quy tắc là các lệnh cập nhật của SQL chuẩn: INSERT, DELETE,
UPDATE. Chúng được chỉ ra bằng các từ khóa INSERT, DELETE, UPDATE trong ký hiệu của Oracle. Trong trường hợp của UPDATE người ta có thể chỉ ra các thuộc tính được cập nhật – ví dụ, bằng cách viết UPDATE OF Luong, MasoDV. Thứ hai, người thiết kế quy tắc cần có cách tham chiếu đến các bộ giá trị đã được chèn, xóa, sửa đổi: Các từ khóa NEW và OLD được sử dụng trong Oracle: NEW được sử dụng để tham chiếu đến bộ vừa được chèn vào hoặc vừa được sửa đổi, trong khi đó OLD được sử dụng để tham chiếu đến bộ bị xóa hoặc bộ trước khi được cập nhật.
Như vậy, quy tắc R1 được kích hoạt sau một phép toán INSERT được áp dụng cho quan hệ NHÂNVIÊN. Trong R1, điều kiện (NEW.MasoDV IS NOT NULL) được kiểm tra, và nếu nó được tính giá trị là đúng, nghĩa là bộ nhân viên vừa mới được chèn vào là có quan hệ với một đơn vị, thì hành động sẽ được thực hiện. Hành động cập nhật các bộ ĐƠNVỊ có liên quan tới nhân viên vừa mới được chèn vào bằng cách cộng lương của người đó (NEW.Luong) vào thuộc tính Tongluong của đơn vị liên quan của chúng.
Quy tắc R2 tương tự với R1 nhưng nó được kích hoạt bằng một phép toán UPDATE, sửa đổi lương của một nhân viên thay vì chèn. Quy tắc R3 được kích hoạt bằng một sửa đổi đối với thuộc tính MasoDV của NHÂNVIÊN, nó có nghĩa thay đổi đăng ký của nhân viên từ một đơn vị sang một đơn vị khác. Không có điều kiện để kiểm tra trong R3, vì vậy hành động được thực hiện mỗi khi sự kiện kích hoạt xuất hiện. Hành động sửa đổi cả đơn vị mới và đơn vị cũ của nhân viên đăng ký lại bằng cách cộng lương của họ vào Tongluong của đơn vị mới và trừ lương của họ ra khỏi Tongluong của đơn vị cũ. Để ý rằng điều này có thể làm việc ngay cả giá trị của MasoDV là NULL bởi vì trong trường hợp này không đơn vị nào được lựa chọn cho hành động của quy tắc.
Điều quan trọng là xét ảnh hưởng của mệnh đề tùy chọn FOR EACH ROW, nó có nghĩa là quy tắc được kích hoạt một cách riêng rẽ đối với mỗi bộ giá trị. Điều này được biết đến như một row-level-trigger. Nếu mệnh đề này bị bỏ qua, trigger sẽ được biết như là một statement-level trigger và sẽ được kích hoạt một lần đối với mỗi lệnh kích hoạt. Để thấy sự khác nhau, hãy xem phép
toán cập nhật sau đây, nó tăng 10% lương cho tất cả các nhân viên đăng ký vào đơn vị 5. Phép toán này sẽ là một sự kiện kích hoạt quy tắc R2:
R2: UPDATE NHÂNVIÊN SET Luong = 1.1* Luong WHERE MasoDV=5;
Bởi vì lệnh ở trên có thể cập nhật nhiều bản ghi, một quy tắc sử dụng ngôn ngữ row-level như là R2 sẽ được kích hoạt một lần đối với mỗi hàng, trong khi đó một quy tắc sử dụng ngữ nghĩa statement-level được kích hoạt chỉ một lần. Hệ thống Oracle cho phép người sử dụng chọn lựa một trong hai tùy chọn trên để sử dụng cho mỗi quy tắc. Việc dựa vào mệnh đề tùy chọn FOR EACH ROW tạo ra một row-level trigger và việc bỏ nó tạo ra một statement-level trigger. Để ý rằng các từ khóa NEW và OLD chỉ có thể được sử dụng với các row-level trigger.
Cú pháp để chỉ ra các trigger trong hệ thống Oracle được tổng kết như sau: <trigger>:: = CREATE TRIGGER <tên Trigger>
(AFTER| BEFORE) <sự kiện kích hoạt> ON <tên bảng> [ FOR EACH ROW]
[WHEN <điều kiện>] <hành động của trigger>;
<Sự kiện kích hoạt>::= <sự kiện của trigger>
<Sự kiện của trigger>::= <INSERT| DELETE| UPDATE| [OF <tên cột> {, <tên cột>}].
Một ví dụ khác, giả sử rằng chúng ta muốn kiểm tra có phải lương của một nhân viên là lớn hơn lương của người giám sát trực tiếp của anh ta hay không? Nhiều sự kiện có thể kích hoạt quy tắc này: việc chèn vào một nhân viên mới, thay đổi lương của một nhân viên hoặc thay đổi người giám sát của nhân viên. Giả sử rằng hành động sẽ thực hiện sẽ là một lời gọi đến một thủ tục bên ngoài INFORM_SUPERVISOR, nó sẽ thông báo về người giám sát. Quy tắc có thể được viết như sau:
BEFORE INSERT OF UPDATE OF Luong, MasoNGS ON NHÂNVIÊN FOR EACH ROW
WHEN
(NEW.Luong > (SELECT Luong FROM NHÂNVIÊN WHERE MasoNV = NEW.MasoNGS))
INFORM_SUPERVISOR (NEW.MasoNGS, NEW.MasoNV);
2.2.2. Vấn đề thiết kế và cài đặt cho các cơ sở dữ liệu tích cực
Phần trước đã cho tổng quan về các khái niệm chính để chỉ ra các quy tắc tích cực. Trong phần này đưa các vấn đề bổ sung liên quan đến việc thiết kế và cài đặt các quy tắc như thế nào. Vấn đề thứ nhất liên quan đến việc kích hoạt, thôi kích hoạt và nhóm các quy tắc. Thêm vào việc tạo ra các quy tắc, một hệ thống cơ sở dữ liệu tích cực phải cho phép những người sử dụng kích hoạt, thôi kích hoạt và bỏ các quy tắc bằng cách tham chiếu đến các tên quy tắc của chúng. Một quy tắc thôi kích hoạt sẽ không bị kích hoạt bởi sự kiện kích hoạt. Tính chất này cho phép các người sử dụng lựa chọn các quy tắc thôi kích hoạt đối với một chu kỳ thời gian nào đó khi chúng là không cần thiết. Các lệnh kích hoạt sẽ làm cho các quy tắc tích cực trở lại. Lệnh drop loại bỏ các luật ra khỏi hệ thống. Một tùy chọn khác là nhóm các quy tắc vào một cái gọi là thiết lập quy tắc, như vậy toàn bộ tập hợp các quy tắc có thể được kích hoạt, ngừng kích hoạt hoặc loại bỏ. Việc có một lệnh có thể kích hoạt một quy tắc hoặc một tập quy tắc thông qua một lệnh PROCESS RULES do người sử dụng đưa ra cũng là một điều có lợi.
Vấn đề thứ hai liên quan đến liệu hành động được kích hoạt có thể được thực hiện trước, sau, hoặc đồng thời với sự kiện kích hoạt được hay không. Vấn đề liên quan là liệu hành động được kích hoạt có thể được xem như một giao tác tách rời hay không hay nó phải là một phần của cung giao tác kích hoạt quy tắc. Trước tiên chúng ta phải cố gắng phân loại các tùy chọn khác nhau.
Điều quan trọng là không phải tất cả các tùy chọn có thể sẵn sang sử dụng đối với một hệ cơ sở dữ liệu tích cực. Thật vậy, hầu hết các hệ thống thương mại được giới hạn đến một hoặc hai tùy chọn.
Giả thiết rằng sự kiện kích hoạt xảy ra như là một phần của việc thực hiện giao tác. Trước hết chúng ta xét các tùy chọn khác nhau với việc sự kiện kích hoạt liên kết với việc tính giá trị của các điều kiện của quy tắc như thế nào. Việc tính giá trị của các điều kiện của quy tắc cũng được xem như xem xét quy tắc bởi vì hành động chỉ được thực hiện sau sự xem xét lại điều kiện tính giá trị đến true hoặc fasle. Có ba khả năng chính đối với sự xem xét quy tắc:
[1]. Sự xem xét tức khắc (immediate consideration): Điều kiện được tính giá trị như là một phần của cùng giao tác như là sự kiện kích hoạt và được tính toán ngay tức khắc. Trường hợp này có thể được phân loại thành ba tùy chọn:
- Tính giá trị điều kiện trước khi thực hiện sự kiện kích hoạt - Tính giá trị điều kiện sau khi thực hiện sự kiện kích hoạt - Tính giá trị điều kiện thay vì thực hiện sự kiện kích hoạt
[2]. Sự xem xét chậm: Điều kiện được tính giá trị ở cuối giao tác chứa sự kiện kích hoạt. Trong trường hợp này có thể có nhiều quy tắc được kích hoạt chờ để có các điều kiện của chúng được tính.
[3]. Sự xem xét riêng rẽ: Điều kiện được tính giá trị như là một giao tác riêng rẽ, tách rời khỏi giao tác kích hoạt.
Tập hợp các tùy chọn tiếp theo liên quan đến mối quan hệ giữa việc tính giá trị điều kiện của quy tắc và việc thực hiện hành động của quy tắc. Ở đây, một lần nữa có ba tùy chọn có thể có: thực hiện tức khắc, thực hiện chậm và thực hiện tách rời. Tuy nhiên, hầu hết các hệ thống tích cực sử dụng tùy chọn thứ nhất. Nghĩa là, khi điều kiện được tính giá trị, nếu nó trả lại giá trị true, hành động được thực hiện ngay tức khắc.
Một vấn đề khác liên quan đến các quy tắc của cơ sở dữ liệu tích cực là sự phân biệt các quy tắc mức dòng (row-level rule) và các quy tắc mức lệnh (statement-level rule). Bởi vì các lệnh cập nhật của SQL (được xem như các sự kiện kích hoạt) có thể chỉ ra một tập hợp các bộ, ta phải phân biệt giữa liệu quy tắc có thể xem xét một lần đối với toàn bộ lệnh hay không hay liệu nó có thể được xem xét một cách tách biệt đối với từng hàng bị ảnh hưởng bởi lệnh. Hệ
thống Oracle cho phép người sử dụng chọn một trong hai tùy chọn trên sử dụng với từng quy tắc.
Một trong các khó khăn có thể hạn chế việc sử dụng rộng rãi các quy tắc tích cực, mặc dù khả năng của chúng lầm đơn giản việc phát triển cơ sở dữ liệu và phần mềm, là ở chỗ không có các kỹ thuật dễ sử dụng để thiết kế, viết và kiểm tra các quy tắc. Ví dụ, rất khó khăn để kiểm tra rằng một tập hợp các quy tắc là tương thích, nghĩa là hai hoặc nhiều quy tắc trong tập hợp không mâu thuẫn với nhau. Cũng rất khó khăn để đảm bảo sự kết thúc của một tập hợp các quy tắc dưới mọi hoàn cảnh. Để minh họa ngắn gọn vấn đề kết thúc, hãy xem xét các quy tắc dưới đây:
R1: CREATE TRIGGER T1 AFTER INSERT ON TABLE1 FOR EACH ROW
UPDATE TABLE 2
SET ATTRIBUTE 1 = ……..; R2: CREATE TRIGGER T2
AFTER UPDATE OF ATTRIBUTE1 ON TABLE 2 FOR EACH ROW
INSERT INTO TABLE 1 VALUE (….);
Ở đây quy tắc R1 được kích hoạt bởi một sự kiện INSERT trên bảng 1 và hành động của nó gồm một sự kiện UPDATE trên thuộc tính 1 của bảng 2. Tuy nhiên, sự kiện kích hoạt của quy tắc R2 là một sự kiện UPDATE trên thuộc tính