mysql事务及事务隔离级别实践

mysql事务

事务是指一个完整的业务逻辑。A向B转账时,A-100;B+100,这是一个完整的业务逻辑,是最小的工作单元,要么同时成功,要么同时失败,不可再分,如此才能保证正确性。

只有DML语句才有事务概念,其他的与事务无关

insert\delete\update

涉及到数据的增删改,数据的安全就需要考虑,就需要使用事务。

事务实现机制

InnoDB提供了一组用来记录事务性活动的日志文件。

事务开启了:
insert
insert
delete
delete
事务结束了;

在事务的执行过程中,每一条DML的操作都会记录到事务性活动的日志文件中,在事务的执行过程中,我们可以提交事务,也可以回滚事务。

当一个事务提交时,innodb会清空事务性活动的日志文件,将数据全部持久化到数据库表中,提交事务标志着事务的结束,并且是一种全部成功的结束。

回滚事务是将之前的dml操作全部撤销,并且清空事务性活动的日志文件,回滚事务标志着事务的结束,是一种全部失败的结束。

如何提交事务与回滚事务?

提交事务:commit
回滚事务:rollback
事务:transaction

mysql默认情况下是支持自动提交事务,每执行一次DML语句,自动提交一次,回滚永远只能回滚到上一次的提交点。

那如何关闭mysql的事务自动提交机制?

start transaction;

使用以上的命令,就可以手动控制事务的提交以及回滚。

事务四个特性

A:原子性,事务是最小的工作单元,不可再分

C:一致性,所有的事务要求,在一个事务当中,所有的操作要么同时成功,要么同时失败,以保证数据的一致性

I:隔离性,A事务和B事务之间具有一定的隔离,A事务在操作一张表时,B事务也操作一张表时会如何?多线程访问同一张表时。

D:持久性,事务最终结束的一个保障,事务提交,就相当于把没有保存在硬盘上的数据保存在硬盘上。

重点研究一下隔离性

隔离性有强弱之分,就是隔离级别。

4个隔离级别

读未提交:read uncommitted(最低的隔离级别)
	事务A可以读取到事务B未提交的数据,这种隔离级别存在脏读现象,dirty read,称为读到了脏数据。此种隔离级别都是理论上的,基本没人用。

读已提交:read committed
	事务A只能读取到事务B提交之后的数据,这种隔离级别解决了脏读现象,这种隔离级别存在不可重复读取数据,例如事务开启之后,第一次读取的数据是3条,当前事务还没结束,可能第二次再读取的时候,读到的数据是4条,3不等于4称为不可重复读。这种隔离级别是比较真实的数据,每一次读到的数据是绝对的真实。

可重复读:repeatable read
	事务A开启之后,不管是多久,每一次在事务A中读取到的数据是一致的,即使事务B已经修改了数据并且提交了,事务A读取到的数据还是没有发生改变,读取到的数据前后一致,这就是可重复读。可重复读的问题,可能存在数据的幻影,每一次读取到的数据都是幻想,不够真实。mysql中的默认隔离级别就是可重复读。

序列化/串行化:serializable(最高的隔离级别)
	最高隔离级别,效率最低,解决了所有的问题,这种各级级别表示事务排队,不能并发。在这种隔离级别下,一个事务想要运行,必须要等到前面的事务处理完成才能开启。

验证以上四个事务隔离级别

read uncommitted
1.创建一张表
mysql> create table t_user(name varchar(255));
Query OK, 0 rows affected (0.03 sec)

mysql> select * from t_user;
Empty set (0.00 sec)

同时打开两个终端

在这里插入图片描述

查看事务隔离级别

mysql5.0版本是这样查的
mysql> select @@tx_isolation;
ERROR 1193 (HY000): Unknown system variable 'tx_isolation'

8.0版本命令
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)
查出当前的默认隔离级别为可重复读

设置隔离级别

mysql> set global transaction isolation level read uncommitted;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)
发现仍然是可重复读,此时退出数据库重新进入
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-UNCOMMITTED        |
+-------------------------+
1 row in set (0.00 sec)
再次查看当前事务隔离级别,发现已经修改。 

两个终端同时开启事务

在这里插入图片描述

在终端A中插入一条数据

在这里插入图片描述

在终端B中查看数据

在这里插入图片描述

发现,事务还没有提交,另一个地方就可以看到数据了,假如此时A终端rollback了,B终端恰好将数据取出来拿到程序中,那就出现了脏读现象。

read committe

接下来切换read committed验证

mysql> set global transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)

退出mysql重新登录
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-COMMITTED          |
+-------------------------+
事务隔离等级已经修改完成

在这里插入图片描述

还是两个终端打开事务,A终端插入一条数据“lisi”

A终端的命令如下
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t_user values("lisi");
Query OK, 1 row affected (0.01 sec)

mysql> select * from t_user;
+----------+
| name     |
+----------+
| zhangsan |
| lisi     |
+----------+	

B终端查看表

mysql> select * from t_user;
+----------+
| name     |
+----------+
| zhangsan |
+----------+
1 row in set (0.00 sec)
发现lisi不能读取到!与刚才的read uncommitted不一样。

A终端提交事务!

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from t_user;
+----------+
| name     |
+----------+
| zhangsan |
| lisi     |
+----------+
2 rows in set (0.00 sec)

B终端再次查表

mysql> select * from t_user;
+----------+
| name     |
+----------+
| zhangsan |
| lisi     |
+----------+
2 rows in set (0.00 sec)
当事务提交以后,就可以看得到A终端提交的数据,如此解决了脏读的发生。
repeatable read

修改事务隔离等级

mysql> set global transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)

查看表中数据

mysql> select * from t_user;
+----------+
| name     |
+----------+
| zhangsan |
| lisi     |
+----------+
2 rows in set (0.00 sec)

A、B终端同时开启事务

start transaction;

A终端插入三条数据

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t_user values("abc");
Query OK, 1 row affected (0.00 sec)

mysql> insert into t_user values("abc");
Query OK, 1 row affected (0.00 sec)

mysql> insert into t_user values("abc");
Query OK, 1 row affected (0.00 sec)

mysql> select * from t_user;
+----------+
| name     |
+----------+
| zhangsan |
| lisi     |
| abc      |
| abc      |
| abc      |
+----------+
5 rows in set (0.00 sec)

B终端查看表中数据

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t_user;
+----------+
| name     |
+----------+
| zhangsan |
| lisi     |
+----------+
2 rows in set (0.00 sec)

A终端提交事务

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

B终端查看表

mysql> select * from t_user;
+----------+
| name     |
+----------+
| zhangsan |
| lisi     |
+----------+
2 rows in set (0.00 sec)
发现当A中的事务提交后,B中查到的数据是在A事务完成前的表中数据,也就是说B的事务查到的是数据是一个A事务发生前版本的数据。

将B中的事务提交后查看表

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t_user;
+----------+
| name     |
+----------+
| zhangsan |
| lisi     |
| abc      |
| abc      |
| abc      |
+----------+
5 rows in set (0.00 sec)

发现当A中的事务提交后,B中查到的数据是在A事务完成前的表中数据,也就是说B的事务查到的是数据是一个A事务发生前版本的数据。




将B中的事务提交后查看表

```sql
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t_user;
+----------+
| name     |
+----------+
| zhangsan |
| lisi     |
| abc      |
| abc      |
| abc      |
+----------+
5 rows in set (0.00 sec)

至此三种事务隔离性就全部验证完成,最后一种事务隔离级别是阻塞的,当一个事务正在执行时,另一个事务会阻塞住,终点掌握可重复读、读已提交。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值