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

来源:互联网 发布:什么是敏捷软件开发 编辑:程序博客网 时间:2024/04/29 14:11



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


数据 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