关于在Java中使用sql语句的一些思考(基于mybatis plus实现)

前言

我确实太少写笔记了,这样很难成长,今天做个第n次 开始。
最常用的sql语句就是插入和更新。插入暂且不提,在更新时,我以前只会无脑借鉴别人的代码。这次突然把几个理解综合了一下。茅塞顿开。
有一点必须强调,我只使用了mybatis plus,其他辅助sql语句的三方包不甚了解。

更新的核心特性——null不更新

如下语句

   public Boolean edit(Long id, AReq req) {
        log.info("编辑信息:id:{}, {}", id, req);
        ADO oldADO = aMapper.selectById(id);
        if (oldADO == null) {
            throw new AException(ErrorCodeEnum.SQL_NULL_EXCEPTION);
        }
        // do something ...
        BeanUtils.copyProperties(req, oldADO);
        int flag = aMapper.updateById(oldADO);
        log.info("编辑: {}", flag);
        return 0 != flag;
    }

以上代码看似没问题,实际存在一个大bug,就是从前端读取数据后,编辑开始,到最后写入数据库期间,但凡有另一个任务对ADO的某个字段进行了修改,就无法修改成功。

比如:ADO有三个字段name、age、status。编辑只对name和age修改,而有一个定时任务对status每一分钟更新一次。那就存在name被编辑后,保存时把status的旧值覆盖了编辑期间更新的status。

这不是一个并发问题,而是一个逻辑问题,当你明确地知道编辑只修改name和age时,你很难意识到,status被影响了,从而导致发现不了为什么定时任务的status更新不生效。

但我们可以利用null不更新的特点规避这个bug。修复后代码如下:

   public Boolean edit(Long id, AReq req) {
        log.info("编辑信息:id:{}, {}", id, req);
        ADO oldADO = aMapper.selectById(id);
        if (oldADO == null) {
            throw new AException(ErrorCodeEnum.SQL_NULL_EXCEPTION);
        }
        // do something ...
        ADO newADO = new ADO();
        BeanUtils.copyProperties(req, newADO);
        newADO.setId(id);
        int flag = aMapper.updateById(newEdgeDO);
        log.info("编辑: {}", flag);
        return 0 != flag;
    }

首先明确的是req中不存在status,则new ADO的status一定为null,借助null不更新特性,则不影响定时任务的执行。

更进一步去思考更新status的定时任务是不是也存在这一问题呢。

   public Boolean check(Long id) {
        ADO aDO = aMapper.selectById(id);
        if (aDO == null) {
            throw new AException(ErrorCodeEnum.SQL_NULL_EXCEPTION);
        }
        // do something ...
        aDO.setStatus("更新了一次内容: " + (new Date()));
        int flag = aMapper.updateById(aDO);
        log.info("编辑: {}", flag);
        return 0 != flag;
    }

同样也需要改成

   public Boolean check(Long id) {
        if (aMapper.selectById(id) == null) {
            throw new AException(ErrorCodeEnum.SQL_NULL_EXCEPTION);
        }
        // do something ...
        ADO aDO = new ADO();
        aDO.setId(id);
        aDO.setStatus("更新了一次内容: " + (new Date()));
        int flag = aMapper.updateById(aDO);
        log.info("编辑: {}", flag);
        return 0 != flag;
    }

当更新的字段比较少或者不需要读取该对象的某些属性时,可以优化成这样:

   public Boolean check(Long id) {
        // do something ...
        int flag = aMapper.update(new LambdaUpdateWrapper<User>()
	        .eq(User::getId, id)
	        .set(User::getStatus, "xxx"));
        log.info("编辑: {}", flag);
        return 0 != flag;
    }

不要把一个简单的逻辑问题搞成复杂的并发问题。

未完待续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值