Apache Derby Bài 09: Ràng buộc toàn vẹn: Primary Key, Foreign Key, Unique và Not Null
1. Ràng buộc toàn vẹn (Integrity Constraints) là gì?
Ràng buộc toàn vẹn là các quy tắc được định nghĩa trực tiếp ở tầng lược đồ (schema) của cơ sở dữ liệu nhằm:
-
Ngăn chặn việc đưa dữ liệu sai lệch, thiếu sót hoặc trùng lặp vào các bảng.
-
Bảo đảm tính nhất quán của mối quan hệ giữa các thực thể mà không phụ thuộc hoàn toàn vào tầng ứng dụng.
-
Tự động sinh ra cấu trúc chỉ mục (Index ngầm định) để tăng tốc độ truy vấn tìm kiếm.
Trong Apache Derby, bạn có thể khai báo ràng buộc ở hai cấp độ:
-
Cấp độ cột (Column-level constraint): Khai báo ngay sau kiểu dữ liệu của cột.
-
Cấp độ bảng (Table-level constraint): Khai báo ở cuối câu lệnh
CREATE TABLE, bắt buộc dùng khi ràng buộc bao gồm từ 2 cột trở lên (ràng buộc kết hợp).
2. Chi tiết 4 ràng buộc cốt lõi trong Apache Derby
1. NOT NULL (Không cho phép rỗng)
-
Ý nghĩa: Bắt buộc trường dữ liệu phải có giá trị khi chèn hoặc cập nhật; không được mang giá trị
NULL. -
Cú pháp: Luôn được khai báo ở cấp độ cột.
SQL
ten_danh_muc VARCHAR(100) NOT NULL
2. PRIMARY KEY (Khóa chính)
-
Ý nghĩa: Định danh duy nhất cho từng bản ghi trong bảng.
-
Đặc tính trong Derby:
-
Mỗi bảng chỉ có duy nhất 1 khóa chính.
-
Các cột tham gia khóa chính tự động mang ràng buộc
NOT NULL. -
Derby tự động tạo một chỉ mục B-tree duy nhất (Unique Index) phía sau để tối ưu tìm kiếm theo khóa chính.
-
SQL
-- Cấp độ cột (cho khóa chính 1 cột)
ma_danh_muc VARCHAR(20) CONSTRAINT pk_danh_muc PRIMARY KEY
-- Cấp độ bảng (khuyến nghị vì dễ đặt tên CONSTRAINT rõ ràng)
CONSTRAINT pk_danh_muc PRIMARY KEY (ma_danh_muc)
-- Khóa chính phức hợp (Composite Primary Key - bắt buộc khai báo cấp độ bảng)
CONSTRAINT pk_chi_tiet_don PRIMARY KEY (ma_don_hang, ma_san_pham)
3. UNIQUE (Giá trị duy nhất)
-
Ý nghĩa: Đảm bảo toàn bộ giá trị trong một hoặc một nhóm cột không bị trùng lặp.
-
Khác biệt với Primary Key:
-
Một bảng có thể có nhiều ràng buộc
UNIQUE. -
Trong Derby, các cột có ràng buộc
UNIQUEvẫn bắt buộc phải làNOT NULL(khác với một số hệ quản trị như PostgreSQL hay MySQL cho phép nhiều giá trị NULL).
-
SQL
CONSTRAINT uq_ma_vach UNIQUE (ma_vach)
4. FOREIGN KEY (Khóa ngoại)
-
Ý nghĩa: Thiết lập mối quan hệ tham chiếu (Referential Integrity) giữa bảng con và bảng cha. Cột khóa ngoại ở bảng con phải trỏ tới một cột là
PRIMARY KEYhoặcUNIQUEở bảng cha. -
Các hành vi xóa dữ liệu (
ON DELETE):-
ON DELETE NO ACTION(Mặc định trong Derby): Nếu bảng cha còn bản ghi con tham chiếu tới thì chặn không cho xóa bảng cha. -
ON DELETE RESTRICT: Tương tựNO ACTION, kiểm tra tính toàn vẹn ngay khi bắt đầu thực thi lệnh xóa. -
ON DELETE CASCADE: Khi xóa bản ghi ở bảng cha, tất cả các bản ghi con liên quan ở bảng con sẽ bị xóa tự động theo. -
ON DELETE SET NULL: Khi xóa bản ghi ở bảng cha, cột khóa ngoại ở bảng con được gán vềNULL(chỉ áp dụng nếu cột khóa ngoại cho phép NULL).
-
Lưu ý trong Derby: Apache Derby chưa hỗ trợ
ON UPDATE CASCADE. Nếu bạn cần cập nhật mã định danh khóa chính ở bảng cha, bạn phải thực hiện thông qua nghiệp vụ ứng dụng hoặc Stored Procedure/Trigger.
3. Thực hành thiết kế quan hệ 1-N với đầy đủ ràng buộc
Chúng ta sẽ xây dựng hai bảng mô phỏng nghiệp vụ quản lý kho hàng: bảng danh mục sản phẩm (bảng cha) và bảng chi tiết sản phẩm (bảng con).
Mở công cụ ij và chạy khối lệnh sau:
SQL
CONNECT 'jdbc:derby:firstdb';
-- 1. Tạo bảng cha: Danh mục ngành hàng
CREATE TABLE danh_muc (
ma_danh_muc VARCHAR(20) NOT NULL,
ten_danh_muc VARCHAR(100) NOT NULL,
slug VARCHAR(120) NOT NULL,
trang_thai SMALLINT DEFAULT 1,
CONSTRAINT pk_danh_muc PRIMARY KEY (ma_danh_muc),
CONSTRAINT uq_danh_muc_slug UNIQUE (slug)
);
-- 2. Tạo bảng con: Sản phẩm thiết bị (Tham chiếu tới danh_muc)
CREATE TABLE thiet_bi (
ma_thiet_bi VARCHAR(30) NOT NULL,
ten_thiet_bi VARCHAR(150) NOT NULL,
ma_danh_muc VARCHAR(20) NOT NULL,
so_serial VARCHAR(50) NOT NULL,
gia_tien DECIMAL(12, 2) NOT NULL,
ngay_nhap DATE DEFAULT CURRENT_DATE,
-- Khóa chính
CONSTRAINT pk_thiet_bi PRIMARY KEY (ma_thiet_bi),
-- Ràng buộc duy nhất cho Serial thiết bị
CONSTRAINT uq_thiet_bi_serial UNIQUE (so_serial),
-- Khóa ngoại tham chiếu bảng danh_muc
CONSTRAINT fk_thiet_bi_danh_muc FOREIGN KEY (ma_danh_muc)
REFERENCES danh_muc (ma_danh_muc)
ON DELETE RESTRICT
);
4. Kiểm tra phản ứng vi phạm ràng buộc (Constraint Violations)
Để hiểu rõ cơ chế bảo vệ của Derby, hãy thử nghiệm các thao tác vi phạm tính toàn vẹn:
Thử nghiệm 1: Chèn vào bảng con mã danh mục không tồn tại
SQL
INSERT INTO thiet_bi (ma_thiet_bi, ten_thiet_bi, ma_danh_muc, so_serial, gia_tien)
VALUES ('TB-001', 'Cam bien nhiet do DHT22', 'DM_DIEN_TU', 'SN-998877', 85000.00);
Kết quả: Derby chặn lại và báo lỗi SQLState 23503 (Foreign key violation):
Plaintext
ERROR 23503: The insert or update value of the FOREIGN KEY constraint 'FK_THIET_BI_DANH_MUC' is invalid.
Thử nghiệm 2: Chèn dữ liệu hợp lệ rồi thử xóa bản ghi cha
SQL
-- Chèn danh mục hợp lệ
INSERT INTO danh_muc (ma_danh_muc, ten_danh_muc, slug)
VALUES ('DM_DIEN_TU', 'Linh kien dien tu', 'linh-kien-dien-tu');
-- Chèn thiết bị thuộc danh mục trên
INSERT INTO thiet_bi (ma_thiet_bi, ten_thiet_bi, ma_danh_muc, so_serial, gia_tien)
VALUES ('TB-001', 'Cam bien nhiet do DHT22', 'DM_DIEN_TU', 'SN-998877', 85000.00);
-- Cố tình xóa danh mục cha khi đang có thiết bị con tham chiếu
DELETE FROM danh_muc WHERE ma_danh_muc = 'DM_DIEN_TU';
Kết quả: Nhờ có quy tắc ON DELETE RESTRICT, Derby bảo vệ dữ liệu cha và từ chối xóa:
Plaintext
ERROR 23504: The delete rule of the FOREIGN KEY constraint 'FK_THIET_BI_DANH_MUC' prevented the deletion.
5. Thao tác thêm hoặc xóa ràng buộc với ALTER TABLE
Nếu bảng đã tồn tại và bạn muốn bổ sung ràng buộc sau này:
SQL
-- Thêm ràng buộc khóa ngoại mới
ALTER TABLE thiet_bi
ADD CONSTRAINT fk_thiet_bi_danh_muc FOREIGN KEY (ma_danh_muc)
REFERENCES danh_muc (ma_danh_muc);
-- Xóa một ràng buộc đã đặt tên
ALTER TABLE thiet_bi
DROP CONSTRAINT uq_thiet_bi_serial;
Best Practice: Luôn đặt tên tường minh cho mọi ràng buộc bằng từ khóa
CONSTRAINT <ten_rang_buoc>(ví dụ:pk_...,fk_...,uq_...). Tránh để Derby tự sinh tên ngẫu nhiên dạngSQL2610101018001, vì sẽ rất khó xác định và gỡ bỏ khi cần bảo trì lược đồ.
6. Tổng kết
-
Các ràng buộc
PRIMARY KEY,UNIQUE,NOT NULL, vàFOREIGN KEYtạo thành lớp bảo vệ tính toàn vẹn dữ liệu ngay tại lõi Derby Engine. -
Derby yêu cầu các cột có ràng buộc
UNIQUEphải đi kèmNOT NULL. -
Derby hỗ trợ đầy đủ quy tắc
ON DELETE(RESTRICT,CASCADE,SET NULL,NO ACTION), nhưng không hỗ trợON UPDATE CASCADE.
Bài tiếp theo sẽ tìm hiểu cách kiểm tra logic giá trị và thiết lập giá trị mặc định: Apache Derby Bài 10: Ràng buộc kiểm tra (CHECK) và giá trị mặc định (DEFAULT).
All rights reserved