SQLite三种事务状态: DEFERRED 、IMMEDIATE和EXCLUSIVE说明

SQLite支持三种类型的事务:DEFERRED、IMMEDIATE和EXCLUSIVE,分别对应不同的锁状态。默认是DEFERRED,不立即获取锁。BEGIN命令用于手动开始事务,COMMIT在所有SQL命令完成后才真正提交。当事务冲突时可能返回SQLITE_BUSY。在nodejs的Sequelize库中,可以通过Sequelize.Transaction.TYPES选择事务类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. SQL As Understood By SQLite

Beginning in version 2.0, SQLite supports transactions with rollback and atomic commit.

The optional transaction name is ignored. SQLite currently does not allow nested transactions.

No changes can be made to the database except within a transaction. Any command that changes the database (basically, any SQL command other than SELECT) will automatically start a transaction if one is not already in effect. Automatically started transactions are committed at the conclusion of the command.

Transactions can be started manually using the BEGIN command. Such transactions usually persist until the next COMMIT or ROLLBACK command. But a transaction will also ROLLBACK if the database is closed or if an error occurs and the ROLLBACK conflict resolution algorithm is specified. See the documentation on the ON CONFLICT clause for additional information about the ROLLBACK conflict resolution algorithm.

In SQLite version 3.0.8 and later, transactions can be deferred, immediate, or exclusive. Deferred means that no locks are acquired on the database until the database is first accessed. Thus with a deferred transaction, the BEGIN statement itself does nothing. Locks are not acquired until the first read or write operation. The first read operation against a database creates a SHARED lock and the first write operation creates a RESERVED lock. Because the acquisition of locks is deferred until they are needed, it is possible that another thread or process could create a separate transaction and write to the database after the BEGIN on the current thread has executed. If the transaction is immediate, then RESERVED locks are acquired on all databases as soon as the BEGIN command is executed, without waiting for the database to be used. After a BEGIN IMMEDIATE, you are guaranteed that no other thread or process will be able to write to the database or do a BEGIN IMMEDIATE or BEGIN EXCLUSIVE. Other processes can continue to read from the database, however. An exclusive transaction causes EXCLUSIVE locks to be acquired on all databases. After a BEGIN EXCLUSIVE, you are guaranteed that no other thread or process will be able to read or write the database until the transaction is complete.

A description of the meaning of SHARED, RESERVED, and EXCLUSIVE locks is available separately.

The default behavior for SQLite version 3.0.8 is a deferred transaction. For SQLite version 3.0.0 through 3.0.7, deferred is the only kind of transaction available. For SQLite version 2.8 and earlier, all transactions are exclusive.

The COMMIT command does not actually perform a commit until all pending SQL commands finish. Thus if two or more SELECT statements are in the middle of processing and a COMMIT is executed, the commit will not actually occur until all SELECT statements finish.

An attempt to execute COMMIT might result in an SQLITE_BUSY return code. This indicates that another thread or process had a read lock on the database that prevented the database from being updated. When COMMIT fails in this way, the transaction remains active and the COMMIT can be retried later after the reader has had a chance to clear.

2. sqlite的事务和锁,很透彻的讲解

