Cấu hình và quản lý SQL Mode trong MySQL để nâng cao tính toàn vẹn dữ liệu

cau hinh va quan ly sql mode trong mysql de nang cao tinh toan ven du lieu

Khi làm việc với MySQL, nếu một số cột trong bảng được khai báo với ràng buộc NOT NULL, bạn có thể gặp lỗi "Field 'FIELD_NAME' doesn't have a default value" nếu không chỉ định giá trị cho các cột đó trong câu lệnh INSERT. Nguyên nhân chính của lỗi này là do MySQL mặc định kích hoạt chế độ SQL hạn chế, được kiểm soát bởi tham số STRICT_TRANS_TABLES.

Nếu ứng dụng của bạn chạy trên một máy chủ mà chế độ này bị vô hiệu hóa, bạn có thể đối mặt với những lỗi tương tự. Vì việc thay đổi cấu trúc cơ sở dữ liệu có thể phức tạp và tiềm ẩn rủi ro, nên việc tắt STRICT_TRANS_TABLES chỉ nên được thực hiện nếu điều đó không làm ảnh hưởng đến logic vận hành của ứng dụng.

Ví dụ, giả sử bạn có một bảng payments trong hệ thống quản lý thanh toán. Người nhận có thể được trả bằng tiền mặt hoặc séc ngân hàng. Để lưu trữ thông tin giao dịch, hệ thống có thể yêu cầu thêm các cột như bank_namecheque_no – tuy nhiên, những cột này không cần thiết khi thực hiện thanh toán bằng tiền mặt.

Nếu hai trường này được thiết lập với ràng buộc NOT NULL, mọi giao dịch thanh toán bằng tiền mặt mà không có giá trị cho bank_name và cheque_no sẽ dẫn đến lỗi “Field 'FIELD_NAME' doesn't have a default value“. Trong tình huống này, tắt chế độ STRICT_TRANS_TABLES sẽ là giải pháp giúp MySQL chấp nhận bản ghi mà không gặp lỗi.

DataOnline sẽ hướng dẫn bạn cách tạo một cơ sở dữ liệu mẫu, thiết lập bảng có các cột với ràng buộc NOT NULL, thử nghiệm chèn dữ liệu để kiểm tra lỗi, và cuối cùng là tắt STRICT_TRANS_TABLES để đảm bảo dữ liệu được xử lý linh hoạt hơn trong ứng dụng MySQL của bạn.

Yêu cầu tiên quyết

Để thử nghiệm hướng dẫn này, hãy đảm bảo bạn có:

Tạo cơ sở dữ liệu mẫu

Bắt đầu bằng cách đăng nhập vào máy chủ của bạn. Sau đó, nhập lệnh dưới đây để mở giao diện dòng lệnh MySQL:

$ sudo mysql -u root -p

Khi được yêu cầu, hãy nhập mật khẩu root của máy chủ MySQL và nhấn Enter để tiếp tục. Sau đó, nhập lệnh sau để tạo một cơ sở dữ liệu mẫu:

mysql> CREATE DATABASE sample;

Chọn cơ sở dữ liệu sample:

mysql> USE sample;

Tiếp theo, bạn sẽ tạo bảng payments. Bảng này sẽ được sử dụng để ghi lại các thanh toán cho người nhận như nhân viên và nhà cung cấp. Trường payment_id là khóa chính, và giá trị của nó sẽ được thiết lập tự động do bạn đã bao gồm từ khóa AUTO_INCREMENT.

Trường payee sẽ lưu tên của người nhận thanh toán. Vì bạn có thể sử dụng nhiều phương thức thanh toán khác nhau, bạn sẽ sử dụng trường payment_method để phân biệt các hình thức thanh toán. Các trường bank_name và cheque_no là các trường tùy chọn, chỉ cần được chỉ định khi payment_method là BANKERS CHEQUE. Ngược lại, với thanh toán bằng CASH, các trường tùy chọn này sẽ được để trống (”).

Thiết lập bảng payments:

mysql> CREATE TABLE payments (
       payment_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
       payee VARCHAR(50),
       payment_method VARCHAR(50),
       bank_name VARCHAR(50) NOT NULL,
       cheque_no VARCHAR(50) NOT NULL
       ) ENGINE = InnoDB;

