Sau khi xác nhận, đúng là trường này không tồn tại - game bắn cá

Mục lục

Hôm nay, một dự án trực tuyến đã gặp lỗi 500. Trong nhật ký Laravel, có thông báo như sau:

Illuminate/Database/QueryException với thông điệp 'SQLSTATE[42S22]: 
Không tìm thấy cột: 1054 Cột 'is_charge' không tồn tại trong 'danh sách trường' 
(SQL: cập nhật `some_categories` đặt `lft` = trường hợp khi `lft` >= 29 thì `lft`+2 nếu không thì `lft` kết thúc, `rgt` = trường hợp khi `rgt` >= 29 thì `rgt`+2 nếu không thì `rgt` kết thúc ở đâu (`lft` >= 29 hoặc `rgt` >= 29))'

Khi thêm menu cấp mới, hệ thống báo lỗi khi cập nhật các giá trị left và right của các nút lịch sử. Tuy nhiên, điều kỳ lạ là câu lệnh SQL không hề chứa trường ‘is_charge’, nhưng vẫn tiếp tục xuất hiện lỗi:

Không tìm thấy cột: 1054 Cột 'is_charge' không tồn tại trong 'danh sách trường'

Lỗi này khá phổ biến, thường xảy ra khi bảng dữ liệu trên môi trường sản xuất chưa được đồng bộ hóa với các trường mới, dẫn đến thiếu sót các trường cần thiết. Nhưng làm sao một câu lệnh SQL hoàn toàn không liên quan lại gây ra lỗi này?

Loại trừ vấn đề từ Laravel

Để loại trừ khả năng lỗi đến từ các thư viện phụ thuộc của Laravel, tôi đã thử thực hiện các câu lệnh trực tiếp trên dòng lệnh MySQL:

mysql> cập nhật some_categories đặt is_charge = 1 ở đâu id = 241;
LỖI 1054 (42S22): Không tìm thấy cột 'is_charge' trong 'danh sách trường'
mysql> cập nhật some_categories đặt type = 1 ở đâu id = 241;
LỖI 1054 (42S22): Không tìm thấy cột 'is_charge' trong 'danh sách trường'

Rõ ràng, tất cả đều gặp cùng một lỗi. Những câu lệnh SQL đơn giản như vậy mà vẫn báo lỗi, chứng tỏ rằng đây không phải là lỗi do cú pháp.

Tôi nghi ngờ rằng bảng này có thể đang sử dụng trigger của MySQL.

Kiểm tra trigger của MySQL

SELECT * FROM information_schema.TRIGGERS \G;

Quả thật, tôi đã tìm thấy trigger tương ứng:

TRIGGER_CATALOG: def
      TRIGGER_SCHEMA: db1
       TRIGGER_NAME: some_categories_insert
    EVENT_MANIPULATION: CHÈN
   EVENT_OBJECT_CATALOG: def
    EVENT_OBJECT_SCHEMA: db1
    EVENT_OBJECT_TABLE: some_categories
       ACTION_ORDER: 1
     ACTION_CONDITION: NULL
     ACTION_STATEMENT: BEGIN CHÈN VÀO db2.some_categories (id,name,type,link,page_id,page_id,parent_id,lft,rgt,depth,image,created_at,updated_at,is_charge) GIÁ TRỊ (NEW.id$,NEW.name,NEW.type,NEW.link,NEW.page_id,NEW.parent_id,NEW.lft,NEW.rgt,NEW.depth,NEW.image,NEW.created_at,NEW.updated_at,NEW.is_charge);
END

Vấn đề rõ ràng rồi - cơ sở dữ liệu db2 mà trigger đang đồng bộ không có trường ‘is_charge’. Sau khi xác nhận, đúng là trường này không tồn tại.

Vấn đề đã được giải quyết.

Cuộc chiến chưa kết thúc

Sau khi thêm trường mới, lỗi trước đó đã không còn xuất hiện. Tuy nhiên, một lỗi khác lại xuất hiện:

[2019-05-13 22:47:49] production.ERROR: SQLSTATE[21S01]: 
Danh sách giá trị chèn không khớp với danh sách cột: 
1136 Số lượng cột không khớp với số lượng giá trị tại dòng 1
 (SQL: chèn vào `some_categories` (`name`, `parent_id`, `lft`, `rgt`, `updated_at`, `created_at`) giá trị (kiểm tra kiểm tra, 225, 29, 30, 2019-05-13 22:47:49, 2019-05-13 22:47:49)) 

Lỗi “Column count doesn’t match value count” rất dễ hiểu - danh sách tên cột không khớp với danh sách giá trị. Tôi đã kiểm tra câu lệnh SQL nhưng không phát hiện vấn đề nào, cho nên chắc chắn lỗi nằm ở trigger.

Trong dòng lệnh MySQL, tôi đã thử nghiệm và phát hiện rằng trigger cũng gây ra lỗi này:

mysql> chèn vào some_categories (name, `type`) giá trị ('test', 1);
LỖI 1136 (21S01): Số lượng cột không khớp với số lượng giá trị tại dòng 1

Do quá mệt mỏi vào ban đêm, tôi đã không thể phát hiện ra sai sót trong trigger. Cuối cùng, tôi quyết định đi ngủ.

Sáng hôm sau, tôi ngay lập tức phát hiện rằng hai trường ‘page_id’ đã bị lặp lại trong trigger. Sau khi sửa chữa, mọi thứ đã hoạt động bình thường trở lại.

Kết luận

  • Khi kiểm tra các vấn đề về câu lệnh SQL trong MySQL, tốt nhất là thực hiện trực tiếp trên dòng lệnh MySQL để tránh sự can thiệp từ các yếu tố khác.
  • Nên hạn chế sử dụng trigger vì chúng dễ bị lãng quên.
  • Thông báo lỗi của MySQL đôi khi không đủ rõ ràng, đặc biệt là khi vấn đề xuất phát từ trigger. Điều này khiến tôi muốn thử nghiệm các hệ quản trị cơ sở dữ liệu khác.
  • Hiệu suất khi xử lý vấn đề vào nửa đêm rất thấp, không nên trông chờ vào việc rà soát thủ công trong những thời điểm này.