SQL事务和锁机制

事务

数据库事务 Database Transaction 是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。
事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。
一个逻辑工作单元要成为事务,必须满足所谓的 ACID(原子性、一致性、隔离性和持久性)属性。事务是数据库运行中的逻辑工作单位,由 DBMS 中的事务管理子系统负责事务的处理。

事务的特性:

  1. 原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚
    (Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
  2. 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
  3. 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
  4. 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失

在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。
事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行。
事务用来管理 insert,update,delete 语句。

事务开始于:

  • 连接到数据库上,并执行一条 DML 语句(insert/update/delete)
  • 前一个事务结束后,又输入了另外一条 DML 语句

事务结束于:

  • 执行 commit/rollback
  • 执行一条 DDL 语句,自动 commit
  • 执行一条 DCL 语句,自动 commit
  • 断开与数据库的连接
  • 执行了一条 DML 语句,该语句却失败了;在这种情况中,会为这个 DML 语句执行 Rollback 语句

在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。因此要显式地开启一个事务务须使用命令 BEGIN 或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交

begin; --启动事务,否则默认单语句单事务
update t_clz set stu_num=100 where id=4; --可以执行多条 sql 语句【针对增删改 DML】
savepoint bb; --定义存储点,可以执行部分回滚
update t_clz set stu_num=55 where id=1; ---可以是多条 sql 语句
rollback to bb; --撤销存储点 bb 之后的所有操作,但是 bb 之前的操作仍旧存在
commit; --提交所有操作结果,注意没有部门提交的概念

JDBC 中事务编程实

在这里插入图片描述
第二条 sql 语句出错会导致语句 1 执行无效

事务并发操作中会有 4 种非正常情况,分别是脏读、幻读、不可重复读和丢失更新(2类)。可以通过隔离等级以限制并发操作的程度。对应不同的事务隔离等级有 4 种,隔离等级越高,出现的问题越少,但是并发性越差。一般是采用默认【数据库隔离等级+Java 编程补偿】方法解决并发的问题

第一种隔离级别:Read uncommitted(读未提交)
如果一个事务已经开始写数据,则另外一个事务不允许同时进行写操作,但允许其他事务读此行数据,该隔离级别可以通过“排他写锁”,但是不排斥读线程实现。这样就避免了更新丢失,却可能出现脏读,也就是说事务 B 读取到了事务 A 未提交的数据。

解决了更新丢失,但还是可能会出现脏读。

第二种隔离级别:Read committed(读提交)
如果是一个读事务(线程),则允许其他事务读写,如果是写事务将会禁止其他事务访问该行数据,该隔离级别避免了脏读,但是可能出现不可重复读。事务 A 事先读取了数据,事务 B 紧接着更新了数据,并提交了事务,而事务 A 再次读取该数据时,数据已经发生了改变。

解决了更新丢失和脏读问题

第三种隔离级别:Repeatable read(可重复读取)
可重复读取是指在一个事务内,多次读同一个数据,在这个事务还没结束时,其他事务不能访问该数据(包括了读写),这样就可以在同一个事务内两次读到的数据是一样的,因此称为是可重复读隔离级别,读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务(包括了读写),这样避免了不可重复读和脏读,但是有时可能会出现幻读。(读取数据的事务)可以通过“共享读镜”和“排他写锁”实现。

解决了更新丢失、脏读、不可重复读、但是还会出现幻读

第四种隔离级别:Serializable(可序化)
提供严格的事务隔离,它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行,如果仅仅通过“行级锁”是无法实现序列化的,必须通过其他机制保证新插入的数据不会被执行查询操作的事务访问到。序列化是最高的事务隔离级别,同时代价也是最高的,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻读

解决了更新丢失、脏读、不可重复读、幻读(虚读)

在这里插入图片描述

批处理 batch

  • 灵活指定 SQL 语句中的变量 PreparedStatement
  • 对存储过程中进行调用 CallableStatement
  • 运用事务处理 Transaction

锁机制

数据库事务是依赖于日志和锁机制实现的。
数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则。对于任何一种数据库来说都需要有相应的锁定机制,所以 MySQL 自然也不能例外。

MySQL 数据库由于其自身架构的特点,存在多种数据存储引擎,每种存储引擎所针对的应用场景特点都不太一样,为了满足各自特定应用场景的需求,每种存储引擎的锁定机制都是为各自所面对的特定场景而优化设计,所以各存储引擎的锁定机制也有较大区别。

表级锁定 table-level
表级别的锁定是 MySQL 各存储引擎中最大颗粒度的锁定机制。该锁定机制最大的特点是实现逻辑非常简单,带来的系统负面影响最小。所以获取锁和释放锁的速度很快。由于表级锁一次会将整个表锁定,所以可以很好的避免死锁问题。 当然锁定颗粒度大所带来最大的负面影响就是出现锁定资源争用的概率也会最高,致使并发度大打折扣使用表级锁定的主要是 MyISAM,MEMORY,CSV 等一些非事务性存储引擎。

行级锁定 row-level
行级锁定最大的特点就是锁定对象的颗粒度很小,也是目前各大数据库管理软件所实现的锁定颗粒度最小的。由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予应用程序尽可能大的并发处理能力而提高一些需要高并发应用系统的整体性能。虽然能够在并发处理能力上面有较大的优势,但是行级锁定也因此带来了不少弊端。由于锁定资源的颗粒度很小,所以每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。行级锁定也最容易发生死锁。 使用行级锁定的主要是 InnoDB 存储引擎。

页级锁定 page-level
页级锁定是 MySQL 中比较独特的一种锁定级别,在其他数据库管理软件中也并不是太常见页级锁定的特点是锁定颗粒度介于行级锁定与表级锁之间,所以获取锁定所需要的资源开销,以及所能提供的并发处理能力也同样是介于上面二者之间页级锁定和行级锁定一样,会发生死锁。

MySQL 这 3 种锁的特性

表级锁: 开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;
行级锁: 开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高;
页面锁: 开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
在数据库实现资源锁定的过程中,随着锁定资源颗粒度的减小,锁定相同数据量的数据所需要消耗的内存数量是越来越多的,实现算法也会越来越复杂。
不过,随着锁定资源颗粒度的减小,应用程序的访问请求遇到锁等待的可能性也会随之降低,系统整体并发度也随之提升。
使用页级锁定的主要是 BerkeleyDB 存储引擎

Innodb 锁机制

InnoDB 的行级锁定同样分为两种类型,共享锁和排他锁,而在锁定机制的实现过程中为了让行级锁定和表级锁定共存,InnoDB 也同样使用了意向锁的概念,也就有了意向共享锁和意向排他锁这两种
当一个事务需要给需要的某个资源加锁时,如果遇到一个共享锁正锁定着自己
需要的资源的时候,自己可以再加一个共享锁,不过不能加排他锁。
如果遇到自己需要锁定的资源已经被一个排他锁占有之后,则只能等待该锁定
释放资源之后自己才能获取锁定资源并添加自己的锁定意向锁的作用就是当一个事务在需要获取资源锁定的时候,如果遇到自己需要的资源
已经被排他锁占用的时候,该事务可以需要锁定行的表上面添加一个合适的意向锁。如果自己需要一个共享锁,那么就在表上面添加一个意向共享锁。而如果自己需要的是某行或某些行上面添加一个排他锁的话,则先在表上面添加一个意向排他锁。意向共享锁可以同时并存多个,但是意向排他锁同时只能有一个存在。
InnoDB 的锁定模式实际上可以分为四种:共享锁 S,排他锁 X,意向共享锁 IS 和意向排他锁 IX

猜你喜欢

转载自blog.csdn.net/Lecheng_/article/details/115360101