Xử lý lỗi trong MySQL
- 18-12-2025
- Toanngo92
- 0 Comments
ySQL dùng HANDLER để “bắt lỗi” khi có sự cố xảy ra trong:
- Stored Procedure
- Function
- Trigger
👉 Cách hoạt động:
- Khai báo HANDLER
- Khi lỗi xảy ra → MySQL tự động nhảy vào HANDLER
Mục lục
2. Cú pháp tương đương TRY – CATCH
🔹 Cấu trúc tổng quát
DECLARE handler_type HANDLER FOR condition_value
BEGIN
-- code xử lý lỗi
END;
Trong đó:
- handler_type
CONTINUE→ tiếp tục chạyEXIT→ dừng procedure ngay
- condition_value
SQLEXCEPTION→ mọi lỗi SQLSQLWARNING→ cảnh báoNOT FOUND→ không có dữ liệu (hay dùng với cursor)
3. Ví dụ đơn giản (tương đương TRY – CATCH)
Ví dụ: INSERT lỗi thì rollback
DELIMITER //
CREATE PROCEDURE insert_user()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SELECT 'Có lỗi xảy ra, đã rollback' AS message;
END;
START TRANSACTION;
INSERT INTO users(name) VALUES ('Toàn');
INSERT INTO users(name) VALUES (NULL); -- lỗi nếu name NOT NULL
COMMIT;
END;
//
DELIMITER ;
👉 Ý nghĩa:
- Nếu bất kỳ lỗi SQL nào xảy ra
- MySQL tự động nhảy vào HANDLER
ROLLBACKđược gọi- Procedure kết thúc (do
EXIT)
4. Ví dụ CONTINUE (không dừng chương trình)
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
SET @has_error = 1;
→ Dùng khi:
- Muốn ghi log lỗi
- Vẫn cho code chạy tiếp
5. Ví dụ bắt lỗi “không tìm thấy dữ liệu”
DECLARE done INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
👉 Thường dùng trong CURSOR loop
6. So sánh nhanh với TRY CATCH (để dễ hiểu)
| Ngôn ngữ khác | MySQL |
|---|---|
| TRY | Code chính trong BEGIN |
| CATCH | DECLARE HANDLER |
| THROW | SIGNAL |
| FINALLY | Không có trực tiếp |
7. Tự phát sinh lỗi (giống THROW)
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Lỗi nghiệp vụ';
👉 Dùng khi:
- Kiểm tra điều kiện nghiệp vụ
- Chủ động dừng procedure
8. Lưu ý quan trọng (hay bị sai)
❌ Không dùng được HANDLER ngoài procedure/trigger
❌ HANDLER phải khai báo trước các câu lệnh SQL
✅ Một procedure có thể có nhiều handler
Bài tập
Tạo database QuanlyNhanKhau
Tạo bảng QuanHuyen
| Column | Datatype | Constraint | Description |
| MaQH | INT auto_increment | NOT NULL | Mã quận huyện |
| TenQH | NVARCHAR(100) | Tên quận huyện |
Tạo bảng DuongPho
| Column | Datatype | Constraint | Description |
| DuongID | INT | NOT NULL | Mã đươờng |
| MaQH | INT | NOT NULL | Mã quận huyện |
| TenDuong | NVARCHAR(MAX) | NOT NULL | Tên Đường |
| NgayDuyet | DATETIME | NOT NULL | Ngày duyệt tên |
Tạo bảng NhaTrenPho
| Column | Datatype | Constraint | Description |
| NhaID | INT | NOT NULL | Mã nhà |
| DuongID | INT | NOT NULL | Mã đường |
| ChuHo | NVARCHAR(50) | NULL | Chủ hộ |
| DienTich | MONEY | NULL | Diện tích |
| SoNhanKhau | int | số nhân khẩu |
Tạo ràng buộc cho các bảng:
Primary key
| Constraint Name | Table | Applied Column |
| PK_QuanHuyen | QuanHuyen | MaQH |
| PK_DuongPho | DuongPho | DuongID |
| PK_NhaTrenPho | NhaTrenPho | NhaID |
Foreign key
| Constraint Name | Referencing Table | Foreign Key column | Referrenced Table | Referenced Column |
| FK_NhaTrenPho_DuongPho | NhaTrenPho | DuongID | DuongPho | DuongID |
| FK_DuongPho_QuanHuyen | DuongPho | MaQH | QuanHuyen | MaQH |

