事务transaction(重点)必须理解,必须掌握
- 什么是事务(transaction):
一个事务就是一个完整的业务逻辑
如:转账事务:从A账户向B账户中转账10000元
该事务的完成步骤为:
将A账户的钱减去10000(update语句)
将B账户的钱加上10000(update语句)
所有步骤完成就是一个完整的业务逻辑,是一个最小的工作单元,要么同时成功或者同时失败,不可再分,这样才能保证钱是正确的 - 只有DML语句才会有事务这一说
insert
delete
update
只有以上三个语句与事务有关系,因为只有这三个语句是对数据库表中的数据进行增删改操作,而在数据库中只要涉及增删改操作就一点要考虑数据的安全问题
数据安全第一位
- 事务的存在
正是因为做某件事的时候,需要多条DML语句共同联合起来才能完成,所以需要事务的存在。如果任何一件复杂的事儿都能一条DML语句搞定,那么事务则没有存在的价值了。本质上,一个事务其实就是多条DML语句同时成功,或者同时失败。 - 事务的原理
InnoDB存储引擎:提供了一组用来记录事务性活动的日志文件
在事务的执行过程中,每一条DML语句的操作都会记录到“事务性活动的日志文件”中。
在事务的执行过程中,我们可以提交事务,也可以回滚事务。
提交事务:
清空事务性活动的日志文件,将数据全部彻底持久化到数据库表中。
提交事务标志着事务的结束。并且是一种全部成功的结束。
回滚事务:
将之前所有的DML操作全部撤销,并且清空事务性活动的日志文件
回滚事务标志着事务的结束。并且是一种全部失败的结束。 - 事务的提交与回滚
提交事务:commit; 语句
回滚事务:rollback; 语句(回滚永远都是只能回滚到上一次的提交点)
在MySQL当中,默认情况下是支持自动提交事务的。即每执行一条DML语句执行一次
关闭事务自动提交(回滚):start transaction;
mysql> select * from t_user;
+------+------+------+
| id | name | sex |
+------+------+------+
| 2 | abc | m |
+------+------+------+
1 row in set (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into t_user(id,name,sex) values
-> (1,'mmm','m'),
-> (3,'www','w');
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> rollback;
Query OK, 0 rows affected (0.01 sec)
mysql> select * from t_user;
+------+------+------+
| id | name | sex |
+------+------+------+
| 2 | abc | m |
+------+------+------+
1 row in set (0.00 sec)
提交事务:
mysql> use test
Database changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| t_student |
| t_user |
+----------------+
2 rows in set (0.04 sec)
mysql> select * from t_user;
+------+------+------+
| id | name | sex |
+------+------+------+
| 2 | abc | m |
+------+------+------+
1 row in set (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into t_user(id,name,sex) values
-> (1,'aaa','m'),
-> (3,'bbb','m');
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from t_user;
+------+------+------+
| id | name | sex |
+------+------+------+
| 2 | abc | m |
| 1 | aaa | m |
| 3 | bbb | m |
+------+------+------+
3 rows in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_user;
+------+------+------+
| id | name | sex |
+------+------+------+
| 2 | abc | m |
| 1 | aaa | m |
| 3 | bbb | m |
+------+------+------+
3 rows in set (0.00 sec)
- 事务的特性ACID
A-原子性(Atomicity):
说明事务是最小的工作单元, 一个事务是一个不可分割的最小单位,事务中的所有操作要么全部成功,要么全部失败,没有中间状态。
C-一致性(Consistency):
事务执行之前和执行之后数据都是合法的一致性状态,即使发生了异常,也不会因为异常引而破坏数据库的完整性约束,比如唯一性约束等。
I-隔离性(Isolation):
每个事务是彼此独立的,不会受到其他事务的执行影响,事务在提交之前对其他事务不可见。隔离性通过事务的隔离级别来定义,并用锁机制来保证写操作的隔离性。
D-持久性(Durability):
事务提交之后对数据的修改是持久性的,即使数据库宕机也不会丢失,通过事务日志中的重做日志(redo log)来保证。事务修改之前,会先把变更信息预写到 redo log 中,如果数据库宕机,恢复后会读取 redo log 中的记录来恢复数据
事务并发处理中可能出现的异常情况
- 脏读:脏读指一个事务访问到了另一个事务未提交的数据
- 不可重复读:不可重复读指一个事务多次读取同一数据的过程中,数据值内容发生了改变,导致没有办法读到相同的值,描述的是针对同一条数据 update/delete 的现象
- 幻读:幻读指一个事务多次读取同一数据的过程中,全局数据(如数据行数发生了改变,仿佛产生了幻觉,描述的是针对全表 insert/delete 的现象
隔离级别(重点)
串行化的事务处理方式当然是最安全的,但是串行无法满足数据库高并发访问的需求,作为妥协,有时不得不降低数据库的隔离标准来换取事务的并发能力,通过在可控的范围内牺牲正确性来换取效率的提升,这种权衡通过事务的隔离级别来实现。
数据库有 4 种事务隔离级别,由低到高依次为
- 读未提交 Read Uncommitted:事务A可以读取到事务B未提交的数据,存在脏读现象(Dirty Read)。这种隔离级别一般都是理论上的,大多数数据库隔离级别都是二挡起步
- 读已提交 Read Committed :事务A只能读到事务B提交之后的数据。解决了脏读现象,但是不可重复读
这种隔离级别是比较真实的数据,每一次读取到的数据是绝对的真实。读已提交是oracle数据库默认的隔离界别- 可重复读 Repeatable Read :事务A开启之后,不管是多久,每一次在事务A中读取到的数据都是一致的,即使事务B将数据修改并提交了,事务A读取到的数据还是没有发生改变。
解决了不可重复读取数据,但是可能会出现幻读,即每一次读取到的数据都是幻象,不够真实。
MySQL中的默认隔离级别是可重复读- 串行化(序列化) Serializable :这是最高隔离级别,效率最低,解决了所有问题。但是这种隔离级别表示事务排队,不能并发(相当于同步)
隔离级别演示——看视频老杜带你学MySQL
1.查看隔离级别语句:8版之前是:select @@tx_isolation;
8版之后:select @@transaction_isolation
mysql> select @@transaction_isolation; +-------------------------+ | @@transaction_isolation | +-------------------------+ | REPEATABLE-READ | -MySQL的默认隔离级别,可重复读 +-------------------------+ 1 row in set (0.01 sec)
- 设置全局的事务隔离级别:
set global transaction isolation level read uncommitted;