需求背景:数据表中有物理主键id,按照每次会话保存笔记,这里
session_id
作为每次会话的凭证,所以每次会话中可能会不断更新笔记,笔记存在就更新笔记,不存在就插入笔记
我想大家都会用
insert into 表名(字段1,字段2,...) values(值1, 值2,...) on duplicate key update 字段1=值1, 字段2=值2...
上面语法在mysql
直接执行sql
语句是没问题的,但是mybatis
就有大坑。我个人完全不推荐这么用等号赋值,而是用values
,在文章末尾会给出推荐写法。
该语句是基于唯一索引或主键使用,比如一个字段session_id
被加上了unique index
,并且表中已经存在了该session_id
的记录值,那么插入就会更新。如果是物理主键id
,那就参数需要带上这个id
,不然id
递增就会成为新记录
INSERT INTO my_table (user_id, kyc_info, todo_info) VALUES ("u123","客户信息","笔记")
ON DUPLICATE KEY UPDATE kyc_info= "客户信息", todo_info="笔记";
当插入session_id
这个唯一索引重复的记录的时候,更新kyc_info
,todo_info
,如果是新记录,就直接插入。
其实这就相当于
代码语言:javascript复制-- 如果session_id相同代表是同一次会话,需求是笔记以会话为单位,一次会话不管怎么保存只能有一个笔记。
UPDATE 表名 SET kyc_info="客户信息", todo_info="笔记" WHERE session_id="huihua123";
直接运行上面这个sql
一点问题都没有,那简直看起来正确极了,但是用到mybatis
,就一直报错
<insert id="insertOrUpdateByPrimaryKeySelective" parameterType="你的entity实体对象">
insert into 表名
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="userId!= null">
user_id,
</if>
<if test="kycInfo!= null">
kyc_info,
</if>
<if test="todoInfo!= null">
todo_info,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="userId!= null">
#{userId,jdbcType=VARCHAR},
</if>
<if test="kycInfo!= null">
#{kycInfo,jdbcType=VARCHAR},
</if>
<if test="todoInfo!= null">
#{todoInfo,jdbcType=VARCHAR},
</if>
</trim>
ON DUPLICATE KEY UPDATE
kyc_info= #{kycInfo,jdbcType=VARCHAR},
todo_info=#{todoInfo,jdbcType=VARCHAR}
</insert>
结果一直报错:
SQLException: No value specified for parameter 4
你甚至惊奇的发现你只传了3个参数却提示没找到第4个参数。
问题出在这里
代码语言:javascript复制 ON DUPLICATE KEY UPDATE
kyc_info= #{kycInfo,jdbcType=VARCHAR},
todo_info=#{todoInfo,jdbcType=VARCHAR}
你应该写成
代码语言:javascript复制 ON DUPLICATE KEY UPDATE
kyc_info= values(kyc_info),
todo_info=values(todo_info)
结果就正确了。
综上,sql语句就应该写成
insert into 表名(字段1,字段2,...) values(值1, 值2,...) on duplicate key update 字段1=values(字段1), 字段2=values(字段2)
而不是
insert into 表名(字段1,字段2,...) values(值1, 值2,...) on duplicate key update 字段1=值1, 字段2=值2...
后者只有sql
单独运行可以,mybatis
运行报错。
前者不管单独运行还是mybatis
执行都是ok
的
所以下面就不推荐这么写
代码语言:javascript复制INSERT INTO my_table(user_id, kyc_info, todo_info) VALUES ("u123","客户信息","笔记")
ON DUPLICATE KEY UPDATE kyc_info= "客户信息", todo_info="笔记";
推荐写法如下:
代码语言:javascript复制INSERT INTO my_table(user_id, kyc_info, todo_info) VALUES ("u123","客户信息","笔记")
ON DUPLICATE KEY UPDATE kyc_info= values(kyc_info), todo_info=values(todo_info);
亲身经历什么叫一个bug
找一天。老铁们点点关注,给你们踩坑了!