MySQL专栏(三)-->事务控制那些事

226 阅读4分钟

这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战

当前事务使用的过程中,主要对于数据更新以及读取过程中,结果不一致出现的概念:

事务:当前的操作要么全部失败,要么全部成功,

并发控制的基本单位

其中Innodb的存储引擎,对于数据库--> 支持事务,行锁

ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性)

** **

隔离级别的由来:

** **

因为多个事务执行的过程中会出现, 脏读,不可重复读,幻读的问题;

提出了解决这些问题的--事务的隔离级别:

** **

读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(serializable )

** **

  • 读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。

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

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

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

** **

问题解析解决方案隔离级别
脏读 数据读取到操作1未提交的假数据(读取到未提交事务的数据) 事务的隔离级别提高到-读已提交
不可重复读 操作2,读取共享数据,但是操作1,在没有提交之前,操作2读取了一次,提交完成之后读取一次(两次结果不一致)事务的隔离级别提高到-可重复读
幻读

数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准。

 

 1.在“可重复读”隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。

 2.在“读提交”隔离级别下,这个视图是在每个 SQL 语句开始执行的时候创建的。

 3.这里需要注意的是,“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念;

 4.而“串行化”隔离级别下直接用加锁的方式来避免并行访问

每条记录更新时,变更记录记载在redo log,回滚记录记载在undo log

将一个值从1-4, 

redolog日志会记录变更的日志信息, undo log日志会记录 回滚的视图日志信息

也就是说,现在值为4,我想回滚操作,就从undo log日志去取回滚操作日志的视图

事务的启动方式:

  

  

默认是自动提交事务, 一个sql语句代表一个事务,遵循ACID 的特性,然后我们开始使用具体的操作;

因为默认是自动提交的,所以我们首先要取消自动提交; 手动提交事务;

 

 set  autocommit=false
 set  autocommit=0

但是很多客户端和框架,会 自动取消提交事务,导致长链接事务,一直等待commit/rollback, 或者断开

 所以比较中肯的方案是,每次都提交事务, 并且自动开启下一个事务;

 

commit work and chain 

在 autocommit 为 1 的情况下,用 begin 显式启动的事务,如果执行 commit 则提交事务。

如果执行 commit work and chain,则是提交事务并自动启动下一个事务,这样也省去了再次执行 begin 语句的开销。同时带来的好处是从程序开发的角度明确地知道每个语句是否处于事务中。

对于上讲的两阶段提交, redo log日志是关于物理 ,bin log 是对于逻辑性,备份用的

因为是两阶段提交,这时候redolog只是完成了prepare, 而binlog又失败,那么事务本身会回滚,所以这个库里面status的值是0。

如果通过binlog 恢复出一个库,status值也是0。

这样不算丢失,这样是合理的结果。

提交的过程

1 prepare阶段 2 写binlog 3 commit 当在2之前崩溃时 重启恢复:后发现没有commit,回滚。备份恢复:没有binlog 。 一致 当在3之前崩溃 重启恢复:虽没有commit,但满足prepare和binlog完整,所以重启后会自动commit。备份:有binlog. 一致