1、概览 {#1概览}
Java 数据库连接(JDBC)应用编程接口(API)提供了一系列类和接口。我们可以使用它们连接关系数据库等数据源并运行 SQL 语句。
以流行的 MYSQL 为例,当我们需要连接到 MySQL 时,就需要使用 MySQL 数据库的专用 JDBC 驱动程序: com.mysql.cj.jdbc.Driver
,该驱动实现了 JDBC API。
在运行 SQL 语句时,我们可能会遇到异常:"com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Data too long for column"。
本文将带你了解出现此异常的原因,以及解决办法。
2、Schema 设置 {#2schema-设置}
首先,创建如下关系表 department
:
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、异常原因 {#3异常原因}
当我们尝试插入或更新超过列定义所设置的最大列大小的列数据时,会出现 MysqlDataTruncation 异常。这种异常只能在运行时发生,即我们运行应用程序时。此外,它只能在特定的数据处理语言(DML)语句中出现。
3.1、可能导致异常的语句 {#31可能导致异常的语句}
当我们使用 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
一样的,还是会出现这个异常。
3.2、JUnit 测试 {#32junit-测试}
在 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修复异常}
修复这个异常一般有两种办法。
4.1、减小数据大小 {#41减小数据大小}
可以减少添加的列数据大小,使其与列定义相匹配。在 INSERT
SQL 语句的示例中,添加一条新数据行,其中 code
列数据大小不超过 4
:
INSERT INTO
DEPARTMENT(id, name, code)
VALUES(6, "Data Science", "DS");
同样,在 UPDATE
SQL 语句示例中,我们应该为 code
列数据提供一个不超过 4 的更新列值:
UPDATE department
SET code = 'CSCI'
WHERE id = 1;
我们可以先在 MySQL 客户端中验证 SQL 语句,然后再将其复制到 JDBC 应用中。
4.2、更改列定义 {#42更改列定义}
如果不能减少添加或更新的列数据的大小时,可以改变表的结构。更确切地说,应该增加产生异常的列的大小。我们可以使用 ALTER TABLE
SQL 语句来做到这一点:
ALTER TABLE DEPARTMENT
CHANGE COLUMN code
code VARCHAR(10);
然后,当我们在 MySQL 客户端或 JDBC 应用中运行相同的 INSERT
和 UPDATE
SQL 语句时,就不会出现错误/异常了。不过,要记住,虽然我们可以增加列的大小来添加更多的数据,但一旦我们添加了更大的对象,就不能再减少列的大小了。为了演示,让我们在将代码列的大小增加到 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 测试验证修复效果 {#43通过-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、总结 {#5总结}
本文介绍了如何解决 "com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Data too long for column" 异常。
总的来说,有两种方式。要么减少数据的大小,要么增大表中列表的大小约束。
Ref:https://www.baeldung.com/java-mysqldatatruncation-data-truncation-data-too-long-for-column