Nhập lệu vào bảng thông tin sau:
Lưu ý, khi nhập dữ liệu datetime, có thể sử dụng chuỗi 'yyyy-mm-dd'
QuanHuyen:
| MaQH | TenQH |
| 1 | Ba Đình |
| 2 | Hoàng Mai |
DuongPho:
| DuongId | MaQH | TenDuong | NgayDuyetTen(dd/mm/yyyy) |
| 1 | 1 | Trường Chinh | 19/10/1946 |
| 2 | 1 | Tây Sơn | 30/12/1998 |
| 3 | 2 | Chùa Bộc | 21/09/1975 |
NhaTrenPho:
| NhaID | DuongID | ChuHo | DienTich | SoNhanKhau |
| 1 | 1 | Toàn Ngô Vĩnh | 100 | 4 |
| 2 | 1 | Lê Văn A | 20 | 12 |
| 3 | 2 | Nguyễn Thị B | 40 | 1 |
Sửa bảng (ALTER TABLE) DuongPho, cột [TenDuong] từ 'Chùa Bộc' thành 'Thái Hà'
Tạo view có tên vw_All_NhaTrenPho với dữ lệu từ 3 bảng: [Nha_Tren_Pho],[DuongPho] và [QuanHuyen]
thực thi view [vw_All_NhaTrenPho]
Tạo view có tên là `[view_AVG_NhaTrenPho]` để tổng hợp dữ liệu trung bình từ 2 bảng `[NhaTrenPho]` và `[DuongPho]`.
-Thực thi view `[view_AVG_NhaTrenPho]` để hiển thị thông tin.
Thực thi view trên để kết quả hiển thị như hình
| TenDuong | Dientichtrungbinh | Nhankhautrungbinh |
| Trường Chinh | 40 | 1 |
| Tây Sơn | 100 | 8 |
Sắp xếp theo thứ tự tăng dần của trung bình [Dientich] và trung bình [SonhanKhau] (Ví dụ: ORDER BY AVG_Dientich ASC, AVG_SoNhanKhau ASC).
Tạo procedured có tên [sp_NgayDuyetTen_DuongPho] với tham số truyền vào:
| Parameter | Data Type |
| @NgayDuyet | DATETIME |
Procedure sẽ làm nghiệp vụ lấy ra toàn bộ đường có ngày duyệt tên là ngày nhập liệu
Thực thi procedure [sp_NgayDuyetTen_DuongPHo] NgayDuyetTen = @NgayDuyet
Chạy Procedure với tham số @NgayDuyet='30/12/1998' (sử dụng date time convert hoặc chuỗi năm tháng ngày)
Kết quả trả ra mô phỏng:
| Ngay Duyet Ten | Ten Duong | Ten Quan Huyen |
| 1998-12-30 00:00:00.000 | Vạn Phúc | Ba đình |
Tạo trigger có tên [TG_NhaTrenPho_Update] để kiểm tra giá trị cột [SoNhanKhau]
- Nếu giá trị nhỏ hơn 0, rollback lại và không thực hiện cập nhâật.
- Nếu giá trị lớn hơn 0, cho phép cập nhật.
| Trigger Name | For Event | Table | Fired Condition | Error Message |
| TG_NhaTrenPho_Update | UPDATE | NhaTrenPho | SoNhanKhau < 0 | SoNhanKhau phai lon hon 0 |
Tạo trigger có tên [TG_DuongPho_Instead_Of_Delete] cho bảng [DuongPho]
| Trigger Name | For Event | Table | Error Message |
| TG_DuongPho_Instead_Of_Delete | DELETE | DuongPho | Khong xoa duoc duong pho |

