文章目录
前言
会话事务隔离级别的英文单词:
- session Transactional isolation level
- 会话 事务 隔离 级别
全局事务隔离级别的英文单词:
- global Transactional isolation level
- 全局 事务 隔离 级别
一、什么是事务?
刚开始学,我的理解是:有很多条语句组成的,就是事务。但是,事务并不只是简单的sql语句的组合,还有一些特性。
课件的解释如下:
1.关于事务的特性
原子性:
- 要么全部完成,要么全部不完成,不会结束在中间的某个环节。如果一个事务在中间的过程出错,就会回滚到事务开始前的状态。
比如我要从建设银行中取出100块钱转账到朋友的建设银行卡中,那么这个事务处理就一定是:我的银行卡金额-100,对方的银行卡金额+100,不可能结束中间的某个环节。如果在转账过程中,网络出现问题导致转账失败,意味着该事务出错,那一定是我的银行卡金额-100,然后再+100。相当于什么都没发生。
持久性:
- 事务处理结束后,对数据的修改就是永久的,即使系统故障也不会丢失。就像上面的例子,转账完成后,我的银行卡少了100,对方银行卡多了100,这个修改是永久的。
一致性和隔离性,关于这两个特性,后面再说,现在不理解。
二、为什么要有事务
事务被 MySQL 编写者设计出来,本质是为了当应用程序访问数据库的时候,事务能够简化我们的编程模型,不需要我们去考虑各种各样的潜在错误和并发问题.可以想一下当我们使用事务时,要么提交,要么回滚,我们不会去考虑网络异常了,服务器宕机了,同时更改一个数据怎么办对吧?因此事务本质上是为了应用层服务的.而不是伴随着数据库系统天生就有的.
事务就是用来当有一批sql语句过来时,将这些语句打包成一个事务对象,这个对象就是事务,再交给事务执行列表,交给MySQL处理。
所以事务就是一个执行对象。帮助我们更简单地处理sql语句。
注意:在MySQL中,只有使用了Innodbs数据库引擎才支持事务。 MyISAM不支持。
三、事务的提交方式
- 自动提交
- 手动提交
查看事务提交方式
show variables like ‘autocommit’;
当执行下面sql语句后:
set autocommit=0;
意味着将事务的自动提交功能关闭了。
set autocommit=1;就会重新打开。
测试事务
准备工作
1.先将事务隔离级别设置成读未提交。(先不用管能不能看懂,先按照步骤进行操作)
mysql> set global transaction isolation level READ UNCOMMITTED;
需要先重启,才能生效。
事务的操作
1.启动事务
法1:
start transaction;
法2:
begin;(推荐)
从启动事务开始之后的所有sql语句,都属于事务。
2.对事务进行回滚(只有在事务进行期间)
1:一次性回滚到最开始
rollback;
2:回滚到某个保存点
rollback to 保存点名字;
先设置保存点:
savepoint s1;再插入数据
insert into account values(1,‘张三’,1000,1);
更多sql语句如下图:
完成后,结果如下:
再执行下面的sql语句:
rollback to s3;
该语句的意思是:回滚到s3这个保存点,也就是在s3之后执行的所有sql语句,都会被撤回。
此时,第三条insert语句就被回滚了。
再回滚到s1,就会发现,插入的所有数据都被撤回了。
3.提交事务(持久化)
要在最一开始进行启动事务后,才能提交事务。
mysql> commit;
也就是将事务内的一堆指令,交给MySQL处理。
4.事务的异常情况
在事务的执行期间,碰到mysql突然中断的情况,mysql的处理是对事务进行自动回滚。
在插入了一条语句后,我们手动关闭mysql客户端:
发现插入的数据并没有上一条数据。
这是因为遇到异常中断时,事务会自动回滚到最开始。
还有一点需要说明:
begin操作会自动更改提交方式,不会受MySQL是否自动提交影响。
只要我们启动事务,就会将自动提交设置成关闭状态。
结论
四、事务的隔离级别
1.理解隔离性
关于事务的原子性,就是 “要么有,要么没有” 的正反两面性,在这样的情况下,事务会出现:事务处理前,事务处理时,事务处理后三种情况。
而原子性就只关心事务处理前和处理后的情况,不关心事务具体怎么处理。
就像有的家庭中的妈妈对儿子说:”你要么就不学,要学你就学好“。对于妈妈来讲,只有学好和不学这两种情况,就是原子性,妈妈不关心儿子具体怎么学,学习过程是否遇到困难的情况。而对于儿子来说,学习过程可能会遇到各种各样的困难,学习环境的不同也会影响学习,所以,儿子需要隔离出一个良好的学习环境,这个就叫做隔离性。
- 数据库中,为了保证事务执行过程不受干扰,就有一个特性:隔离性。
- 数据库中,允许事务受不同程度的干扰,就有一个特性:隔离等级。
2.隔离级别
1.读未提交【Read Uncommitted】
这种隔离级别等于未隔离。几个事务之间可以看到其他事务没有提交的结果。
(实际中不会用这种)
2.读提交【Read Committed】
该隔离级别是大多数数据库默认的级别(但MySQL不是)。
一个事务智能看到其他已经提交的事务作出的改变。
3.可重复读【Repeatable Read】
MySQL默认的隔离级别。它确保同一个事务,在执行
中,多次读取操作数据时,会看到同样的数据行。
4.串行化【Serializable】
这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突,
从而解决了幻读的问题。它在每个读的数据行上面加上共享锁,。但是可能会导致超时和锁竞争
(这种隔离级别太极端,实际生产基本不使用)
5.查看与设置隔离级别
查看隔离级别
SELECT @@global.tx_isolation; --查看全局隔离级别
SELECT @@session.tx_isolation; --查看会话(当前)全局隔离级别
SELECT @@tx_isolation; --默认查看回话全集隔离级别
设置隔离级别
– 设置当前会话 or 全局隔离级别语法 SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
设置会话事务隔离级别时,只会影响当前回话,另起一个会话时不受影响。
例:
设置会话事务隔离级别为读提交。
mysql> set session transaction isolation level read committed;
可以看到设置成功了
同理,设置全局事务隔离级别未读未提交:
set global transaction isolation level read uncommitted;
设置全局的,会对每一个会话都产生影响。
读未提交的问题——脏读问题
在设置全局事务读未提交的情况下:
在会话1中插入的数据,还没提交,在会话2中就能无障碍地看到,这样的现象叫做脏读。
左边回话1刚插入数据,还没commit,右边会话2就能立刻读到了。
读提交的问题——不可重复读问题
设置了全局会话隔离级别为:read committed;
在会话A中手动启动事务:begin;
同时启动会话B的事务,在会话B中查询account表格内容如下:
在会话A中,(注意,会话A和会话B都处于事务状态),插入一条新的值:
在会话A进行事务提交前,查询会话B:
发现没有看到会话A中插入的那条数据。
但是,在会话A进行事务提交后:commit;
再次查询会话B,就看到了会话A插入的那条数据。
要知道,会话B始终处于事务状态!!!
意味着在事务过程的不同时间段,查询相同的表,发现查询到的数据不一样!!!!
读取到了不同的值,这种现象叫做不可重复读(non reapeatable read)
实际上,这也是一个问题,是大问题。
可重复读——幻读问题
可重复读就完美解决了上面的在两个并发的事务中,一个事务在插入数据,另一个查到了在对方事务插入数据前和插入数据后的变化不一样的情况。
(本质上是用了加锁+其他策略解决)
幻读发生在一个事务重新执行一个查询时,返回了一组不同的行,因为另一个并发的事务在这段时间内插入或删除了符合查询条件的记录。
这就好像出现幻觉一样。