Mysql基础课四:事务

事务

  1. 保证一组数据库操作,要么全部成功,要么全部失败;

  2. 事务支持是在引擎层实现的,所以并不是所有引擎均支持,如 MyISAM 不支持,InnoDB 支持;

  3. 事务的 ACID,原子性,一致性,隔离性,持久性;

  4. 一致性,是指数据库内部数据状态,在某个时刻的一致性,也包含了数据和日志在逻辑上的一致性,举例说,某个时刻,将数据库的 bin log 在从库上还原,应该和主库该时刻,数据状态是一致的;

事务使用

  1. 手动开启 begin,提交 commit,关闭自动提交 autocommit = 0,这导致一个 select 语句也会开启一个事务,并且不会自动提交,除非手动 commit 或者断开连接,才会提交事务;

  2. 关闭自动提交,可能导致长连接意外导致的长事务,需要避免,所以建议使用 set autocommit=1 来开启自动提交,并在需要将多个操作放在一个事务时,通过显式 begin,commit 来操作;

  3. 如果执行 commit work and chain,表示提交事务后,自动启动下一个事务,这样节省了再次执行 begin 语句的交互开销;

  4. 并且事务的启动,是在执行第一条 sql 语句时才真正启动,而不是 begin 的声明处;

隔离性

  1. 隔离性,解决多个事务之间的脏读,不可重复读和幻读的问题,隔离级别和并发度是反向相关的;

  2. 读未提交,是指一个事务未提交时,它所做的变更可以被其他事务看到;读已提交,是指一个事务提交之后,他所作的变更才能被其他事务看到;

  3. 可重复读,是指事务在执行过程中,无论何时,对一个数据的重复读,总是一致的,串行化,就是读写都会加锁,锁冲突时,必须等待前一个事务执行完成;

MVCC 多版本控制

  1. 同一条记录在 InnoDB 中可以存在多个版本,每次事务更新数据时,会记录一段回滚日志,利用回滚日志就可以生成一个数据版本, 每个数据版本都有一个 row trx_id, 是由事务的 id 来标识的;

  2. 如果存在一个长事务,会存在很老的事务视图,就可能访问很早版本的数据,导致这部分回滚记录必须保留,这会大量占用存储空间,有时候为了清理大量的回滚段,需要重建整个库,所以不建议使用长事务,并且还可能长久占用锁资源;

	// 获取Mysql中超过60S的长事务
	select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60
  1. 普通查询语句,会根据 row trx_id 来构建 一致性视图,来确定数据版本的可见性;

一致性视图

  1. 读未提交,读写都是根据记录上的最新值,所以无法避免脏读,串行化,是加表锁的方式,访问数据,所以可以避免脏读,不可重复读,幻读;

  2. 读已提交和可重复读,都是通过创建一致性读视图,来实现隔离级别的访问的;

	一致性读视图并不是 create view 创建的视图概念,而是 InnoDB 在实现 MVCC 多版本控制时,根据 row_trx_id 来构建的一致性读视图;
  1. 读已提交,是在 sql 语句执行时创建的一致性视图,由 sql 语句执行前提交的事务数据组成,所以可以避免脏读,但无法避免不可重复读;

  2. 可重复读,是在事务启动就创建了一致性视图,然后整个事务过程都使用该视图,所以可以避免脏读,不可重读,但无法避免幻读,并且在可重复读隔离级别,更新数据时,都是先读后写的,这个读是当前读,可以读到当前其他事务已提交的值,就不会造成修改丢失;

  3. 示例,如图,

	读未提交下,V1 = 2,V2 = 2,V3 = 2
	读已提交下,V1 = 1,V2 = 2,V3 = 2
	可重复读下,V1 = V2 =1,V3 = 2
	串行化下,V1 = 1,V2 = 1,V3 = 2,因为锁,事务B想要修改值1,就必须等待事务A提交完成

Mysql基础课四:事务_第1张图片

当前读

  1. 除了 update 语句是当前读,select 语句如果加锁 lock in share mode 或者 for update ,这样也是当前读,并且当前读,如果数据被其他事务加锁,需要等待锁释放后读;

  2. 那么当前读,可以读到其他事务未提交的修改吗,结论是可以,但不是读到未提交的,而是当前读会加锁,而其他事务的 update 操作也会加锁,所以当前读的事务会等待,其他事务执行完释放锁之后,获取锁来读数据;

隔离级别的配置

  1. Oracle默认隔离级别是:读已提交,而Mysql的默认隔离级别是:可重复读,可以通过启动参数 transaction-isolation 来设置,通过 show variables 来查看当前值;

  2. 因为可重复读以上,会引入间隙锁,并发度会下降,如果业务不需要重复读的保证,可以设置为 读提交 的隔离级别,加上 binlog_format=row 的设置;

一致性视图和锁

  1. 根据两阶段锁协议,执行 update 语句会添加行锁,并且在事务提交时才会释放;

  2. 如下图,事务A显式开启了一个事务,并且开启时间是在执行 select 语句时才开启,事务B同样,事务C开启了一个自动提交的事务,命令 start transaction with consistent snapshot 会要求立即建立一致性视图;

  3. 在可重复读级别,初始化数据是 (1,1),对于事务 A 来说,视图创建时,事务 B 和 C 都没有提交,所以它们的修改都不可见,事务A 查询的结果是 (1,1);

  4. 可重复读下,因为 update 操作需要当前读,所以事务 B 修改后的结果是 (1,3),查询到的结果是(1,3);事务C 就修改为(1,2),并马上提交;

  5. 如果事务 A 的读,修改为 in share mode,读到的值就是(1,3)了,因为也是当前读,会等待事务 B 的锁释放,才加锁读数据;

  6. 如果是在读提交的隔离级别,事务A 读到的值是(1, 2),因为视图是在执行 select 语句时创建的;
    Mysql基础课四:事务_第2张图片

  7. 如果上面的例子,修改为如下,事务 A 读到的结果是(1,1),事务 B 修改和读到的结果都是(1,3),因为会等待事务 C‘ 的锁释放;
    Mysql基础课四:事务_第3张图片

你可能感兴趣的:(Mysql)