tkmybatis使用不当导致全表数据更新!快检查你的用法正确吗

上周三下午刚睡醒,生产环境的消息报警中出现了一条空指针错误,这条常见的错误消息,拉开了8个小时修数据的帷幕。

根据空指针的错误信息找到了对应的代码和数据,诡异的是这条数据中一个重要的关联字段竟然是空的。随后写了一个sql,查出全表中此字段为空的数据竟然高达29万条,近乎全表的数据都被洗了。这下可坏了!这时候钉钉里频繁出现业务人员拉工单,反馈系统单据异常、已结算的订单找不到、订单金额错误等问题。线上系统近乎瘫痪了!

我赶快反馈了组长和其他同事,分头行动。最终经历了2次代码上线和n次脚本修复,终于补完了,结束已经是晚上9点。
导致问题的代码简化如下:

	public int updateOrderByCode(OrderDto entity) {
        entity.setCode="123456";
        entity.setRefCode = "999999";
        Example e = new Example(Order.class);
        Example.Criteria cri = e.createCriteria();
        cri.andEqualTo(Order.Fields.code,entity.getCode());
        return orderManager.updateByExampleSelective(entity,e);
    }

这个方法的逻辑是将编码为”123456“的refCode字段更新为“999999”。
但是由于前端的和接口没做校验,导致传入的参数都是空,逻辑变成了下面的内容:

	public int updateOrderByCode(OrderDto entity) {
        entity.setCode=null;
        entity.setRefCode = "";
        Example e = new Example(Order.class);
        Example.Criteria cri = e.createCriteria();
        cri.andEqualTo(Order.Fields.code,entity.getCode());
        return orderManager.updateByExampleSelective(entity,e);
    }

如果这段代码在原生的mybatis执行是不会有问题的,因为底层会检验条件参数值是否为null,为null则抛错,不会再更新数据。

	//mybatis对Example.Criteria条件参数的检验
	protected void addCriterion(String condition, Object value, String property) {
            if (value == null) {
                throw new RuntimeException("Value for " + property + " cannot be null");
            }
            criteria.add(new Criterion(condition, value));
        }

但是在tkmybatis(版本3.5.3)中,逻辑不同了!
tkmybatis在检验参数值时需要满足变量值notNull是true才会抛错,不然它会舍弃这个条件!而notNull默认是false,这意味着如果仅有的参数值是null,则更新全表!

	protected void addCriterion(String condition, Object value, String property) {
            if (value == null) {
                if (this.notNull) {
                    throw new MapperException("Value for " + property + " cannot be null");
                }
            } else if (property != null) {
                this.criteria.add(new Example.Criterion(condition, value));
            }
        }

Example构造方法的源码如下,可以看到在声明时可以指定entityClass、exists,、notNull这三个参数。exists是当条件对应字段不存在则抛错的开关,notNull是当条件的参数值为null则抛错的开关。
如果不传则默认为exists : true,notNull:false。

  	public Example(Class<?> entityClass) {
        this(entityClass, true);
    }
    public Example(Class<?> entityClass, boolean exists) {
        this(entityClass, exists, false);
    }
    public Example(Class<?> entityClass, boolean exists, boolean notNull) {
        this.exists = exists;
        this.notNull = notNull;
        this.oredCriteria = new ArrayList();
        this.entityClass = entityClass;
        this.table = EntityHelper.getEntityTable(entityClass);
        this.propertyMap = this.table.getPropertyMap();
        this.ORDERBY = new Example.OrderBy(this, this.propertyMap);
    }

正确的做法是在声明条件参数Example同时指定notNull为true

     Example e = new Example(Order.class,true,true);

至此问题定位和解决方案已经描述完了。如果你的项目中也使用了tkmybatis,快检查你的用法正确吗😨?
数据无价,对技术要有敬畏之心,使用时做好调研!
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值