事务

事务

什么是事务

一个事务是一个完整的业务逻辑单元,不可再分
比如:银行账户转账,从A账户向B账户转账1000,需要执行两条update语句

update t_a set balance - 1000 where actno='act-001';
update t_a set balance + 1000 where actno='act-002';

以上两条DML语句必须同时成功,或者同时失败,不允许出现一条成功,一条失败。

和事务相关的语句只有:DML语句(insert delete update)

为什么
因为这三个语句都是和数据库表当中的 数据 相关的。
事务的存在是为了保证数据的完整性,安全性

事务的特性?

事务包括四大特性:ACID
A:原子性:事务是最小的工作单元,不可再分。
C:一致性:事务必须保证多条DML语句同时成功或者同时失败
I:隔离性:事务A与事务B之间具有隔离。
D:持久性:持久性说的是最终数据必须持久化到硬盘文件中,事务才算成功的结束

关于事务之间的隔离性

事务隔离性存在隔离级别,理论上隔离级别包括4个

  • 第一级别:读未提交(read uncommitted)
    • 对方事务还没有提交,我们的当前事务可以读取到对方未提交的数据。
    • 读未提交存在脏读(Dirty Read)现象:表示读到了脏的数据
  • 第二级别:读已提交(read committed)
    • 对方事务提交之后的数据我方可以读取到。
    • 读已提交存在的问题是:不可重复读

例子:现在A表有5条数据 ABCDE,我读取到5条, 此时对方已经提交了删除 A数据,我现在再去读就变成了 BCDE,如果此时对方又提交了删除B数据,我再去读取就变成了CDE

  • 第三级别:可重复读(repeatable read)

    • 这种隔离级别解决了:不可重复读问题
    • 这种隔离级别存在的问题是:读取到的数据是幻想。
  • 第四级别:序列化读/串行化读(serializable)

    • 事务A与事务B不能并发,只能排队。这种隔离级别最高,效率最低,数据最安全 ,解决了所有问题
    • 问题:效率低,需要事务排队

使用两个事务演示以上的隔离级别

第一演示readuncommitted

设置事务的隔离级别

set global transaction isolation level read uncommitted;

查看事务的全局隔离级别:

mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| READ-UNCOMMITTED      |
+-----------------------+
1 row in set, 1 warning (0.00 sec)

## 第二演示read committed读已提交

第一步

-- 设置事务的隔离级别
mysql> set global transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)
-- 查看事务的隔离级别
mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| READ-COMMITTED        | -- 读已提交
+-----------------------+
1 row in set, 1 warning (0.00 sec)

mysql> exit   -- 退出 重进
Bye
mysql> use rzk;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed



-- 打开两个窗口进行操作
mysql> start transaction;  -- 打开MySQL在第一个窗口执行
Query OK, 0 rows affected (0.00 sec)
mysql> start transaction;  -- 打开MySQL在第二个窗口执行
Query OK, 0 rows affected (0.00 sec)


mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zhangsan |
|  2 | lisi     |
|  3 | lisan    |
|  4 | lin      |
|  5 | linkimn  |
|  6 | waghjn   |
|  7 | uyjjn    |
+----+----------+
7 rows in set (0.00 sec)

第二步在第二个窗口进行插入

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

第三步插入完成后在第一窗口查看有没有插入成功

mysql> select * from t_user;  -- 可以看到未成功
+----+----------+
| id | username |
+----+----------+
|  1 | zhangsan |
|  2 | lisi     |
|  3 | lisan    |
|  4 | lin      |
|  5 | linkimn  |
|  6 | waghjn   |
|  7 | uyjjn    |
+----+----------+
7 rows in set (0.00 sec)

第四步在插入的窗口里面进行commit提交

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

第五步 返回第一个窗口查询

mysql> select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zhangsan |
|  2 | lisi     |
|  3 | lisan    |
|  4 | lin      |
|  5 | linkimn  |
|  6 | waghjn   |
|  7 | uyjjn    |
| 10 | rzk      |  -- 此时就可以看到数据已经插入成功
+----+----------+
8 rows in set (0.00 sec)

第三演示 repeateble read 可重复读

设置事务隔离级别

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

mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ       |
+-----------------------+
1 row in set, 1 warning (0.00 sec)

退出,重登

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

在窗口二删除数据,窗口一查看数据
窗口二 commit; 窗口一的数据还是不会变
可为什么读到数据了呢,其实读到的是备份数据,幻想,这种就是可重复读

第四演示serializable

第一步开启事务

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

mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| SERIALIZABLE          |
+-----------------------+
1 row in set, 1 warning (0.00 sec)

mysql> exit  -- 重进
Bye

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

可以看到第一条插入,然后在去另一个窗口查询,查询就卡住了,
必须要等第一个事务执行完毕才能去执行下一个事务

原文地址:https://www.cnblogs.com/rzkwz/p/13301629.html