如何處理“MysqlDataTruncation:資料截斷:列資料太長”
1. 概述
Java 資料庫連線 (JDBC) 應用程式介面 (API) 提供了一組類別和介面。我們可以使用它們連接到關聯式資料庫等資料來源並執行 SQL 語句。我們使用 MySQL 資料庫特定的 JDBC 驅動程式com.mysql.cj.jdbc.Driver
,當我們想要連接到 MySQL 時,它會實作此 API。
在執行SQL語句時,我們可能會遇到異常訊息: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Data too long for column
。
在本教程中,我們將學習如何解決此異常。
2. 架構設定
除了我們可能已經使用的開發環境之外,我們不需要任何特殊的設定。我們將討論使用 JUnit 5 整合測試和 Apache Maven 作為建置工具來解決此異常。為了進行演示,我們將使用University
資料庫中的Department
表。此外,我們將在執行 SQL 語句時使用表列code
。讓我們找到該表的表定義,以便知道可以添加的資料的大小:
DESC department;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| name | varchar(50) | YES | | NULL | |
| code | varchar(4) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
值得注意的是, code
列定義僅允許使用大小為4
或更小的varchar
。
3. 異常原因
當我們嘗試插入或更新超出列定義設定的最大列大小的列資料時,我們會收到MysqlDataTruncation
異常。這個異常只能在運行時發生,即當我們運行應用程式時。此外,它只能在特定的資料操作語言 (DML) 語句中發生。
3.1.可能導致異常的語句
當我們使用 INSERT SQL 語句向列新增資料時,會出現此異常。為了用對應的 SQL 範例進行示範,當我們嘗試新增新的Department
表格行,其中code
列大小超過 4 時,我們會收到以下 SQL 錯誤:
INSERT INTO
DEPARTMENT(id, name, code)
VALUES(6, "Data Science", "DATSCI");
ERROR 1406 (22001): Data too long for column 'code' at row 1
無論 INSERT 語句是在 MySQL 客戶端 shell 中還是在 JDBC 應用程式中運行,我們都會收到錯誤/異常。
此外,當使用 UPDATE SQL 語句時,我們可能會遇到此異常。為了用相應的 SQL 範例進行演示,我們嘗試更新Department
表中的一行數據,其中更新後的code
列大小超過 4:
UPDATE department
SET code = 'COMPSCI'
WHERE id = 1;
ERROR 1406 (22001): Data too long for column 'code' at row 1
事實上,我們得到了一個 SQL 錯誤。
3.2.運行 JUnit 測試
讓我們示範如何在 Java 應用程式中取得MysqlDataTruncation
異常:
`@Test
void givenTableInsert_whenDataTruncationExceptionThrown_thenAssertionSucceeds()
throws SQLException, ClassNotFoundException {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/university?" +"user=root");
Statement stmt = conn.createStatement ();
Exception exception = assertThrows(SQLException.class, () -> {
stmt.execute ("INSERT INTO DEPARTMENT(id, name, code) VALUES(6, 'Data Science', 'DATSCI')");
});
String expectedMessage = "Data truncation: Data too long for column";
String actualMessage = exception.getMessage();
assertTrue(actualMessage.contains(expectedMessage));
}`
此外,確切的異常訊息包括列名稱。
4. 如何修復異常
我們透過使用兩個選項之一來修復異常。
4.1.減少資料大小以匹配列定義
我們應該減少新增的列資料大小以符合列定義。在引用的 INSERT SQL 語句範例中,我們應該新增一個新資料行,其中程式碼列資料不超過 4:
INSERT INTO
DEPARTMENT(id, name, code)
VALUES(6, "Data Science", "DS");
同樣,在 UPDATE SQL 語句的參考範例中,我們應該為code
列資料提供不超過 4 的更新列值:
UPDATE department
SET code = 'CSCI'
WHERE id = 1;
此外,我們可以在將 SQL 語句包含到 JDBC 應用程式之前在 MySQL 用戶端中驗證它們。
4.2.更改列定義
當我們不想減少新增或更新的列資料的大小時,我們應該更改表的結構。更準確地說,我們應該增加生成異常的列大小。我們可以使用 ALTER TABLE SQL 語句來完成此操作:
ALTER TABLE DEPARTMENT
CHANGE COLUMN code
code VARCHAR(10);
之後,當我們執行相同的 INSERT 和 UPDATE SQL 語句時,無論是在 MySQL 客戶端或 JDBC 應用程式中,我們都不會收到錯誤/例外。但是,我們應該記住,雖然我們可以增加列大小來添加更多數據,但一旦添加了更大的對象,我們就無法減少列大小。為了進行演示,讓我們嘗試將code
列大小增加到 10 並添加更大尺寸的列資料後將其減少回 4:
ALTER TABLE DEPARTMENT
CHANGE COLUMN code
code VARCHAR(4);
ERROR 1265 (01000): Data truncated for column 'code' at row 6
因此,只有當後續資料修改需要時,我們才應該更改列定義。
4.3.使用 JUnit 測試驗證修復
讓我們驗證一下使用所討論的兩個選項之一是否可以修復MysqlDataTruncation
異常。我們為相同測試類別MySQLDataTruncationUnitTest
新增第二個測試方法,以執行另一個 JUnit 整合測試。相應地,第二種測試方法是給表插入(用INSERT運行)。執行此語句時,請確保不會引發異常。這次我們使用斷言assertDoesNotThrow()
:
`@Test
void givenTableInsert_whenStatementRun_thenEnsureNoExceptionThrown() throws SQLException, ClassNotFoundException {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/university?" + "user=root");
Statement stmt = conn.createStatement();
assertDoesNotThrow(() -> {
stmt.execute ("INSERT INTO DEPARTMENT(id, name, code) VALUES(6, 'Data Science', 'DS')");
});
}`
當我們使用範例表執行 JUnit 測試時,兩個測試都應該通過。
5. 結論
在本文中,我們學習如何修復com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Data too long for column
異常問題。
我們有兩個選項來修復此異常。當我們不想減少新增的列資料大小時,可以改變表結構。我們這樣做是為了增加列定義中的列大小。但是,當無法變更表結構時,我們應該減少新增的資料大小以符合列大小。
與往常一樣,本文中使用的範例腳本可在 GitHub 上取得。