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