数据库插入失败引出的多线程问题



昨天遇到一个奇葩问题, 一组不重复的数据在插入数据库的时候


数据 a 出现unique failed , 但是插入成功

数据 b 没有报错, 但是插入失败

并且发现for循环内都遍历不到数据b , 但是for循环外是可以打印到它的


就像鬼打墙一样搞了我6个小时查不出原因,

最后发现只要在插入前进行一次排序就不会出错, 虽然不明白原理, 姑且先这么把问题解决掉



<span style="font-size:14px;">public boolean insertClauseList(List<Clause> clauses,int stdNo){

//        Collections.sort(clauses, new Comparator<Clause>() {
//            @Override
//            public int compare(Clause lhs, Clause rhs) {
//                if (lhs.parentno != rhs.parentno) {
//                    return lhs.parentno - rhs.parentno;
//                } else {
//                    return lhs.sortby - rhs.sortby;
//                }
//            }
//        });

        SQLiteDatabase db = helper.getWritableDatabase();
        long insertResult;
        ArrayList<String> errorList = new ArrayList<>();
        for (Clause clause : clauses) {

            ContentValues values = new ContentValues();
            values.put(DBConstants.CLAUSE_NO,clause.no);
            values.put(DBConstants.CLAUSE_PARENTNO,clause.parentno);
            values.put(DBConstants.CLAUSE_SORTBY,clause.sortby);
            values.put(DBConstants.CLAUSE_CHAPTER,clause.chapter);
            values.put(DBConstants.CLAUSE_CAPTION,clause.caption);
            values.put(DBConstants.CLAUSE_GENRE,clause.genre);
            values.put(DBConstants.CLAUSE_ISCATALOG,clause.iscatalog);
            values.put(DBConstants.CLAUSE_EXPLAIN,clause.explain);
            values.put(DBConstants.CLAUSE_MANDATORY,clause.mandatory);
            values.put(DBConstants.CLAUSE_FAILING,clause.failing);
            values.put(DBConstants.CLAUSE_STDID,clause.stdid);
            values.put(DBConstants.CLAUSE_STDNO,stdNo);

            insertResult = db.insert(DBConstants.TB_CLAUSE, null, values);

            if (insertResult == -1)
                errorList.add(BaseApp.getContext().getString(R.string.ommitted,clause.no));

            if (clause.parentno == 0){
                LogUtils.w("根节点保存结果__"+insertResult);
            }

        }

        if (errorList.size() == 0){
            return true;
        }else {
            LogUtils.w("errorlist--"+errorList);
            return false;
        }
    }</span>


今天换了一台新的6.0测试机, 运行到相同的位置的时候报出CurrentModifyException, 才想起这个鬼打墙是多线程访问相同资源造成的


原因是我在网络获取数据后, 把同一个list分别传递给主线程展示和子线程进行插入数据库操作


并且, 主线程的界面在展示前对list进行了一次排序, 而此时子线程正在遍历list插入数据


结果是 子线程插入数据a完成后 主线程将数据a和数据b位置对换了, 子线程访问到该位置时读取的还是数据a的内存地址, 数据b因此没有访问到


新的机器由于性能好, 多个线程操作数据的速度更快, 才暴露出问题


由此进行如下改进


1.  避免传递源数据, 使用ArrayList(List)构造复制一个list后传递

2.  对数据进行增删改的操作放到分发之前完成, 分发后只进行遍历


问题解决



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值