mybatis框架中的queryWrapper的or查询,联想到MySQL中and 和or的关系
测试小姐姐发来删除设备的bug,删除设备之前需要统计处于运行中或故障中子设备的数量,统计的原生SQL应该是这样的:
SELECTCOUNT( 1 ) FROMtable_name WHERE( id = '679135XXXXXXX1212' AND ( STATUS = 1 OR STATUS = 2 ) AND isRemoved = 0)
服务端使用mybatis框架的QueryWrapper【query包装器】
来统计子设备,之前的查询语法是这样的:
public int method(String id, int isRemoved) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("id", id); queryWrapper.eq("status", DeviceConstant.DeviceStatus.WORK) .or().eq("status", DeviceConstant.DeviceStatus.FAULT); return mapper.selectCount(queryWrapper); }
但是生成出来的SQL语句是
SELECTcount(1) FROMtable_name WHERE( id = '679135XXXXXXX1212' AND STATUS = 1 OR STATUS = 2 AND isRemoved = 0);
正如我们所知道的那样,MySQL中的 and
的优先级高于or
,因而,上面的SQL语句可以转化为
SELECTcount(1) FROMtable_name WHERE( (id = 679135XXXXXXX1212 AND STATUS = 1 ) OR (STATUS = 1 AND isRemoved = 0) );
于是,就违背了我们最初的SQL语句,自然查询出来的有可能不对,导致统计的结果不对,因为这样的SQL语句表明:查询出设备Id等于‘679135XXXXXXX1212’且状态等于1,或者所有未移除的设备的状态等于2。
因此,mybatis的queryMapper的查询语法需要修改,如下:
public int method(String id, int isRemoved) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("id", id);queryWrapper.and(wrapper -> wrapper.eq("status", DeviceConstant.DeviceStatus.WORK) .or().eq("status", DeviceConstant.DeviceStatus.FAULT) ); return mapper.selectCount(queryWrapper); }
这种方式生成的SQL语句如下
SELECTCOUNT( 1 ) FROMtable_name WHERE( id = ? AND ( ( STATUS = ? OR STATUS = ? ) ) AND isRemoved = ? )
这样的SQL才是我们想要的查询语句。
这是一个很细节的语法,一旦不注意,就陷入了mybatis的陷阱中。mybatis本身没有问题,本身是个优秀的框架。