Bẫy khi nâng cấpViệc nâng cấp từ một cơ sở dữ liệu cũ như MySQL 5.6 lên phiên bản 8.0 thường mang lại cảm giác cải thiện rõ rệt về hiệu suất. Tuy nhiên, nhiều nhà phát triển gặp trở ngại khi chạy migration hoặc import các bản dump SQL cũ. Đột nhiên, một lệnh ALTER TABLE đơn giản thất bại với một lỗi gây ức chế:
ERROR 1067 (42000): Invalid default value for 'created_at'
Lỗi này thường nhắm vào các cột TIMESTAMP hoặc DATETIME sử dụng '0000-00-00 00:00:00' làm giá trị mặc định. Mặc dù điều này đã hoạt động trong nhiều năm ở các môi trường cũ, các phiên bản MySQL hiện đại bảo vệ tính toàn vẹn dữ liệu chặt chẽ hơn nhiều.
Nguyên nhân gốc rễ: Strict ModeĐây không phải là lỗi trong mã nguồn của bạn. Đó là kết quả của việc MySQL chuyển hướng sang kiểm tra dữ liệu nghiêm ngặt hơn. Bắt đầu từ phiên bản 5.7, ra mắt vào năm 2015, MySQL đã bật "Strict Mode" theo mặc định. Hai SQL mode cụ thể gây ra lỗi 1067 này là:
- NO_ZERO_IN_DATE: Ngăn chặn các ngày có năm hợp lệ nhưng tháng hoặc ngày bằng không (ví dụ: 2023-00-01).- NO_ZERO_DATE: Cấm hoàn toàn ngày giả
0000-00-00 00:00:00.Các ứng dụng cũ thường sử dụng các ngày 'bằng không' này làm giá trị tạm thời (placeholder). MySQL hiện đại coi chúng là những giá trị không hợp lệ về mặt logic. Khi bạn cố gắng tạo bảng với các giá trị mặc định này, engine sẽ chặn thao tác để ngăn dữ liệu hỏng hoặc vô nghĩa lọt vào các hàng của bạn.
Cách khắc phục nhanh: Theo Session (Tạm thời)Bạn có thể cần chạy migration một lần hoặc import bản dump SQL dung lượng 500MB mà không muốn cấu hình lại toàn bộ máy chủ. Trong những trường hợp này, bạn có thể tạm thời nới lỏng các quy tắc cho session cơ sở dữ liệu hiện tại. Chạy lệnh này trước script chính của bạn:
-- Xem cài đặt hiện tại của bạn
SELECT @@sql_mode;
-- Vô hiệu hóa tính nghiêm ngặt về ngày cho session này
SET session sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
Bằng cách loại bỏ NO_ZERO_IN_DATE và NO_ZERO_DATE khỏi chuỗi, bạn yêu cầu MySQL tạm bỏ qua quy tắc này chỉ trong lần này. Điều này cho phép các ngày 'bằng không' được chấp nhận mà không báo lỗi.
Cách khắc phục vĩnh viễn: Cấu hình máy chủĐể đảm bảo lỗi này không quay lại sau khi khởi động lại máy chủ, bạn phải cập nhật tệp cấu hình toàn cục. Thường là my.cnf trên Linux hoặc my.ini trên Windows.
Bước 1: Tìm tệp cấu hình của bạn- Ubuntu/Debian: /etc/mysql/mysql.conf.d/mysqld.cnf- CentOS/RHEL: /etc/my.cnf- Windows (XAMPP): C:\xampp\mysql\bin\my.ini### Bước 2: Sửa đổi SQL ModeTìm phần [mysqld]. Nếu dòng sql_mode đã tồn tại, hãy chỉnh sửa nó. Nếu không, hãy thêm vào. Đảm bảo giá trị không bao gồm hai mode "ZERO" đã đề cập ở trên.
[mysqld]
sql_mode = "ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"
Bước 3: Khởi động lại dịch vụÁp dụng các thay đổi bằng cách khởi động lại MySQL daemon:
# Dành cho người dùng Linux
sudo systemctl restart mysql
# Dành cho người dùng macOS (Homebrew)
brew services restart mysql
Cách tiếp cận chuyên nghiệp: Cập nhật SchemaVô hiệu hóa strict mode là một giải pháp tình thế, nhưng nó không phải là giải pháp "sạch" nhất. Cách tốt nhất là cập nhật schema của bạn để xử lý các ngày trống một cách chính xác. Các cơ sở dữ liệu hiện đại nên sử dụng NULL hoặc thời gian hiện tại thay vì một chuỗi các số không.
Thay vì sử dụng giá trị mặc định không hợp lệ:
-- Lệnh này sẽ thất bại trong Strict Mode
ALTER TABLE users ADD COLUMN created_at DATETIME DEFAULT '0000-00-00 00:00:00';
Hãy thử một trong những lựa chọn thay thế hiện đại sau:
-- Lựa chọn A: Cho phép NULL (Khuyến nghị cho các ngày không bắt buộc)
ALTER TABLE users ADD COLUMN created_at DATETIME DEFAULT NULL;
-- Lựa chọn B: Sử dụng timestamp hiện tại (Tốt nhất cho lịch sử hệ thống)
ALTER TABLE users ADD COLUMN created_at DATETIME DEFAULT CURRENT_TIMESTAMP;
Xác minhXác nhận việc khắc phục bằng cách đăng nhập vào terminal MySQL và kiểm tra trạng thái toàn cục:
SELECT @@GLOBAL.sql_mode;
Nếu chuỗi đầu ra không chứa NO_ZERO_DATE, các lệnh CREATE và ALTER của bạn giờ đây sẽ thực thi trơn tru.
Mẹo chuyên nghiệp để thành côngDữ liệu cũ thường chứa các timestamp "bẩn" không tuân theo tiêu chuẩn ISO. Tôi khuyên bạn nên sử dụng Timestamp Converter trên ToolCraft để xác minh xem một timestamp kiểu số nguyên có chuyển đổi sang ngày tháng hợp lệ hay không trước khi thực hiện chèn dữ liệu hàng loạt. Nó giúp tiết kiệm hàng giờ đồng hồ debug lỗi 'Invalid value'.
Hãy kiểm tra cả framework ứng dụng của bạn. Ví dụ, Laravel mặc định để 'strict' => true trong config/database.php. Ngay cả khi bạn thay đổi cài đặt máy chủ, framework có thể ghi đè chúng trong giai đoạn kết nối. Nếu lỗi vẫn còn, hãy đảm bảo cấu hình DB ở cấp độ ứng dụng khớp với độ linh hoạt mới của máy chủ.

