Apache Derby Bài 45: Phân tích nhật ký hệ thống (derby.log) và khắc phục sự cố
Trong công việc bảo trì hệ thống thực tế—cho dù đó là xử lý luồng dữ liệu logistics phức tạp hay điều tra nguyên nhân lỗi thiết bị phần cứng tại các nhà ga—nhật ký hệ thống luôn là "hộp đen" cung cấp manh mối đầu tiên. Đối với Apache Derby, hộp đen này chính là tệp derby.log.
1. Vị trí và Vai trò của derby.log
Mặc định, ngay khi Derby Engine khởi động (dù ở chế độ Embedded hay Network Server), nó sẽ tự động sinh ra một tệp văn bản có tên derby.log tại thư mục gốc của hệ thống (xác định bởi biến derby.system.home). Nếu biến này không được thiết lập, tệp log sẽ nằm ở ngay thư mục nơi bạn chạy ứng dụng Java.
Tệp này ghi lại toàn bộ vòng đời của cơ sở dữ liệu:
-
Thông tin khởi động và tắt máy chủ (Boot/Shutdown).
-
Các cảnh báo hệ thống (Warnings) và lỗi nghiêm trọng (Severe Errors).
-
Dấu vết của các giao dịch bị bế tắc (Deadlock traces).
-
Quá trình phục hồi dữ liệu tự động (Crash Recovery) sau khi mất điện.
Lưu ý: Mặc định, Derby sẽ ghi đè tệp này mỗi khi khởi động lại. Nếu bạn muốn lưu vết lịch sử dài hạn, hãy thêm thuộc tính derby.infolog.append=true vào tệp derby.properties (đã học ở Bài 23).
2. Giải phẫu một thông điệp Log chuẩn
Một thông điệp lỗi trong derby.log thường đi kèm với các mã định danh giúp bạn khoanh vùng sự cố nhanh chóng. Dưới đây là một mẫu log điển hình khi xảy ra lỗi:
Plaintext
2026-10-10 09:15:32.450 GMT
Thread[DRDAConnThread_5,5,derby.daemons]
XID = 152899 (UserTransaction)
ERROR 40001: A lock could not be obtained due to a deadlock, cycle of locks and waiters is:
Lock : ROW, don_hang, (1, 14)
...
Các thành phần cốt lõi cần chú ý:
-
Timestamp: Thời điểm chính xác xảy ra sự cố (luôn ghi theo múi giờ JVM).
-
Thread ID: Cho biết luồng nào đang xử lý. Các luồng bắt đầu bằng
DRDAConnThreadám chỉ đây là một yêu cầu gửi đến từ Network Client. -
XID (Transaction ID): Mã định danh giao dịch. Rất hữu ích để đối chiếu khi bạn nghi ngờ hai giao dịch đang xung đột với nhau.
-
Mã SQLState (Ví dụ:
40001): Đây là mã lỗi chuẩn quốc tế, chìa khóa quan trọng nhất để tra cứu nguyên nhân.
3. Các mã lỗi (SQLState) kinh điển và hướng xử lý
Khi phân tích các báo cáo sự cố (Incident Reports), việc phân loại nhanh mã lỗi sẽ giúp bạn đưa ra hướng xử lý chính xác. Dưới đây là các SQLState phổ biến nhất trong Derby:
-
XJ040(Database locked):-
Nguyên nhân: CSDL đang được một tiến trình JVM khác chiếm giữ. Thường xảy ra khi bạn mở DBeaver/DataGrip ở chế độ Embedded trong lúc ứng dụng Java đang chạy.
-
Khắc phục: Đóng một trong hai ứng dụng, hoặc kiểm tra và xóa thủ công tệp
db.lcknếu ứng dụng trước đó bị treo (crash). Đảm bảo mọi kết nối GUI đều dùng Network Mode (Bài 25).
-
-
08001(Connection refused):-
Nguyên nhân: Client không thể tìm thấy Network Server.
-
Khắc phục: Kiểm tra xem lệnh
startNetworkServerđã được chạy chưa, kiểm tra IP/Port và tường lửa của máy chủ.
-
-
40001(Deadlock):-
Nguyên nhân: Xung đột tài nguyên khi hai giao dịch cùng chờ khóa của nhau.
-
Khắc phục: Derby sẽ tự động
ROLLBACKmột giao dịch. Ở phía ứng dụng Java, bạn cần viết logic bắt lỗi này và thực hiệnRetry(Thử lại) giao dịch.
-
-
28502/28504(Authorization Error):-
Nguyên nhân: User đã xác thực nhưng không có quyền
SELECThoặcUPDATEtrên bảng chỉ định. -
Khắc phục: Dùng tài khoản Database Owner chạy lệnh
GRANTđể cấp quyền (Bài 37).
-
-
X0Y32(Table already exists):-
Nguyên nhân: Cố gắng
CREATE TABLEmột bảng đã tồn tại. -
Khắc phục: Bắt lỗi này trong khối
catchđể bỏ qua, hoặc dùng cơ chế quản lý Schema tự động như Flyway/Liquibase/Hibernate ddl-auto.
-
4. Bật chế độ "Truy vết truy vấn" (Statement Logging)
Nếu hệ thống bị chậm bất thường nhưng không hề báo lỗi, bạn cần xem chính xác Derby đang phải xử lý những câu lệnh SQL nào. Bạn có thể ép Derby ghi lại toàn bộ mã SQL của các câu truy vấn vào derby.log.
Thêm các dòng sau vào derby.properties:
Properties
# Ghi lại nội dung các câu lệnh SQL
derby.language.logStatementText=true
# Ghi chi tiết về quá trình cấp phát và chờ khóa (Hữu ích khi điều tra hiệu năng)
derby.locks.deadlockTrace=true
Cảnh báo: Chế độ này sẽ làm tệp log phình to rất nhanh và làm giảm hiệu năng I/O. Chỉ nên bật trong môi trường Test, hoặc bật tạm thời trên Production khi cần điều tra sự cố (Troubleshooting), sau đó phải tắt đi.
5. Quy trình xử lý sự cố chuẩn mực
Khi hệ thống báo lỗi, thay vì khởi động lại ngay lập tức, hãy tuân thủ quy trình sau để giữ nguyên hiện trường:
-
Cô lập vấn đề: Mở
derby.log, trích xuất đoạn log tại thời điểm xảy ra lỗi dựa vào Timestamp. -
Định danh lỗi: Tìm mã SQLState (thường gồm 5 ký tự chữ và số).
-
Phân tích ngữ cảnh: Xem XID của luồng gây lỗi và kiểm tra xem có hiện tượng tranh chấp khóa (Lock contention) hay tràn bộ nhớ không.
-
Mô phỏng lại: Trích xuất câu lệnh SQL từ log (nếu có) và chạy thử trên DBeaver/
ijđể xem lỗi có lặp lại không.
Khi đã phân tích được log và hiểu hệ thống đang làm gì, bước tiếp theo để giải quyết tình trạng "chậm chạp" là nhìn sâu vào cách Derby phân giải một câu lệnh SQL.
All Rights Reserved