• 面试:Sqlite的线程、进程安全性


    ContentProvider相关_沙漠一只雕得儿得儿的博客-CSDN博客_contentprovider线程安全

    1、如果是单进程多线程,多线程访问数据库的时候会出现这样的异常,Sqlite 自身是不支持多线程同时操作的

    1. java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed .
    2. 或 java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase : 或 java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase:

    很简单,直接用多线程锁就可以 

    2、如果是多进程呢:sqlite多进程多连接经常死锁。设计上就不是干这事的。

    SQLite的并发性允许多个进程一次打开数据库文件,并允许多个进程一次读取数据库。当任何进程想要写入时,它必须在更新期间锁定整个数据库文件。但这通常只需要几毫秒。其他流程只是等待作者完成然后继续他们的业务。其他嵌入式SQL数据库引擎通常只允许单个进程一次连接到数据库。

    多进程写sqlite的实验:sqlite3的进程安全访问测试_LostSpeed的博客-CSDN博客

    sqlite3同一个表无法由2个进程同时读写表记录。
    总有一个进程会出现“database is locked”的报错
    ,去查了资料。大概意思是:因为是文件型数据库,无法使2个进程同时向同一个文件写数据。我的应用是一个读(读完一条记录删一条),一个写,应该会触发sqlite的文件读写锁吧。
    尝试sql执行失败后重试,倒是可以继续跑。但是每一个SQL都有可能失败,都要重试。这执行效率就下来了。

    3、多线程同时往数据库插入数据

    现在我们有Thread 1Thread 2两个线程要往数据库中插入数据:

    那么我们可能会收到下如下错误logcat,并且其中一个线程的插入写数据库操作将会执行失败:

    android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5)

    为什么会发生 SQLiteDatabaseLockedException 异常呢?

    因为每一次我们新创建new一个SQLiteOpenHelper对象,都会新建立一个数据库连接database connection。如果同时用两个不同的connection往数据库中写数据,其中一个将会失败,并收到database is locked异常。

    如何确保多线程先使用的是同一个数据库连接database connection

    使用单例类。

    SQLite 与线程

    SQLite 线程安全和并发 - 走看看

    SQLite 是线程安全的。

    线程模型

    SQLite 支持如下三种线程模型

    • 单线程模型 这种模型下,所有互斥锁都被禁用,同一时间只能由一个线程访问。
    • 多线程模型 这种模型下,一个连接在同一时间内只有一个线程使用就是安全的。
    • 串行模型 开启所有锁,可以随意访问。

    设置线程模型

    SQLite 可以通过以下三种方式进行线程模型的设置,在实际应用中选择任一一项都可以。

    • 编译期设定 通过 SQLITE_THREADSAFE 这个参数进行编译器的设定来选择线程模型
    • 初始化设定 通过调用 sqlite3_config() 可以在 SQLite 初始化时进行设定
    • 运行时设定 通过调用 sqlite3_open_v2() 接口指定数据库连接的数据库模型

    SQLite 并发和事务

    事务

    事务是 SQLite 的核心概念。对数据库的操作 (绝大部分) 会被打包成一个事务进行提交,需要注意的是,这里的打包成事务是自动开启的。举例而言,如果简单在一个 for 循环语句里向数据库中插入 10 条数据,意味着将自动生成 10 个事务。但需要注意的是事务是非常耗时的,一般而言, SQLite 每秒能够轻松支持 50000 条的数据插入,但是每秒仅能够支持几十个事务。一般而言,事务速度受限于磁盘速度。所以在批量插入时需要考虑禁用自动提交,将其用 BEGIN ... COMMIT 打包成一个事务。

    锁和并发

    SQLite 通过五种锁状态来完成事务。

    • UNLOCKED ,无锁状态。数据库文件没有被加锁。
    • SHARED 共享状态。数据库文件被加了共享锁。可以多线程执行读操作,但不能进行写操作。
    • RESERVED 保留状态。数据库文件被加保留锁。表示数据库将要进行写操作。
    • PENDING 未决状态。表示即将写入数据库,正在等待其他读线程释放 SHARED 锁。一旦某个线程持有 PENDING 锁,其他线程就不能获取 SHARED 锁。这样一来,只要等所有读线程完成,释放 SHARED 锁后,它就可以进入 EXCLUSIVE 状态了。
    • EXCLUSIVE 独占锁。表示它可以写入数据库了。进入这个状态后,其他任何线程都不能访问数据库文件。因此为了并发性,它的持有时间越短越好。

    一个线程只有拥有低级别锁时才能够获得更高一级的锁

  • 相关阅读:
    SpringBoot+Vue+Element-UI实现自动排课系统
    windows 下使用virtualbox7.0设置共享文件夹详细,绝对好用
    Mysql查询优化 -Explain 详解(上)
    CentOS7 Hive2.3.8安装
    数字图像处理——大作业 基于车道信息的违法车辆车牌识别
    山西电力市场日前价格预测【2023-10-04】
    12寸和8寸封装线的差异点
    Photoshop插件-charIDToTypeID-PIStringTerminology.h-不同值的解释及参考-脚本开发-PS插件
    2022年 11月26日 KNN 学习笔记
    基于Spring-Data-Elasticsearch 优雅的实现 多字段搜索 + 高亮 + 分页 + 数据同步✨
  • 原文地址:https://blog.csdn.net/cpcpcp123/article/details/127683565