文章目录
一. 事务的简介
- 事务的概念:事务是一个操作序列,该序列中有多个操作,要么都做,要么都不做。参考银行转账。
- 事物的特点:
- 原子性:原子是自然界最小的颗粒,具有不可再分的特点。事务中的所有操作可以看做是一个原子,要么全部执行,要么都不执行。
- 一致性:事务执行的结果必须要保证数据库中的数据的一致性。
- 隔离性:指的各个事务的操作时互不干扰的,任意一个事务的内部操作都对其他并发的事务都不能进行干扰。
- 持久性:指事务一旦提交后对数据库中的数据做出的任何改变都会永久保存。
二. 事务的控制
- 开启事务
-
语法:start transaction | begin 开启一个新的事务
-
创建一个库test5
-
创建一张表account(id账号主键唯一,username账号名,balance金额)
-
插入数据
-
-
例如:开启新事物,完成转账,完成张三给李四转账200
-- 创建表 create table account( id int(8) primary key auto_increment, username varchar(30), balance double ); -- 插入数据 insert into balance account(username,balance) values('张三',2000),('李四',2000) -- 查询数据 select * from account -- 完成张三给李四转账200 start transaction; update account set balance=balance-200 where username='张三'; update account set balance=balance+200 where username=';李四'; -- 关闭在重新启动,会发现,张三和李四账户中还是原来的2000元
-
注意:使用start transaction 开启一个新事物后,该事物不会自动提交必须手动提交
- 提交事务
-
语法:commit
-- 完成张三给李四转账200 start transaction; update account set balance=balance-200 where username='张三'; update account set balance=balance+200 where username=';李四'; -- 提交事务!!! commit; -- 查询张三李四账户信息,此时张三1800,李四2200 select * from account
- 回滚事务
-
语法:rollback;
-
注意:开启的事务,未提交时候可以回滚!已经提交的数据,没有办法回滚!
-
例如:回滚事务-- 完成张三给李四转账200
-- 完成张三给李四转账200 start transaction; update account set balance=balance-200 where username='张三'; update account set balance=balance+200 where username='李四'; -- 回滚 rollback;
三. 事务的隔离级别
- 【关于事物的隔离级别的博客】https://blog.csdn.net/l1394049664/article/details/81814090
- 【脏读;不可重复读;幻读 的博格】https://blog.csdn.net/qq_33591903/article/details/81672260
1. 基本概念
-
脏读:
脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。例如:用户A向用户B转账100元,对应SQL命令如下
update account set money=money+100 where name=’B’; (此时A通知B)
update account set money=money - 100 where name=’A’;
当只执行第一条SQL时,A通知B查看账户,B发现确实钱已到账(此时即发生了脏读),而之后无论第二条SQL是否执行,只要该事务不提交,则所有操作都将回滚,那么当B以后再次查看账户时就会发现钱其实并没有转。 -
不可重复读:
不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
例如事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发送了不可重复读。
不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
在某些情况下,不可重复读并不是问题,比如我们多次查询某个数据当然以最后查询得到的结果为主。但在另一些情况下就有可能发生问题,例如对于同一个数据A和B依次查询就可能不同,A和B就可能打起来了…… -
虚读(幻读):
幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。
SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。
-
事物的隔离级别用于决定如何控制并发用户读写数据的操作
-
事务隔离界别由低到高分为:
2. 事务级别
1. read uncommitted
-
定义:读取未提交的数据内容
-
例子:张三开启事务,进行转账操作,但是不提交事务;设置事务隔离级别为read uncommitted;查看事务隔离级别;开启事务,查询表中的数据,可以查询到位提交的数据。
-- 1.张三开启事务,进行转账操作,但是不提交事务 select * from account; start transaction; update account set balance=balance-200 where username='张三'; update account set balance=balance+200 where username='李四'; -- 2.设置事务隔离级别为read uncommitted set session transaction isolation read uncommitted; -- 3.查看事务隔离级别 select @@transaction_isolation; -- 4.开启事务,查询表中的数据,可以查询到位提交的数据 start transaction; select * from transaction; -- 回滚 rollback; ```
-
张三开启事务进行转账,但未提交事务,李四设置了隔离级别是read uncommitted,开启事务查询数据时就可以看到张三修改后的数据,如果张三现在做rollback回滚操作,则李四看到的数据就是脏数据(即进行了转账,但是未提交)。
2 read committed
-
定义:指的是读取提交的数据,该隔离界别下,所有事务只能看到其他事务已经提交的数据。该隔离级别解决了脏数据(脏读)的问题。
-
例如:设置李四创建窗口的隔离界别为read committed;查看设置是否成功;开启事务读取数据;张三开启事务进行转账,开始不提交事务,最后再提交事务。
-- 设置李四创建窗口的隔离界别为read committed set session transaction isolation read committed; -- 查看设置是否成功 select @@transaction_isolation -- 开启事务读取数据 start transaction select * from transaction -- 张三开启事务进行转账,现在不提交事务 start transaction; update account set balance=balance-200 where username='张三'; update account set balance=balance+200 where username='李四'; -- 最后再提交事务 commit; ```
-
总结:李四设置的隔离级别是read committed,开启事务查询数据,张三开始事务进行转账,但不提交事务,李四查询数据时候没有看到转账的数据,还是原来的数据;当张三提交了事务,李四查询数据时候可以看到提交后的数据,这样解决了脏读的问题,但是李四前后两次读取数据结果不一致,则read committed不能解决repeatable(重复读)的问题。
3. repeatable read
-
定义:指可重复读,即两次读取的结果要一致;是MYSQL默认的隔离级别。
-
例如:设置李四窗口的隔离级别为repeatable read,查看设置是否成功;开启事务读取数据;张三开启事务进行转账,不提交事务;提交事务
-- 设置李四窗口的隔离级别为repeatable read,查看设置是否成功 set session transaction isolation repeatable read; select @@transaction_isolation; -- 开启事务读取数据 start transaction; select * from transaction; -- 张三开启事务进行转账,不提交事务; start transaction; update account set balance=balance-200 where username='张三'; update account set balance=balance+200 where username='李四'; -- 提交事务 commit; ```
-
总结:李四设置隔离级别repeatable read,开启事务查询数据,张三开始事务进行转账,但不提交数据,李四查询数据,则看到还是原来的数据;张三提交事务,李四查询数据,看到的数据还是原来的数据,查询两次,前后数据都是相同的,则repeatable read解决了不可重复读取的问题。
-
例如:李四创建设置隔离级别repeatable read;查询是否设置隔离级别成功;开始事务查询数据;张三开始事务插入数据,并提交
-- 李四创建设置隔离级别repeatable read set session transaction isolation repeatable read; -- 查询是否设置隔离级别成功 select @@transaction_isolation; -- 开始事务查询数据 start transaction; select * from transaction; --张三开始事务插入数据,并提交 start transaction; insert into account(username,balance) vaules ('王五',2000); commit; ```
-
测试:李四设置隔离级别 repeatable read,但是没有产生幻读问题,因为:MySQL中的InnoDB存储引擎使用(MVCC机制)解决了repeatable read下的幻读问题。
-
接着设置隔离级别为read committed,演示:
-- 李四创建设置隔离级别repeatable read set session transaction isolation read committed; -- 查询是否设置隔离级别成功 select @@transaction_isolation; -- 开始事务查询数据 start transaction; select * from transaction; --张三开始事务插入数据,并提交 start transaction; insert into account(username,balance) vaules ('赵六',2000); commit; ```
-
设置隔离级别为read committed,开启事务查询数据,另一个事务进行插入数据,并提交,在查询中再次查询,结果可以查询到刚刚插入的数据’赵六‘,则产生幻读。
4. serializable
-
定义:可串行化;该隔离级别是最高的,同时花费也是最大的,性能最低,一般很少用。因为在该隔离级别下,事务是按照顺序执行。
-
例如:
-- 李四创建设置隔离级别repeatable read set session transaction isolation serializable; -- 查询是否设置隔离级别成功 select @@transaction_isolation; -- 开始事务查询数据 start transaction; select * from transaction; -- 开启事务,插入数据,并提交(查看是否可以插入) start transaction; insert into account(username,balance) vaules ('孙琦',2000); commit; ```