文章目录
- 前言
- 事务(Transaction)的操作
- 什么是事务?
- 事务的特性
- 事务的隔离级别
- 事务相关的语句
- 演示事务回滚和提交
- 演示事务隔离级别
- read uncommitted(读取未提交)
- read committed(读取已提交)
- repeateable read(可重复读)
- serializable(序列化)
前言
数据库中的事务是指对数据库执行一批操作,这些操作最终要么全部执行成功,要么全部失败!
事务(Transaction)的操作
什么是事务?
一个事务是一个完整的业务逻辑单元,不可再分。
事务是逻辑的一组操作,要么执行,要么不执行。
事务的存在是保证数据的完整性,安全性。
事务的特性
事务特性 | 含义 |
原子性(Atomicity) | 一个事务中的所有操作要么全部完成,要么全部失败。事务执行后,不允许停留在中间某个状态 |
一致性(Consistency) | 不管在任何给定的时间,并发事务有多少,事务必须保证运行结果的一致性 |
隔离性(Isolation) | 要求事务不受其他并发事务的影响,在给定的时间内,该事务是数据库唯一运行的事物 |
持久性(Durability) | 事务一旦提交,结果便是永久性的,即便发生宕机,仍然可以依靠事务日志完成数据的持久化 |
事务的隔离级别
名称 | 隔离级别 | 脏读 | 不可重复读 | 幻读 |
读取未提交 | read uncommitted | 是 | 是 | 是 |
读取已提交 | read committed | 否 | 是 | 是 |
可重复读 | repeatable-read | 否 | 否 | 是 |
串行化 | serializable | 否 | 否 | 否 |
- 脏读: 一个事务读取到了另一个事务中尚未提交的数据
- 不可重复读: 一个事务中两次读取的数据内容不一致,要求的是一个事务中多次读取时数据是一致的,这是事务update时引发的问题
- 幻读: 一个事务中两次读取的数据的数量不一致,要求在一个事务多次读取的数据的数量是一致的,这是insert或delete时引发的问题
事务相关的语句
DML语句,insert、update、delete
MySQL事务默认是自动提交的!只要执行一条DML就提交一次!
MySQL默认的隔离级别是:repeatable-read (可重复读取)
- START TRANSACTION 开启事务(关闭mysql自动提交机制)
- ROLLBACK 事务回滚(返回事务内执行的操作)
- COMMIT 事务提交(提交事务内执行的操作)
演示事务回滚和提交
代码如下(示例):
-- ===========================================事务回滚===========================================
-- 开启事务
START TRANSACTION;
-- 插入数据
insert into user (username,age) values('zhangsan',18);
insert into user (username,age) values('lisi',18);
insert into user (username,age) values('wangwu',18);
-- 查询
SELECT * FROM user;
-- 事务回滚
ROLLBACK;
-- 再次查询
SELECT * FROM user;
-- ===========================================提交事务===========================================
-- 开启事务
START TRANSACTION;
-- 插入数据
insert into user (username,age) values('zhangsan',18);
insert into user (username,age) values('lisi',18);
insert into user (username,age) values('wangwu',18);
-- 查询
SELECT * FROM user;
-- 事务提交
COMMIT;
-- 再次查询
SELECT * FROM user;
-- 事务回滚
ROLLBACK; -- 已经提交了,回滚没有作用
-- 再次查询
SELECT * FROM user;
演示事务隔离级别
设置事务的隔离级别,开启两个客户端A和B,A进行开启事务并执行查询,B进行开启事务并DML数据
read uncommitted(读取未提交)
也叫脏读,一个事务在处理过程中读取了另外一个事务未提交的数据。
你都还没提交,我就读到了你刚操作的数据,万一你回滚了怎么办,你说这脏不脏。
代码如下(示例):
-- 设置事务的全局隔离级别
mysql> 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)
-- 然后重新进入MySQL
mysql> exit;
-- ================客户端A=================
mysql> use test;
Database changed
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from user;
Empty set (0.01 sec)
-- ================客户端B=================
mysql> use test;
Database changed
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into user (username,age) values('zhangsan',18);
Query OK, 1 row affected (0.00 sec)
-- ================客户端A=================
mysql> select * from user;
+----+----------+------+
| id | username | age |
+----+----------+------+
| 1 | zhangsan | 18 |
+----+----------+------+
1 row in set (0.00 sec)
-- ================客户端B=================
mysql> insert into user (username,age) values('lisi',18);
Query OK, 1 row affected (0.00 sec)
-- ================客户端A=================
mysql> select * from user;
+----+----------+------+
| id | username | age |
+----+----------+------+
| 1 | zhangsan | 18 |
| 2 | lisi | 18 |
+----+----------+------+
2 rows in set (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
-- ================客户端A=================
mysql> use test;
Database changed
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from user;
Empty set (0.01 sec)
-- ================客户端B=================
mysql> use test;
Database changed
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into user (username,age) values('zhangsan',18);
Query OK, 1 row affected (0.00 sec)
-- ================客户端A=================
mysql> select * from user;
Empty set (0.00 sec)
-- ================客户端B=================
mysql> insert into user (username,age) values('lisi',18);
Query OK, 1 row affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.02 sec)
-- ================客户端A=================
mysql> select * from user;
+----+----------+------+
| id | username | age |
+----+----------+------+
| 1 | zhangsan | 18 |
| 2 | lisi | 18 |
+----+----------+------+
2 rows in set (0.00 sec)
repeateable read(可重复读)
客户端A事务没有提交前,不管客户端B事务执行什么操作,客户端A事务都是原始数据,如果客户端A、B事务都提交了就能读取到相同的数据行。也就是出现幻读的现象!(就是两个都要提交才能读取到相同的数据行,虽然B提交了但A没有提交也没有用)
代码如下(示例):
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> exit
-- ================客户端A=================
mysql> use test;
Database changed
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from user;
Empty set (0.00 sec)
-- ================客户端B=================
mysql> use test;
Database changed
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into user (username,age) values('zhangsan',18);
Query OK, 1 row affected (0.00 sec)
-- ================客户端A=================
mysql> select * from user;
Empty set (0.00 sec)
-- ================客户端B=================
mysql> insert into user (username,age) values('lisi',18);
Query OK, 1 row affected (0.00 sec)
mysql> select * from user;
+----+----------+------+
| id | username | age |
+----+----------+------+
| 1 | zhangsan | 18 |
| 2 | lisi | 18 |
+----+----------+------+
2 rows in set (0.00 sec)
mysql> delete from user;
Query OK, 2 rows affected (0.00 sec)
mysql> select * from user;
Empty set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.11 sec)
mysql> insert into user (username,age) values('zhangsan',18);
Query OK, 1 row affected (0.11 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from user;
+----+----------+------+
| id | username | age |
+----+----------+------+
| 3 | zhangsan | 18 |
+----+----------+------+
1 row in set (0.00 sec)
-- ================客户端A=================
mysql> select * from user;
Empty set (0.00 sec)
serializable(序列化)
也叫串行化,排队进行事务内的操作!
一个事务A第一次操作完,另一个事务B进行操作就会进行等待,事务A提交后,事务B就会执行操作。
代码如下(示例):
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
-- ================客户端A=================
mysql> use test;
Database changed
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from user;
Empty set (0.00 sec)
-- ================客户端B=================
mysql> use test;
Database changed
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into user (username,age) values('zhangsan',18);
-- 。。。。。进入一个等待的状态,等待客户端A的事务提交后才执行
-- ================客户端A=================
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
-- ================客户端B=================
mysql> insert into user (username,age) values('zhangsan',18);
Query OK, 1 row affected (25.89 sec)
-- ================客户端A=================
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from user;
-- 。。。。。进入一个等待的状态,等待客户端B的事务提交后才执行
-- ================客户端B=================
mysql> commit;
Query OK, 0 rows affected (0.10 sec)
-- ================客户端A=================
mysql> select * from user;
+----+----------+------+
| id | username | age |
+----+----------+------+
| 1 | zhangsan | 18 |
+----+----------+------+
1 row in set (4.83 sec)