SQLite有三种不同的事务,使用不同的锁状态。事务可以开始于:DEFERRED、IMMEDIATE或EXCLUSIVE。事务类型在BEGIN命令中指定:

            BEGIN [ DEFERRED | IMMEDIATE | EXCLUSIVE ] TRANSACTION;
            
            一个DEFERRED事务不获取任何锁(直到它需要锁的时候),BEGIN语句本身也不会做什么事情——它开始于UNLOCK状态。默认情况下就 是这样的,如果仅仅用BEGIN开始一个事务,那么事务就是DEFERRED的,同时它不会获取任何锁;当对数据库进行第一次读操作时,它会获取 SHARED锁;同样,当进行第一次写操作时,它会获取RESERVED锁。
            
            由BEGIN开始的IMMEDIATE事务会尝试获取RESERVED锁。如果成功,BEGIN IMMEDIATE保证没有别的连接可以写数据库。但是,别的连接可以对数据库进行读操作;但是,RESERVED锁会阻止其它连接的BEGIN IMMEDIATE或者BEGIN EXCLUSIVE命令,当其它连接执行上述命令时,会返回SQLITE_BUSY错误。这时你就可以对数据库进行修改操作了,但是你还不能提交,当你 COMMIT时,会返回SQLITE_BUSY错误,这意味着还有其它的读事务没有完成,得等它们执行完后才能提交事务。
            
            EXCLUSIVE事务会试着获取对数据库的EXCLUSIVE锁。这与IMMEDIATE类似,但是一旦成功,EXCLUSIVE事务保证没有其它的连接,所以就可对数据库进行读写操作了。
            
            上节那个例子的问题在于两个连接最终都想写数据库,但是它们都没有放弃各自原来的锁,最终,SHARED锁导致了问题的出现。如果两个连接都以 BEGIN IMMEDIATE开始事务,那么死锁就不会发生。在这种情况下,在同一时刻只能有一个连接进入BEGIN IMMEDIATE,其它的连接就得等待。BEGIN IMMEDIATE和BEGIN EXCLUSIVE通常被写事务使用。就像同步机制一样,它防止了死锁的产生。
            
            基本的准则是:如果你正在使用的数据库没有其它的连接,用BEGIN就足够了。但是,如果你使用的数据库有其它的连接也会对数据库进行写操作,就得使用BEGIN IMMEDIATE或BEGIN EXCLUSIVE开始你的事务。 

3. 使用说明

基于nodejs库Sequelize过程中,提供了Sequelize.Transaction.TYPES参数

    try {
      t = await gSequelize.getSequelize().transaction({ type: Sequelize.Transaction.TYPES.IMMEDIATE });
      await gSequelize.createTableNameItem(tableName, t);
      await gSequelize.initialDayDevsModel(tableName, t);
      for (let i = 0; i < msgArray.length; i++) {
        await gSequelize.createDayDevsItem(tableName, msgArray[i], t);
      }
      await t.commit();
    } catch (error) {
   	  await t.rollback();
      return undefined;
    }
