• 记录一个有意思的问题……


    今天业务开发出现了一个有意思的问题:

    一段操作逻辑里,两次update同一个表,如果两次updated偶成功,则对另一个表进行一次insert操作
    两次update是用的同一个方法,传入参数对象属性值不同。

    现象:

    a.数据库里数据更新操作成功
    b.insert操作,时而成功时而失败。
    c.如果从头debug跟进每个处理逻辑,插入数据一定处理成功。

    处理逻辑
    private void deal(){
        DataBO dataBO = new DataBO();
        dataBO.setId(23);
        dataBO.setXxx("XXX");
        dataBo.setYyy("YYY");
        boolean result = update(dataBO);
        if(!result)
            return;
    
        dataBO = new DataBO();
        dataBO.setId(23);
        dataBO.setOneStatus(0);
        dataBO.setTwoStatus(0);
        result = update(dataBO);
        if(!result)
            return;
    
        //插入数据
        insert();
    }
    
    update方法
    public boolean update(DataBO dataBO){
        return dataDAO.updateById(dataBO) > 0;
    }
    
    BO
    public class DataBO{
        private Long id;
        private int isDeleted;
        private int oneStatus;
        private int twoStatus;
        private String xxx;
        private String yyy;
        private Date gmtCreated;
        private Date gmtModified;
    }
    
    mapper
    <update id="updateById" parameterClass="DataBO" >
            update data_table set gmt_modified = now()
            <dynamic prepend="" >
                 <isNotEmpty prepend="," property="gmtCreated">
                        gmt_created = #gmtCreated#
                </isNotEmpty>
                 <isNotEmpty prepend="," property="gmtModified">
                        gmt_modified = #gmtModified#
                </isNotEmpty>
                 <isNotEmpty prepend="," property="isDeleted">
                        is_deleted = #isDeleted#
                </isNotEmpty>
                <isNotEmpty prepend="," property="xxx">
                        xxx = #xxx#
                </isNotEmpty>
                <isNotEmpty prepend="," property="yyy">
                        yyy = #yyy#
                </isNotEmpty>
                <isNotEmpty prepend="," property="oneStatus">
                        one_status = #oneStatus#
                </isNotEmpty>
                <isNotEmpty prepend="," property="twoStatus">
                        two_status = #twoStatus#
                </isNotEmpty>
            </dynamic>
        where id = #id#
    </update>·
    

    分析定位

    表象是,数据库里数据更新明明操作成功了,但插入失败了。
    Debug无法复现,就打印了些日志来分析,结果是第二次更新没有成功,影响条数为0
    copy日志中的sql去数据库客户端执行,操作成功:

    update data_table set gmt_modified = now() ,one_status =0,two_status=0,where id = 23;
    

    所以核心问题就是为什么程序里执行更新操作会时常失败。

    排查发现:

    • 数据库update操作,当原数据库记录数据与传入参数没有任何变化时,不执行操作,影响记录数为0
    • 传入参数两个int属性,初始化时会被置为0,导致第二个update需要更新的字段都与数据库记录一致,isNotEmpty条件判断无意义
    • 成功失败的关键,在于now()的取值,若两次更新时间一样,则所有参数一致,更新失败。所以在客户端操作更新成功,debug拉开了时间差异,也会更新成功

    这样一段逻辑,到处都是坑,但就是各种错误写法/用法聚集一起,才露出了这种“大新闻”的表象,只要一个条件不符合,这个问题的复杂程度都要降低很多,更容易排查。
    比如,属性值类型不用int,或者检查方式更严谨,或者没有gmt_modified = now() 这个条件(哪怕是复制到客户端测试的时候没有这个条件,问题也都早就暴露出来了)……

  • 相关阅读:
    web 单例 多例
    python socket客户端
    foy: 轻量级的基于 nodejs 的通用 build 工具
    Hydux: 一个 Elm-like 的 全功能的 Redux 替代品
    AlarmManager使用注意事项
    【转】android ListView 几个重要属性
    自己写的小工具软件集合
    win8.1 cygwin编译java轻量虚拟机avian
    android 图片缩放抗锯齿
    windows phone和android,ios的touch事件兼容
  • 原文地址:https://www.cnblogs.com/coderzl/p/8304659.html
Copyright © 2020-2023  润新知