使用mybatis遇到的一个Sql语句小坑

本文深入探讨了在使用MyBatis框架时遇到的Mapper与Provider问题,特别是当使用HashMap传递数据并生成SQL语句时出现的意外情况。通过对mybatis源码的分析,揭示了ParamNameResolver类中导致参数异常包装的机制,并提供了正确的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在项目中使用到了mybatis 作为数据库连接,由于自己对于mybatis 不熟悉的原因导致使用mapper和Provider 生产SQL语句是,发生一些问题。

目的:
我又一个work类, 对应mysql 中的一张数据表 work,现在需要使用insert语句下个数据库插入数据。

实现方案:
前端接口使用一个 hashmap 承载 work中的数据(没有自定义数据结构),
Mapper中的代码如下

 @InsertProvider(type= WorksProcider.class,method = "insertWork")
 int insertWork( @Param("workInfo")Map<String, String>);

WorksProcider 中 生产sql语句,为了偷懒,map中的key和数据库中的列名一一对应,直接想遍历映射:

 public String insertWork(Map<String, String> workInfo) {
        String sql = "insert CARTOON_WORK (" + Joiner.on(",").join(workInfo.keySet()) + ") values (" + Joiner.on(",").join(workInfo.values())
                + ");";
        return sql;
    }

问题:
神奇的问题就来了 ,运行时,provider组装sql前 workInfo 是这样的
provider错误
和我想的完全不一样,怎么会这么包装呢?

分析:
通过查询网上的其他资料,和debug跟随源码,找到问题所在
mybatis类中,ParamNameResolver 负责生成参数,有这么一段代码

int i = 0;
for (Map.Entry<Integer, String> entry : names.entrySet()) {
        param.put(entry.getValue(), args[entry.getKey()]);
        // add generic param names (param1, param2, ...)
        final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
        // ensure not to overwrite parameter named with @Param
        if (!names.containsValue(genericParamName)) {
          param.put(genericParamName, args[entry.getKey()]);
        }
        i++;
 }

上面的 if (!names.containsValue(genericParamName)) 这段代码就是产生上面结果的原因,mybatis 会将所有参数加入一份复制,方便后续处理。

正常使用maybatis 的方式应该是这种模式 使用#{work.uid} 这种模式

 public String insertWorkInfo(@Param("work") Work work) {
        return new SQL() {{
            INSERT_INTO("Work");
            VALUES("uid", "#{work.uid}");
            VALUES("title", "#{work.title}");
            VALUES("tel", "#{work.tel}");
            VALUES("address", "#{work.address}");
        }}.toString();
    }

再最终执行sql语句之前,mybatis 会根据#{work.uid} 匹配,到参数取对应的值。

而我们的程序中为了偷懒,绕过了mybatis的这个过程,直接产生最终的sql语句,又使用了mybatis框架进行传参,导致 最终生成的sql语句错误。

总结:
问题产生的根源还是来自于自己对mybatis的不熟悉,然后又自作聪明,不按照正常的方式使用mybatis,导致的错误。

解决方案:
1、老老实实按照mybatis的常规使用方式,通过#{work.address} 将参数传入sql语句,使用mybatis框架自动处理
2、想偷懒也可以,知道上述过程之后, 只要将@Param(“work”) 注解去掉之后,就不会使用mybaitis带来的问题,直接能拿到自己想要的参数(十分不推荐,都这样了,还不如不使用框架)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值