标签:com 原理 插入 use https mode tail pat 持久化
做为开发人员对数据库事务应该都不陌生,但是如果知其然而不知其所以然的话,在开发中难免写出来的代码存在bug,本文主要介绍mysql中的事务,重点讲解事务的隔离级别。原子性是指事务是一个不可分割的工作单位,事务中的操作要么全部执行,要么全部都不执行。
例如:
begin // 开启事务
A:update user set account=account+1 where id =1;
B:update user set account=account+1 where id =1;
commit
这个事务,执行commit时,在么两条语句都执行成功,如果出错,执行rollback时,两条语句的操作都会回滚到原始状态;
undo log保证原子性
在操作任何数据之前,首先将数据备份到一个地方(这个存储数据的地方就是undo log)。然后进行数据的修改,如果用户出现了错误或者用户执行了rollback语句,系统可用利用undo log中的备份的数据恢复到事务开始之前的状态。
注意:undo log是逻辑日志
可以理解为:
事务执行前和事务执行后,数据库的完整性约束不被破坏。即事务的执行是从一个有效状态转移到另一个有效状态;
例如:
tom给jack转账50元,如果从tom账户减少后系统故障或其它原因没有给jack加上50元,而事务还没有执行完毕,数据库会将整个转账过程回滚,保证数据的一致性;
隔离性是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会互相干扰;
一旦事务提交成功,事务中所有的数据操作都必须被持久化保存到数据库中,即使提交事务后,数据库崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据。
redo log保证持久性
redo log记录的是新数据的备份,在事务提交前,只要将redo log持久化即可,不需要将数据持久化。当系统崩溃时,虽然数据没有持久化,但是redo log已经持久化,系统可以根据redo log的内容,将所有数据恢复到最新的状态。
上面介绍了数据库的事务特性,其中隔离性,是我们本文中重点需要解说的,设置不同的数据库事务之间的隔离级别,会解决相应的事务并发问题。那么下面说一下事务都会引起哪些问题:
事务A读取到了事务B已经修改但尚未提交的数据,如果事务B回滚,A读取的数据与上次不一致;不符合事务的一致性要求;
例如:A(图左)和B(图右)同时开启事务,A执行如下命令:
用户A并未提交事务,可见在事务B中两次查询的结果已经发生变化,读取了事务A中未提交的数据;
事务A读取到了事务B已经提交的修改数据,不符合隔离性;
上图可见,事务B读取到了事务A所修改的数据;
事务A读取到了事务B提交的新增数据,不符合隔离性;
事务B读取到了事务A提交的新增数据;
隔离级别等级:
查看隔离级别:
show variables like ‘%isolation%‘;
SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation;
设置隔离级别:
全局:SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
会话:SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
读未提交是数据库事务隔离级别最低的级别,它任何问题都没有解决;
设置数据库事务隔离级别为读未提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
读已提交它主要解决脏读的问题;
设置数据库事务隔离级别为读已交
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
可以看出,读已提交已经解决了脏读的问题;
设置事务隔离级别:
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
可以看到,就算事务A已经提交,事务B也不会再读到事务A提交的数据;
那么可重复读是否解决了幻读呢?
我们试验一下:
这是怎么回事呢?不是说好的可重复读不会解决幻读的问题吗?为什么这里新插入的数据就是没有在事务B中读取到呢? (下节解答)
串行化就不多说了,它其实是将事务按排队的处理方式,但是这样会使事务非常低率的。
我们先来看个示例:
从上面的执行过程可以看出,在A事务提交之后,B事务虽然执行查询时没有 问题,但是在B事务执行更新之后,再查询时,账户直接少了100;这是为什么呢?
InnoDB的MVCC通过每行记录后面的两个隐藏字段来实现的,创建时的版本号和删除时的版本号。每个事务开始版本号都会递增。
SELECT:
快照读:
读取的是快照版本,也就是历史版本;普通的select就是快照读
当前读:
读取的是最新版本,update、delete、insert、select...lock in share mode、select ... for update是当前读;
3.3节疑惑解答
事务A执行更新之后,提交了事务,而事务B再执行更新的时候,它其实是一个当前读,能够读取到最新的已经被事务A修改后的数据(前提事务A已经提交)。
这块内容比较复杂,可以参考:
https://blog.csdn.net/shenchaohao12321/article/details/92801779
标签:com 原理 插入 use https mode tail pat 持久化
原文地址:https://blog.51cto.com/13733462/2453460