在 Spring Boot + MyBatis/MyBatis-Plus 开发过程中,数据库操作是核心部分之一。然而,由于 SQL 语法、数据类型不匹配、约束冲突等问题,开发者经常会遇到 org.springframework.dao.DataIntegrityViolationException 异常。
本文将通过两个典型案例,深入分析 DataIntegrityViolationException 的常见原因,并提供完整的解决方案。同时,我们会结合代码示例,帮助读者理解如何避免类似问题。
DataIntegrityViolationException 是 Spring 框架在数据库操作失败时抛出的异常,通常由以下原因引起:
接下来,我们通过两个实际案例进行分析。
在执行以下 MyBatis XML 映射的 SQL 时,报错:
org.springframework.dao.DataIntegrityViolationException:
### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation:
Data truncation: Truncated incorrect DOUBLE value: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...'错误 SQL:
<update id="updateCookie">
update task_management set cookie = #{cookie}
<if test="creatorId != null">
and creator_id = #{creatorId}
</if>
</update>错误原因:
WHERE 关键字,导致 and creator_id = #{creatorId} 被解析为 cookie = (#{cookie} and creator_id = #{creatorId})。creatorId 进行逻辑运算,导致类型转换失败。错误 SQL 实际执行情况:
-- 错误的 SQL
UPDATE task_management SET cookie = ('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...' AND creator_id = 123);
-- 正确的 SQL 应该是
UPDATE task_management SET cookie = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...' WHERE creator_id = 123;<where> 标签<update id="updateCookie">
UPDATE task_management
SET cookie = #{cookie}
<where>
<if test="creatorId != null">
AND creator_id = #{creatorId}
</if>
</where>
</update><trim> 标签<update id="updateCookie">
UPDATE task_management
SET cookie = #{cookie}
<trim prefix="WHERE" prefixOverrides="AND">
<if test="creatorId != null">
AND creator_id = #{creatorId}
</if>
</trim>
</update>@Update("<script>" +
"UPDATE task_management SET cookie = #{cookie}" +
"<where>" +
" <if test='creatorId != null'>AND creator_id = #{creatorId}</if>" +
"</where>" +
"</script>")
void updateCookie(@Param("cookie") String cookie, @Param("creatorId") Long creatorId);始终在 UPDATE/DELETE 语句中使用 WHERE 条件,避免全表更新。
使用 MyBatis 动态 SQL 标签(<where>、<trim>)防止语法错误。
启用 SQL 日志,检查实际执行的 SQL:
logging.level.org.mybatis=DEBUG在插入数据时,报错:
org.springframework.dao.DataIntegrityViolationException:
### Error updating database. Cause: java.sql.SQLException:
Data truncated for column 'match_status' at row 1错误 SQL:
INSERT INTO customer_order (match_status) VALUES ('pending_verification');可能原因:
match_status 是 ENUM,但插入了不在枚举列表的值。match_status 是 TINYINT,但插入了字符串或超出范围的值(如 256)。match_status 是 VARCHAR(10),但插入了超长字符串(如 "pending_verification")。排查方法:
查看表结构:
DESC customer_order;检查 match_status 列的定义:
SHOW CREATE TABLE customer_order;match_status 是 ENUM如果 match_status 是 ENUM('pending', 'success', 'failed'),则只能插入这三个值之一:
ALTER TABLE customer_order
MODIFY COLUMN match_status ENUM('pending', 'success', 'failed') NOT NULL;代码调整:
customerOrder.setMatchStatus("success"); // 正确
// customerOrder.setMatchStatus("invalid_status"); // 错误match_status 是 TINYINT如果 match_status 是 TINYINT(0-255),则不能插入字符串或超出范围的值:
ALTER TABLE customer_order
MODIFY COLUMN match_status TINYINT UNSIGNED NOT NULL DEFAULT 0;代码调整:
customerOrder.setMatchStatus(1); // 正确
// customerOrder.setMatchStatus(256); // 错误(超出范围)
// customerOrder.setMatchStatus("pending"); // 错误(类型不匹配)match_status 是 VARCHAR 但长度不足如果 match_status 是 VARCHAR(10),但插入了更长的字符串:
ALTER TABLE customer_order
MODIFY COLUMN match_status VARCHAR(50); -- 扩大长度代码调整:
customerOrder.setMatchStatus("pending"); // 正确
// customerOrder.setMatchStatus("pending_verification"); // 可能被截断在数据库设计阶段明确字段类型和约束。
在代码中校验数据是否符合数据库约束。
使用日志监控 SQL 执行情况:
logging.level.org.springframework.jdbc=DEBUG问题类型 | 错误示例 | 解决方案 |
|---|---|---|
SQL 语法错误 | UPDATE ... SET col = val AND ... | 使用 <where> 标签 |
ENUM 不匹配 | 插入不在枚举列表的值 | 修改数据库或代码 |
数值超出范围 | TINYINT 插入 256 | 检查数据库范围 |
字符串超长 | VARCHAR(10) 插入 20 字符 | 扩大列长度或截断数据 |
查看数据库表结构:
DESC table_name;
SHOW CREATE TABLE table_name;启用 SQL 日志:
logging.level.org.mybatis=DEBUG
logging.level.org.springframework.jdbc=DEBUG在代码中校验数据:
if (value.length() > 10) {
throw new IllegalArgumentException("字段超长");
}DataIntegrityViolationException 是 Spring Boot 开发中常见的数据库异常,通常由 SQL 语法错误、数据类型不匹配或约束冲突引起。通过本文的分析和解决方案,希望读者能够更高效地定位和修复类似问题。
关键点回顾:
如果你有更多问题,欢迎在评论区交流!🚀