数据库Connection pool关闭、未打开异常及Entity主键重复问题咨询
一、数据库未打开/连接池已关闭的IllegalStateException
你提到的这两个异常,本质上都是数据库连接管理出了问题,尤其是在高并发(数千次查询)场景下更容易暴露,结合你说的多线程操作、数据库关闭后仍交互的诱因,咱们可以从这几个方向解决:
严格管控数据库实例的生命周期
如果你用的是Android原生的SQLiteOpenHelper,一定要保证它是单例模式——多次创建实例会导致连接池被频繁初始化/关闭,很容易出现“连接池已关闭”的问题。另外,绝对不要在还有异步查询任务在执行的时候调用close()方法,要确保所有数据库操作都完成后再关闭连接。多线程操作必须保证线程安全
数据库操作本身不是线程安全的,尤其是在并发读写时,很容易出现连接状态混乱。如果是用原生SQLite,记得对读写操作加锁(比如用synchronized块包裹);如果用Room的话,直接用它提供的@Dao异步API(比如suspend方法配合Coroutines),Room已经帮你处理了线程安全和连接池管理。异常捕获与重试机制
对于高并发场景下偶尔出现的连接池异常,可以在捕获到IllegalStateException后,先检查数据库连接状态,如果确实已关闭,重新初始化连接后再重试操作(注意设置重试次数上限,避免死循环)。
二、主键重复的Entity插入问题
当插入和已有数据主键相同的Entity时,数据库会触发UNIQUE约束冲突,通常会抛出SQLiteConstraintException,解决思路分三种,你可以根据业务需求选:
替换旧数据(推荐)
用INSERT OR REPLACE的逻辑,比如在Room里可以给@Insert注解加上onConflict = OnConflictStrategy.REPLACE,这样当主键重复时,会自动删除旧数据并插入新数据;原生SQL的话直接写INSERT OR REPLACE INTO table (...) VALUES (...)。先查询再更新/插入
插入前先根据主键查询是否存在对应数据:如果存在就执行UPDATE操作,不存在就执行INSERT。不过这种方式要注意并发问题,最好把查询+更新/插入放在一个事务里,避免中间被其他线程修改数据。捕获冲突异常做业务处理
直接捕获SQLiteConstraintException,然后根据业务场景给用户提示(比如“该数据已存在”),或者执行其他自定义逻辑。
内容的提问来源于stack exchange,提问作者Josh Laird

