记一次Mybatis Update遇到的坑

记一次Mybatis Update遇到的坑

背景

最近遇到一个线上问题,由于接手老项目不久,对代码不熟悉,导致这个坑排查了很久才发现。说他是坑吧,其实也不算坑,只能说是由于前人对这个东西不够了解导致的。

简介

问题是这样的,在A表中,每次业务操作都会根据条件在A表中查询id,如果查询到了,就不执行插入,反之会执行插入,并且返回id,代码如下:

private Integer getOrAddxxxByName(String name) {
    Integer id = xxxDao.queryRCChannelId(name);
    if (id == null) {
        id = xxxDao.addRCChannel(name);
    }
    return id;
}

这段代码里最后返回的结果就是所谓的id,这个id又会在B表中做关联,乍眼一看,这段代码好像没什么问题,但是线上却产生了奇怪的现象,那就是新用户首次操作了和这段代码有关的功能时,在B表中都会出现一条关联id为1的数据,这就奇怪了,用户每次重新加入的数据,为啥给我返回个1,然后第二次操作又恢复正常了???

于是我点进了dao对应的addRCChannel方法,发现了问题,xml中对应方法实现是这样的

<insert id="addRCChannel">
    INSERT channel_info (`channel_name`) VALUES (#&#123;channelName&#125;);
</insert>

如果看到这儿你也没发现问题,那只能说明,你也被写代码的老哥带进去了!问题的原因就是因为insert方法每次返回的结果是成功的行数,也就是说,我们成功插入一条,那永远都是返回1,这就和上面方法的逻辑产生了冲突,他想要的是,每次返回成功之后的数据id

解决

文档

这时候自然就应该打开Mybatis的文档了,上面是这么说的:

插入语句的配置规则更加丰富,在插入语句里面有一些额外的属性和子元素用来处理主键的生成,而且有多种生成方式。

首先,如果你的数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),那么你可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置到目标属性上就 OK 了。例如,如果上面的 Author 表已经对 id 使用了自动生成的列类型,那么语句可以修改为:

可以看到,文档上对这两个字段进行了解释

按照我的理解,useGeneratedKeys这个属性默认为false,设置为true,他就会把插入的这条数据的id设置到keyProperty指定的列中,所以,上面xml只要改成下面这样


<insert id="addRCChannel" useGeneratedKeys="true" keyProperty="id">
    INSERT channel_info (`channel_name`) VALUES (#&#123;channelName&#125;);
</insert>

这时候,代码修改如下:

private Integer getOrAddxxxByName(String name) &#123;
    Integer id = xxxDao.queryRCChannelId(name);
    if (id == null) &#123;
        Channel channel = new Channel();
        channel.setChannelName(name);
        xxxDao.addRCChannel(channel);
        id = channel.getId();
    &#125;
    return id;
&#125;

这样,最后返回的结果就是数据的真实id了。

总结

这个问题看似简单,实际上需要对Mybatis很熟悉,至少要阅读过文档,而不是想当然的复制一段代码没有报错就是成功了,细节决定成败,每一个疏忽的小问题,到了线上都是不好的用户体验。


   转载规则

本文不允许转载。
 上一篇
在SpringMVC中优雅的拼接URL 在SpringMVC中优雅的拼接URL
在SpringMVC中优雅的拼接URL背景 在日常开发中常常会遇到拼接URL的情况,大多数时候可以手动拼接字符串来达到目的,但是这样的方式不够优雅,同时容易出错。其实SpringMVC中已经给我们提供好了工具,这个工具就是UriCompon
下一篇 
Mac上安装多个JDK并动态切换 Mac上安装多个JDK并动态切换
Mac上安装多个JDK并动态切换 本地已经安装了JDK8,现在需要安装JDK13,但是需要在两个JDK之间动态切换。 下载JDK13 首先在Oracle官网下载JDK13 https://www.oracle.com/technetwo
2019-12-27