1、关于事务
一个事务(transaction
)是一个完整的业务逻辑单元 ,不可再分。往往多条DML
(数据操纵语言,包括insert,delete,update
)语句组成一个事务,且这些DML
语句必须同时执行成功或失败,这样才能保证数据的完整性和安全性。
当开启事务机制时,DML
语句执行成功之后并不会直接在存储区上修改数据,而是先把执行记录, 即未提交的数据放到缓存中,等到提交事务(commit
)之后才会真正修改数据。如果回滚事务(rollback
)则会清空缓存区,相当于撤销一系列DML
语句, 提交和回滚都会结束事务机制。
2、事务的特性
事务包括四大特性:ACID
。
Atomicity
(原子性):一个事务中的DML
语句必须同时执行成功或失败,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚到事务开始前的状态。即事务不可分割、不可约简;Consistency
(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏;Isolation
(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致;Durability
(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
3、事务的隔离级别
事务隔离分为不同级别,包括:
- 未提交读(
read uncommitted
): 对方事务未提交时, 我方当前事务可以读取到对方未提交的数据。但是一旦对方回滚事务, 我们读取到数据是无效的, 称为脏读
(dirty read)现象。 - 提交读(
read committed
): 我方当前事务可以读取对方事务提交之后的数据, 但是如果对方事务修改多次,我们同样的语句获取的数据却不一样, 这样一来不能重复读取, 避免出现数据不一致的情况。 - 可重复读(
repeatable read
): 在我方开启事务之后, 无论对方怎么提交事务, 我方读取到的都是事务开启时对应的数据, 这样虽然解决了不可重复读的问题, 但是读取到的数据缺少了时效性。 - 串行化(
Serializable
): 类似于线程同步, 事务不能并发进行。当一个事务正在操作一张表时, 操作同一张表的另外一个事务执行DML
语句后会陷入等待状态。保证了数据的安全性, 但是需要事务排队, 效率低。
MySQL8.0
可通过select @@global.transaction_isolation;
查看当前事务隔离级别。
+--------------------------------+
| @@global.transaction_isolation |
+--------------------------------+
| REPEATABLE-READ |
+--------------------------------+
修改事务隔离级别的方法如下:set global/session transaction isolation level 级别
, 全局级对所有会话有效, 会话级只对当前会话有效。表示级别的字段为:
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE
4、事务演示
MySQL默认自动提交模式, 单条DML
语句将缺省地开始一个新的事务, 如果执行成功, 事务自动提交, 通过服务器变量autocommit
来控制, 如set autocommit=on/off
。
//建表student:id、name
create table student(
id int primary key auto_increment,
name varchar(255)
);
//开启事务机制
start transaction;
insert into student (name) values('Alice');
//执行结果暂时存储到缓存区
mysql> select * from student;
+----+-------+
| id | name |
+----+-------+
| 1 | Alice |
+----+-------+
insert into student (name) values('Bob');
mysql> select * from student;
+----+-------+
| id | name |
+----+-------+
| 1 | Alice |
| 2 | Bob |
+----+-------+
//回滚,提交用commit;
rollback;
//清空缓存区,结果为空
mysql> select * from student;
Empty set (0.00 sec)
//MySQL默认自动提交
insert into student (name) values('Alice');
rollback;
//虽然回滚,但是数据依然存储成功
mysql> select * from student;
+----+-------+
| id | name |
+----+-------+
| 3 | Alice |
+----+-------+
//自增值不会回滚,会一致递增
如果在事务中设置保存点: savepoint 名称
, 那么回滚的时候可以选择rollback to 保存点名称
, 将保存点之后的缓存区清空, 但这样并没有真正结束事务, 若再次rollback
, 保存点之前的缓存区仍会被清空。
欢迎评论区交流~👍