大意了,误用了MyBatis的$符号

复盘

近期有一个小业务需求,非常简单,本质就是增加几个过滤参数,可以透传给数据库就可以了。

代码使用MyBatis作为ORM框架

原始SQL如下

<select id="listDevices" resultType="DeviceDO">
  select device_uuid as deviceUUID, client_type as clientType
    from tb_device
    order by gmt_modified desc
</select>

上面没有过滤条件,本次改造是增加client_type的过滤,由于可能存在多个client_type,故需要使用MyBatis的foreach用法构造in条件。当时偷了个懒,直接从现有代码库里面copy了一份做了改动。

第一版改造如下:

<select id="listDevices" resultType="DeviceDO">
  select device_uuid as deviceUUID, client_type as clientType
    from tb_device
    where client_type in <foreach collection="list" index="index" item="item" open="(" close=")" separator=",">
		${item}</foreach>
    order by gmt_modified desc
</select>

关于foreach用法可以参照:https://juejin.cn/post/6844903886575108110

自以为应该没有问题,就屁颠屁颠的部署服务到预发环境了,结果报错了。

MyBatis的异常:

Unknown column 'android' in 'where clause'] with root cause

奇怪,怎么会把android当做了列呢,这明明是查询条件才对。从日志里面又捞取了一下执行的SQL,终于发现端倪,原来传入到的条件并没有添加""。

select device_uuid as deviceUUID, client_type as clientType       
from tb_device
where client_type in  (android , iOS )
order by gmt_modified desc

那就再检查一下代码吧,把自己的代码和原来copy的代码仔细做了一下对比,并未发现异常,奇怪+1。

那就再检查一下对应的字段类型吧,发现原来正常工作的类型是int,所以即使不加引号也可以正常运行。但是这里的client_type是varchar类型,如果不加引号那就会报错。

所以问题来了,为什么没有添加引号呢? 还是检查一下MyBatis的Mapper文件,发现犯了一个巨大的错误,其他条件地方使用的是#+变量名,这里使用了$+变量名,那就替换一下吧。

更新后SQL:

<select id="listDevices" resultType="DeviceDO">
  select device_uuid as deviceUUID, client_type as clientType
    from tb_device
    where client_type in <foreach collection="list" index="index" item="item" open="(" close=")" separator=",">
		#{item}</foreach>
    order by gmt_modified desc
</select>

替换以后执行就正常了。

==>  Preparing: select device_uuid as deviceUUID, client_type as clientType from tb_device where client_type in ( ? , ? ) order by gmt_modified desc 
==> Parameters: android(String), iOS(String)
<==      Total: 0

延伸

关于MyBatis #和$的区别,可以参照一下这个https://segmentfault.com/a/1190000004617028

提取一下文章关键信息,mybatis 在对 sql 语句进行预编译之前,会对 sql 进行动态解析。

  • #{ } 解析为一个 JDBC 预编译语句(prepared statement)的参数标记符,能使用#{ }的地方就用#{ }
  • ${ } 仅仅为一个纯碎的 string 替换,在动态 SQL 解析阶段将会进行变量替换,表名作为变量时,必须使用 ${ }。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

51iwowo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值