处理 MySQL 异常:“MysqlDataTruncation: Data truncation: Data too long for column”

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 设置

首先,创建如下关系表 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、异常原因

当我们尝试插入或更新超过列定义所设置的最大列大小的列数据时,会出现 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

一样的,还是会出现这个异常。

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 语句的示例中,添加一条新数据行,其中 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、更改列定义

如果不能减少添加或更新的列数据的大小时,可以改变表的结构。更确切地说,应该增加产生异常的列的大小。我们可以使用 ALTER TABLE SQL 语句来做到这一点:

ALTER TABLE DEPARTMENT 
CHANGE COLUMN code 
code VARCHAR(10);

然后,当我们在 MySQL 客户端或 JDBC 应用中运行相同的 INSERTUPDATE 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 测试验证修复效果

现在,来验证一下上述两个方法是否能修复 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” 异常。

总的来说,有两种方式。要么减少数据的大小,要么增大表中列表的大小约束。


Ref:https://www.baeldung.com/java-mysqldatatruncation-data-truncation-data-too-long-for-column