Java操作SQLite数据库行转移遇唯一约束失败,求解决方案
解决SQLite行转移时的主键唯一约束冲突问题
问题根源
你之前的方案报错,是因为更新id时没指定执行顺序,SQLite默认按主键升序处理行,导致更新过程中出现重复id,触发唯一约束校验失败。比如要调整的区间里,先更新小id会和还未更新的大id产生冲突。
通用解决方案
不管是把行往后移还是往前移,核心是按避免冲突的顺序更新id,同时用事务保证操作的原子性:
1. 往后移场景(比如将id=1移到id=4)
步骤:
- 取出目标行数据
- 删除原行
- 对
[目标位置, 原最大id]区间的id加1,按id降序更新(先改大id,不会和未更新的小id冲突) - 插入数据到目标位置
代码实现:
// 开启事务保证原子性 sq.beginTransaction(); try { // 1. 获取要移动的行数据 String name = Db.getName(1); // 2. 删除原行 Db.delete(1); // 3. 按降序更新id,避免冲突 adjustIdsBackward(4); // 4. 插入到目标位置 Db.insert(4, name); sq.setTransactionSuccessful(); } finally { sq.endTransaction(); } // 对应的id调整方法 private void adjustIdsBackward(int targetId) { sq.execSQL("UPDATE table SET id = id + 1 WHERE id >= ? ORDER BY id DESC", new Object[]{targetId}); }
2. 往前移场景(比如将id=4移到id=2)
步骤:
- 取出目标行数据
- 删除原行
- 对
[目标位置, 原行id-1]区间的id减1,按id升序更新(先改小id,不会和未更新的大id冲突) - 插入数据到目标位置
代码实现:
sq.beginTransaction(); try { String name = Db.getName(4); Db.delete(4); adjustIdsForward(2, 4); Db.insert(2, name); sq.setTransactionSuccessful(); } finally { sq.endTransaction(); } private void adjustIdsForward(int targetId, int originalId) { sq.execSQL("UPDATE table SET id = id - 1 WHERE id >= ? AND id < ? ORDER BY id ASC", new Object[]{targetId, originalId}); }
关键说明
- 必须指定更新顺序:往后移用降序,往前移用升序,从根本上避免更新过程中的id重复
- 用事务包裹整个操作,一旦中间步骤出错可以回滚,防止数据出现不一致的状态
内容的提问来源于stack exchange,提问作者Aziz Labiod
相关产品推荐
相关产品推荐

