06月09, 2021

【工作踩坑】之mysql问题

最近不知道怎么回事,接连有同事踩坑,而且都是和Mysql有关,一个是执行delete语句导致全变数据删除,另一个是使用Mybatis封装的Wrapper更新表出问题导致


in子查询问题

前两天同事遇到一个Mysql删除语句问题,最终导致全表数据删除,接下来就给大家详细介绍下问题的原因和解决方法。

问题重现

在介绍问题之前,先问大家一个问题,现在库里有两张表user(用户表)、class(班级表),用户表有两个字段(id,name),班级表也有两个字段(id,type),然后执行以下sql:

delete from user where name in ( select name from class where id =1 )

大多数同学可能认为应该会报错,因为class表没有name字段,但事实真实这样吗?其实并不是,这条sql不但不会报错,而且会导致user表中所有数据将被删掉,有兴趣的同学可以自己试试。

Why

我们做技术的不只是要解决问题,更重要的是要知道问题的本质,这样才能使我们更加印象深刻。我们梳理下问题的本质:在in子查询中,不管是修改、插入或删除,子查询中字段在表中不存在时语句不会报错,但是如果子查询中的字段在外层表中没有,那么语句就会报错,比如把子查询中的name字段换成age:

delete from user where name in ( select age from class where id =1 )

执行这条语句就会报字段不存在的错误

总结一下造成问题的原因就是:在不使用表别名的前提下,如果in子查询中的字段在内表中找不到就会引用外表

Mybatis Wrapper 更新问题

这个同事遇到的问题是在使用wrapper更新的时候,有个条件字段的值为空,结果更新的时候mysql没有处理这个字段,导致多更新了很多记录,最终导致的结果是给几万人退了款(辛亏运营账户钱不多,不然真的要祭天了-_-)。

问题重现

我们还是以user表举例,假设user表有id、name、age、sex,然后需求是更新age=18岁并且sex=男的用户的name为‘aaa’,那么对应的sql语句应该是:

update user set name='aaa' where age=18 and sex='男'

使用wrapper执行如下:

 Wrappers.<User>lambdaUpdate()
                .set(User::getName, name)
                .eq(User::getAge, age)
                .eq(User::getSex,sex)

如果此时传入的sex值为null,那么最终的sql就变成了:

update user set name='aaa' where age=18

这样的话就会导致很多不应该修改的记录被修改

本文链接:http://blog.keepting.cn/blog//post/work_mysql_problem_01.html

-- EOF --

Comments