前言
TCL:Transaction Control Language,事务控制语言,这个是数据库中最最基础的一部分,也是在面试中最常提到的问题,这块尽可能的详细介绍一下。
一、概念
一个或一组SQL语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行,这样就可以称之为是事务。
怎么理解呢,在网上搜索mysql事务,在大多数中都是以一个转账的案例展开,这里也不例外,可以想到有小富婆和小乞丐两个人,下面是这两个人的银行账户情况
姓名 | 余额 |
---|---|
小富婆 | 1000 |
小乞丐 | 10 |
先以一个故事展开,有一天小乞丐在外面行乞,很是可怜,这个时候一个小富婆看到了他,感觉这个娃真的是太不容易了,就要施舍一点钱给他,但是没带钱,只能去银行转账给他(去银行,我就是不取现金,诶,就是玩),这个时候富婆决定转账100给小乞丐,那么小乞丐和富婆现在的账户情况是:
姓名 | 余额 |
---|---|
小富婆 | 900 |
小乞丐 | 110 |
这样的情况是正确的对吧,但是如果保证这个情况呢,要知道在数据库中要对这两条数据进行操作的话,会进行两步SQL,一、在小富婆账户中减去100元,二、在小乞丐账户中加上100元,这样才完成了整个转账操作。那么可不可能出现一种情况,当完成第一步的时候,第二部失败,那么可能就会出现下面的账户情况:
姓名 | 余额 |
---|---|
小富婆 | 900 |
小乞丐 | 10 |
这样凭空少了100元,还有一种情况,就是给小乞丐增加了100元,但是在小富婆账户中减去100元的时候失败了。
姓名 | 余额 |
---|---|
小富婆 | 1000 |
小乞丐 | 10 |
不管下面的哪种情况,都不是我们想要的,那要如何保障我们想要的情况发生呢,这个就是SQL事务的意义了,当一次操作要分为多个SQL语句进行,并且相互之间是有一种依赖关系,那么我们就可以将它看成是一个事务,事务也必须具有四大特性,那就是一致性、原子性、隔离性、持久性,通过这四大特性来约束事务的完成和失败。
这里要了解一下数据库的存储引擎:
在Mysql中数据用各种不同的技术存储在文件(或内存)中,这个就是存储引擎。
通过show engines;
来查看mysql支持的存储引擎
在Mysql中用的最多的存储引擎是innodb
,这个存储引擎是支持事务的。注:有些存储引擎可能是不支持事物的。
二、特性
事务的特性就像上面提到的,是四大特性ACID,A(Atomicity)原子性、C(Consistency)一致性、I(Isolation)隔离性、D(Durability)持久性,下面分开介绍,这里比较重要的就是Isolation。
1 Atomicity原子性
原子性就是上面例子中,需要将两次数据库操作看成是一个原子性的操作,也就是这两次操作是不允许中断的,要么全部成功,要么全部失败。
也就是事务是一个不可分割的工作单元,事务中的操作要么发生,要么不发生。
2 Consistency一致性
事务必须使数据库从一个一致性的状态变换到另外一个一致性的状态。好比如上面例子中,对于银行来讲小富婆和小乞丐的账户总额是1010元,如果他们之间如果转账,最后的他们的总额还是1010元,这个状态是不会改变的。
3 Isolation 隔离性
隔离性是四大特性中面试最容易遇到的,因为这个相对于其他三个特性来讲会难理解一些。
事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
其实这个不能互相干扰,我认为理解为在业务上不能因为多个事务执行而导致出现预料之外的结果会更好一些,因为事务并不是越隔离越好,也不是真的互相之间不关联就是最完美的状态,这个要根据具体的业务具体分析。
提到Isolation就不得不提到在多事务并发处理时可能存在的问题:赃读、不可重复读、幻读
赃读:
当数据库中的一个事务A正在修改一个数据但是还没有提交或回滚的时候,另外一个事务B来读取修改后的内容并且使用了,之后事务A提交了,此时就引起了赃读。
此种情况发生在读未提交的隔离级别。
不可重复读:
在一个事务A中多次操作数据,在事务操作过程中,事务B也做了处理,并且该值发生了改变,这时候就会导致A在事务操作的时候发现数据与第一次不一样了,这就是不可重复读;
这种情况发生在读未提交、读已提交的隔离级别。
幻读:
一个事务按相同的查询条件重新读取以前检索过的数据,发现了其他事务新插入满足该检索条件的数据,这种现象可以称之为幻读。
幻读和不可重复读的区别就是范围,不可重复读指的是本身,而幻读指的是一个区间,解决幻读的方法就是加范围锁。
这里有一点要注意,在InnoDB引擎中已经在可重复读的级别中解决了幻读问题,具体细节可以自行百度。
基于上面的问题,Mysql的隔离级别可以分为:
读未提交、读已提交、可重复读、串行化
- 读未提交:一个事务还未提交,它所做的变更就可以被其他事务所看到;
- 读已提交:一个事务提交后,它所做的变更才可以被别的事物看到;
- 可重复读:一个事务执行过程中看到的数据是一致的,未提交的更改对其他事物对其他事务是不可见的;
- 串行化:对应一个记录会加读写锁,出现重读的时候,后访问的事务必须等待前面一个事务执行完成才能继续执行。
关于隔离级别要深入的话,涉及到方方面面在,想深入了解的朋友可以综合多查看几篇文章。
这里推荐一个我借鉴的博客
4 Durability 持久性
持久性是指一个事务一旦被提交,他对数据库中数据的改变就是永久性的,接下来其他操作和数据库故障不应该对其有任何影响。
这个也是数据库的最基本的特性。
三、使用
Mysql事务默认是自动提交的,可以使用下面语句进行查询当前数据库自动提交的属性。
SHOW ENGINES; # 查看当前数据所支持的存储引擎
SHOW VARIABLES LIKE 'autocommit'; # 查看当前数据库支持事务自动提交的状态
基本使用事务的语句
SET autocommit=0; # 开启事务
BEGIN; # 开启事务
/* ...*/
UPDATE grade_new SET `studentId`=6 WHERE id=10; # 事务中的sql语句
/* ...*/
ROLLBACK; # 回滚事务
COMMIT; # 提交事务
开启事务是有两种形式,使用的比较多的还是BEGIN
,但是不管是哪种开始事务的方式都是一样的作用,并且开启事务只对当前事务有效,下次如果不开启事务的话,事务是不会主动开启的。
回滚事务,恢复到事务执行之前的状态,也就是相当于没有执行事务。
提交事务,将当前事务所做的变更作为一个原子性的操作同步到内存中。
结语
关于这节其实写的很不好,大家权当一个入门简单了解,不过虽然不够详细,但是应该是没有错误,至于为什么没有深入去写,根本原因还是个人能力不能,对更详细的锁了解不是很清楚,怕误导大家,后续会整理关于锁的内容,到时候有机会的话,再整理这一节吧