<think>嗯,用户问的是关于SQLiteIMMEDIATEEXCLUSIVE模式,虽然这两个模式对其他客户端更严格,但优点是如果所需的锁不可用,它们会立即失败,而不是在执行DDL或DML命令之后。我需要先回顾一下SQLite事务锁机制。 首先,SQLite有不同的事务锁模式:DEFERREDIMMEDIATEEXCLUSIVEDEFERRED是最低级别的,开始事务时不会获取锁,而是在执行写操作时才尝试获取锁,这可能导致在后续操作中等待锁,从而引发阻塞或超时。而IMMEDIATE模式在事务开始时就会尝试获取预留锁(RESERVED),这样其他连接无法写入,但可以读取。EXCLUSIVE模式则获取排他锁,完全排斥其他连接。 用户提到的优点是,使用IMMEDIATEEXCLUSIVE模式时,如果锁不可用,事务会立即失败,而不是等到执行DDL/DML时才失败。这点很重要,特别是在需要避免长时间等待的应用场景中,比如高并发或需要快速失败的系统。比如,如果一个事务在开始时就无法获取必要的锁,立即失败可以让应用程序更快地处理错误,而不是等待到执行具体命令时才发现问题,这样可能已经执行了部分操作,导致回滚更复杂。 接下来需要解释为什么DEFERRED模式会有延迟失败的问题。因为DEFERRED事务开始时没有获取锁,可能在后续操作中需要锁时被阻塞,这时候如果其他事务持有锁,当前事务会等待,直到超时或锁释放。而IMMEDIATEEXCLUSIVE事务开始时尝试获取锁,如果失败就立即返回错误,避免了后续操作中的不确定性。 然后,应该举例子说明两种模式的区别。比如,在DEFERRED模式下,事务开始时没有锁,当执行UPDATE时发现锁被占用,就会等待;而IMMEDIATE模式在BEGIN时尝试获取锁,如果失败则直接报错,不会执行后续操作。这对于需要原子性操作的情况很重要,确保事务一旦开始就能顺利执行,否则立即处理。 另外,需要提到适用场景。IMMEDIATE适用于需要快速失败避免阻塞的场景,比如高并发的短事务EXCLUSIVE用于需要独占访问的情况,如数据库维护操作,确保操作期间没有其他连接干扰。 还要注意用户可能的背景,可能是开发人员在使用SQLite时遇到了锁竞争的问题,或者在设计高并发应用时需要优化事务处理。因此,解释时应强调这些模式如何帮助减少等待时间提高系统响应速度,同时权衡严格性并发性。 最后,确保回答结构清晰,分点说明每个模式的特点、优缺点,并结合实例,帮助用户更好地理解应用。</think>以下是关于 SQLite 中 **IMMEDIATE** **EXCLUSIVE** 事务模式的解释: --- ### **核心概念** 在 SQLite 中,事务的锁模式决定了事务如何与其他客户端(连接)**竞争资源**。`IMMEDIATE` `EXCLUSIVE` 是两种更严格的锁模式,相较于默认的 `DEFERRED` 模式,它们的行为优势如下: --- ### **1. DEFERRED 模式的潜在问题** - **默认行为**:事务开始时**不立即获取锁**,直到执行第一条写操作(如 `INSERT`、`UPDATE`)时才尝试获取锁。 - **风险**:如果锁被其他事务占用,事务会**阻塞并等待锁释放**,最终可能导致: - **超时**(由 `busy_timeout` 设置决定)。 - **执行 DDL/DML 命令后失败**,需回滚已执行的操作。 --- ### **2. IMMEDIATE EXCLUSIVE 模式的优势** - **IMMEDIATE 模式**: - **行为**:事务开始时立即获取 **RESERVED 锁**(预留锁),阻止其他事务写入,但允许读取。 - **优点**:若锁不可用,事务直接**失败在 `BEGIN` 阶段**,避免后续操作浪费资源。 - **EXCLUSIVE 模式**: - **行为**:事务开始时尝试获取 **EXCLUSIVE 锁**(排他锁),完全禁止其他事务读写。 - **优点**:若锁不可用,同样**立即失败**,无需等待 DDL/DML 执行后才报错。 #### **关键区别** | 模式 | 锁类型 | 失败时机 | 并发性影响 | |------------|--------------|---------------------------|--------------------------| | `DEFERRED` | 延迟获取锁 | 可能在执行 DML 后失败 | 高并发,但可能阻塞 | | `IMMEDIATE`| RESERVED 锁 | 事务开始时失败 | 允许读,禁止写 | | `EXCLUSIVE`| EXCLUSIVE 锁 | 事务开始时失败 | 完全禁止读写 | --- ### **3. 示例对比** #### **场景** 两个客户端尝试同时修改同一数据表。 - **DEFERRED 模式**: ```sql BEGIN DEFERRED; -- 未获取锁 -- 执行其他操作... UPDATE table SET col = 1; -- 此时才尝试获取锁,若失败则在此处阻塞或报错 ``` **风险**:若锁被占用,`UPDATE` 可能失败,但事务已执行了部分操作(如之前的 `INSERT`),需回滚。 - **IMMEDIATE/EXCLUSIVE 模式**: ```sql BEGIN IMMEDIATE; -- 立即尝试获取锁,若失败则直接报错 -- 后续操作仅在锁可用时执行 UPDATE table SET col = 1; ``` **优势**:锁竞争问题在事务开始时暴露,避免无效操作。 --- ### **4. 适用场景** - **IMMEDIATE**: - 需快速检测锁冲突(如高并发短事务)。 - 允许其他连接读取数据,但禁止写入。 - **EXCLUSIVE**: - 需独占访问(如数据库维护操作)。 - 确保事务完整执行,不受任何干扰。 --- ### **总结** - **核心价值**:`IMMEDIATE` `EXCLUSIVE` 通过**提前锁定资源**,牺牲部分并发性,换取了**操作可预测性****失败快速响应**。 - **选择依据**:根据业务对并发性、原子性响应速度的需求权衡。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值