Sau khi cấu trúc cơ sở dữ liệu đã được thiết lập, bạn sẽ thử nghiệm với một số câu lệnh INSERT với cả chế độ hạn chế bật và tắt để xem các cài đặt này ảnh hưởng như thế nào đến các câu lệnh SQL của bạn.

Chèn bản ghi khi chế độ STRICT_TRANS_TABLES bật

Bắt đầu bằng cách chèn một bản ghi thanh toán hợp lệ được thực hiện bằng BANKERS CHEQUE. Đối với lệnh chèn này, bạn sẽ chỉ định giá trị cho tất cả các cột, bao gồm cả các cột bank_name và cheque_no, vì chúng là bắt buộc đối với thanh toán bằng BANKERS CHEQUE.

Chạy câu lệnh INSERT dưới đây:

mysql> INSERT INTO payments
       (
       payee,
       payment_method,
       bank_name,
       cheque_no
       )
       VALUES
       (
       'JOHN DOE',
       'BANKERS CHEQUE',
       'XYZ BANK',
       '111'
       );

Câu lệnh trên sẽ thực thi thành công mà không gặp vấn đề, và bạn sẽ nhận được thông báo tương tự như sau:

Query OK, 1 row affected (0.01 sec)

Tiếp theo, hãy thử INSERT một bản ghi thanh toán bằng CASH vào bảng payments. Lần này, không định nghĩa giá trị cho các cột bank_name và cheque_no. Theo logic nghiệp vụ của bạn, các trường này nên được bỏ qua vì không liên quan.

mysql> INSERT INTO payments (
       payee,
       payment_method
       )
       VALUES
       (
       'JOHN DOE',
       'CASH'
       );

Vì bạn không định nghĩa giá trị cho các cột bank_name và cheque_no – các cột được tạo với từ khóa NOT NULL – bạn sẽ nhận được lỗi sau:

ERROR 1364 (HY000): Field 'bank_name' doesn't have a default value

Mặc dù câu lệnh INSERT trên phù hợp với logic nghiệp vụ của bạn, nó đã thất bại. Nếu bạn đã nhập khẩu một cơ sở dữ liệu với nhiều bảng được định nghĩa theo cách này, bạn có thể gặp phải rất nhiều vấn đề. Nếu việc thay đổi cấu trúc cơ sở dữ liệu là không khả thi hoặc tốn nhiều thời gian, bạn có thể chọn vô hiệu hóa chế độ SQL hạn chế.

Kiểm tra và tắt chế độ sql_mode hạn chế

Đầu tiên, để vô hiệu hóa chế độ STRICT_TRANS_TABLES, hãy kiểm tra giá trị sql_mode mặc định bằng cách chạy lệnh dưới đây:

mysql> SELECT @@GLOBAL.sql_mode;

Bạn sẽ nhận được một giá trị dạng chuỗi phân cách bằng dấu phẩy. Trong giá trị đó, STRICT_TRANS_TABLES sẽ có mặt, nghĩa là chế độ này đang được bật.

+-----------------------------------------------------------------------------------------------------------------------+
| @@GLOBAL.sql_mode                                                                                                     |
+-----------------------------------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+-----------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

Để tắt chế độ này, bạn sẽ cần chỉnh sửa tệp cấu hình MySQL. Đầu tiên, thoát khỏi giao diện dòng lệnh MySQL:

mysql> QUIT;

Sau đó, mở tệp cấu hình /etc/mysql/my.cnf bằng nano:

$ sudo nano /etc/mysql/my.cnf

Thêm thông tin dưới đây vào tệp. Giá trị của sql_mode sẽ là giá trị bạn đã nhận được sau khi chạy lệnh SELECT @@GLOBAL.sql_mode; với phần STRICT_TRANS_TABLES đã bị loại bỏ:

[mysqld]
sql_mode = ONLY_FULL_GROUP_BY,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

Lưu và đóng tệp. Sau đó, khởi động lại máy chủ MySQL để áp dụng các thay đổi:

$ sudo systemctl restart mysql

Chèn bản ghi khi chế độ STRICT_TRANS_TABLES tắt

