SpringBoot中MyBatis的MySQL UPDATE如何判断字段实际更新
问题原因
MyBatis的update方法返回值底层依赖JDBC驱动返回的行数统计结果,MySQL JDBC驱动默认返回的是WHERE条件匹配到的记录行数,而非字段值实际发生变更的行数。
你当前编写的SQL只要能通过email = #{email}匹配到user表中的对应记录,无论IF分支逻辑是否真的修改了groupId字段值,驱动都会将这条记录计入返回行数,因此无论是否产生实际变更方法都会返回1。
可用解决方案
方案1:修改JDBC连接参数(改造成本最低)
如果使用MySQL数据库,直接在JDBC连接URL后追加参数useAffectedRows=true,配置后驱动会将返回规则改为统计字段值实际发生修改的受影响行数,配置示例如下:
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/your_db_name?useUnicode=true&characterEncoding=utf8&useAffectedRows=true
配置完成后原有SQL即可符合预期:
- 当allGroup表存在传入的groupId,且目标用户当前groupId不等于传入值时:更新成功,返回1
- 当allGroup表不存在传入的groupId,或目标用户当前groupId已经等于传入值时:无实际字段修改,返回0
注意:如果项目中其他更新方法的业务逻辑依赖默认的「匹配行数」返回规则,修改全局JDBC参数前需要做好全量逻辑评估,避免影响其他业务。
方案2:调整SQL逻辑(无侵入性,推荐)
不需要修改全局配置,直接调整UPDATE语句的判断逻辑,将更新前置条件加到WHERE子句中,只有满足更新要求时才会匹配到记录:
@Update("UPDATE user SET groupId = #{groupId} " + "WHERE email = #{email} " + "AND EXISTS(SELECT 1 FROM allGroup WHERE groupId = #{groupId}) " + "AND (groupId <> #{groupId} OR groupId IS NULL)") int updateUserGroup(@Param("groupId") Integer groupId, @Param("email") String email);
该方案语义明确,不依赖任何驱动配置,逻辑判断规则:
- 同时满足「邮箱匹配用户存在」「传入groupId在allGroup表存在」「用户当前groupId和传入值不一致」三个条件时,才执行更新,返回1
- 其余场景无法匹配到待更新记录,直接返回0
注:条件中加OR groupId IS NULL是为了兼容用户groupId为NULL的场景,因为SQL中NULL值和任意值做<>判断都不会成立,会漏判更新场景。
方案3:业务层前置校验
可以在执行更新前先做两次校验:先查询allGroup表确认传入groupId存在,再查询目标用户的当前groupId是否和传入值一致,只有两个校验都通过时才执行更新操作,否则直接返回0。该方案会额外增加两次数据库查询,性能弱于前两种方案,非特殊场景不推荐使用。
内容的提问来源于stack exchange,提问作者Nathan
相关产品推荐
相关产品推荐

