1. 事务的特性ACID

  • 原子性: Atomicity

一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚。

  • 一致性:Consistency

数据库总是从一个一致性的状态转换到另一个一致性的状态。

  • 隔离性:Isolation

通常来说,一个事务所做的修改在最终提交前,对其它事务是不可见的。

  • 持久性:Durability

一旦事务提交,则所有修改就永久保存在数据库的磁盘中。
RELDOLOG https://www.yuque.com/imyiren/notes/gwhyb9#Nf0aF

2. 事务的隔离级别

  • 读未提交(read uncommitted)
  • 读已提交(read committed)
  • 可重复读(repeatable read)
  • 串行化(serializable )
    • 隔离级别产生的三个问题:

    脏读(dirty read): 不可重复读(non-repeatable read): 幻读(phantom read):

2.1 读未提交

  • 一个事务还没提交时,它做的变更就能被别的事务看到。
  • 实现:“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念;
  • 问题:脏读、不可重复读、幻读

    2.2 读已提交

  • 一个事务提交之后,它做的变更才会被其他事务看到。

  • 实现:“读已提交”隔离级别下,这个视图是在每个 SQL 语句开始执行的时候创建的
  • 问题:不可重复读、幻读

    2.3 可重复读 (MySQL默认 )

  • 一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。

  • 实现:使用视图实现,视图是在事务启动时创建的,整个事务存在期间都用这个视图。
  • 问题:幻读

    2.4 串行化

  • 顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

  • 实现:“串行化”隔离级别下直接用加锁的方式来避免并行访问。 (锁是部分锁,不是表锁)
  • 问题:它会强制事务串行执行,避免了脏读、不可重复读、幻读的问题,但是牺牲了并发性。

    2.5 问题解读

  1. 脏读
  • 事务A 读到了事务B修改了但是还未提交的数据
  1. 不可重复读
  • 事务A 开始读了一次数据,事务B开始修改了一个数据提交后,然后事务A又读了一次,发现和上次读取的数据不一样。
  1. 幻读
  • 事务A 按照一定条件进行数据读取, 期间事务B 插入了相同搜索条件的新数据,事务A再次按照原先条件进行读取时,发现了事务B 新插入的数据 称为幻读

    2.6 隔离级别的案例

    image.png

  • 若隔离级别是“读未提交”, 则 V1 的值就是 2。这时候事务 B 虽然还没有提交,但是结果已经被 A 看到了。因此,V2、V3 也都是 2。

  • 若隔离级别是“读提交”,则 V1 是 1,V2 的值是 2。事务 B 的更新在提交后才能被 A 看到。所以, V3 的值也是 2。
  • 若隔离级别是“可重复读”,则 V1、V2 是 1,V3 是 2。之所以 V2 还是 1,遵循的就是这个要求:事务在执行期间看到的数据前后必须是一致的。
  • 若隔离级别是“串行化”,则在事务 B 执行“将 1 改成 2”的时候,会被锁住。直到事务 A 提交后,事务 B 才可以继续执行。所以从 A 的角度看, V1、V2 值是 1,V3 的值是 2。

    2.7 事务相关设置

  1. 查询事务隔离级别:

    1. # 当前会话:
    2. select @@tx_isolation;
    3. show variables like 'transaction_isolation';
    4. # 系统级别:
    5. select @@global.tx_isolation;
  2. 设置事务隔离级别

    1. # 注意 这样设置当前会话不会生效,只有下一个会话才会生效。 可重复读
    2. set transaction isolation level REPEATABLE READ;
    3. # 设置当前会话的事务隔离级别 : 读已提交
    4. set transaction isolation level read committed;
    5. # 设置同的事务隔离级别: 读未提交
    6. set transaction isolation level read uncommitted;
  3. 启动提交回滚事务 ```sql

    开始事务

    begin start transaction

提交事务

commit

回滚事务

rollback

  1. 4. 关闭默认自动提交
  2. ```sql
  3. set autocommit = 0;
  • 该命令会把这个线程的自动提交关掉。这样只要执行一个select语句,事务就启动,并不会自动提交,直到主动执行commit或rollback或断开连接。
  • 在autocommit=1的情况下用begin显式启动事务,如果执行commit则提交事务。

    3. MVCC 多版本并发控制

  • MVCC(Mutil-Version Concurrency Control),就是多版本并发控制。MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问。

  • 在MySQL的InnoDB引擎中就是指在读已提交(READ COMMITTD)可重复读(REPEATABLE READ)这两种隔离级别下的事务对于SELECT操作会访问版本链中的记录的过程。

    3.1 MVCC在行中的隐藏列

  1. DATA_TRX_ID
    • 记录最近更新这条行记录的 事务 ID ,大小为 6 个字节
  2. DATA_ROLL_PTR
    • 表示指向该行回滚段 (rollback segment) 的指针,大小为 7 个字节, InnoDB 便是通过这个指针找到之前版本的数据。该行记录上所有旧版本,在 undo 中都通过链表的形式组织。
  3. DB_ROW_ID
    • 行标识(隐藏单调自增 ID ),大小为 6 字节,如果表没有主键, InnoDB 会自动生成一个隐藏主键,因此会出现这个列。另外,每条记录的头信息( record header )里都有一个专门的 bitdeleted_flag )来表示当前记录是否已经被删除。

4. MySQL中的各种锁

4.1 全局锁:

  • 全局锁就是对整个数据库实例加锁。MySQL 提供了一个加全局读锁的方法,命令是 Flush tables with read lock (FTWRL)。当你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句。

    4.2 行锁 (InnoDB引擎支持)

  • 行锁就是针对数据表中行记录的锁。这很好理解,比如事务 A 更新了一行,而这时候事务 B 也要更新同一行,则必须等事务 A 的操作完成后才能进行更新。

  • 在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。
  • 如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。

  • 注意

    • 行锁是通过索引结构来实现的,如果所在列没有索引,update一条数据都会锁表

    • 4.3 表锁