Trong bước này, bạn sẽ thử chèn các bản ghi mà không có giá trị cho tất cả các cột được định nghĩa và xem MySQL có bỏ qua lỗi “Field 'FIELD_NAME' doesn't have a default value” hay không.

Đăng nhập lại vào máy chủ MySQL:

$ sudo mysql -u root -p

Nhập mật khẩu của máy chủ MySQL và nhấn Enter để tiếp tục. Sau đó, kiểm tra giá trị sql_mode để xác nhận đã được cập nhật:

mysql> SELECT @@GLOBAL.sql_mode;

Kết quả đầu ra của bạn sẽ hiển thị một chuỗi giá trị phân cách bằng dấu phẩy mà không có STRICT_TRANS_TABLES, như ví dụ dưới đây:

+---------------------------------------------------------------------------------------------------+
| @@GLOBAL.sql_mode                                                                                 |
+---------------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+---------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

Chuyển sang cơ sở dữ liệu sample:

mysql> USE sample;

Chạy một câu lệnh INSERT cho thanh toán bằng CASH và lần này, không cung cấp giá trị cho các cột bank_name và cheque_no:

mysql> INSERT INTO payments
       (
       payee,
       payment_method
       )
       VALUES
       (
       'JOHN DOE',
       'CASH'
       );

Câu lệnh INSERT của bạn bây giờ sẽ thành công. Tuy nhiên, bạn sẽ nhận được một số cảnh báo nhẹ như được hiển thị trong kết quả sau:

Query OK, 1 row affected, 2 warnings (0.00 sec)

Để xem các cảnh báo cuối cùng, chạy lệnh:

mysql> SHOW WARNINGS;

Bạn sẽ thấy nguồn gốc của các cảnh báo như dưới đây, nhưng điều này không ảnh hưởng đến bản ghi:

+---------+------+------------------------------------------------+
| Level   | Code | Message                                        |
+---------+------+------------------------------------------------+
| Warning | 1364 | Field 'bank_name' doesn't have a default value |
| Warning | 1364 | Field 'cheque_no' doesn't have a default value |
+---------+------+------------------------------------------------+
2 rows in set (0.00 sec)

Hãy thử nhập một bản ghi thanh toán với phương thức thanh toán khác, chẳng hạn như PAYPAL:

mysql> INSERT INTO payments
       (
       payee,
       payment_method
       )
       VALUES
       (
       'JOHN DOE',
       'PAYPAL'
       );

Bản ghi cho PAYPAL sẽ được chèn thành công mà không gặp vấn đề:

Query OK, 1 row affected, 2 warnings (0.01 sec)

Chạy câu lệnh SELECT trên bảng payments để xác nhận các bản ghi đã có:

mysql> SELECT
       payment_id,
       payee,
       payment_method,
       bank_name,
       cheque_no
       FROM payments;

Kết quả trả về sẽ hiển thị tất cả các thanh toán như ví dụ dưới đây:

+------------+----------+----------------+-----------+-----------+
| payment_id | payee    | payment_method | bank_name | cheque_no |
+------------+----------+----------------+-----------+-----------+
|          1 | JOHN DOE | BANKERS CHEQUE | XYZ BANK  | 111       |
|          2 | JOHN DOE | CASH           |           |           |
|          3 | JOHN DOE | PAYPAL         |           |           |
+------------+----------+----------------+-----------+-----------+
3 rows in set (0.00 sec)

Ngay cả khi chế độ STRICT_TRANS_TABLES đã được tắt, bạn vẫn có thể thấy các bản ghi thanh toán của bạn được chèn vào bảng mà không vi phạm logic nghiệp vụ của ứng dụng.

Kết luận

Trong hướng dẫn này, bạn đã nắm được cách điều chỉnh giá trị của sql_mode để khắc phục lỗi “Field ‘FIELD_NAME’ doesn’t have a default value”. Hãy vận dụng kiến thức này để vô hiệu hóa chế độ STRICT_TRANS_TABLES trong trường hợp việc chỉnh sửa cấu trúc cơ sở dữ liệu không khả thi, giúp đảm bảo ứng dụng của bạn hoạt động trơn tru hơn.

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *