程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

事务隔离级别

balukai 2025-03-13 13:10:24 文章精选 60 ℃

数据库的事务有原子性,一致性,隔离性,持久性。

事务的隔离性由隔离级别体现,事务有四种隔离级别。

1,READ UNCOMMITTED(未提交读)

事务可以读取其他事务未提交的修改。

2,READ COMMITTED(已提交读)

事务读取的信息是其他事务已提交的。

3:REPEATABLE READ(可重复读)

与不可重复读相对,事务中不存在读取同一份数据不一样的情况。READ UNCOMMITTED和READ COMMITTED级别下存在不可重复读的情况,当事务还未提交,其他事务修改数据并且提交,此时该事务再查询同一份数据时,数据发生改变。mysql的默认事务隔离级别。

4:SERIALIZABLE(串行化)

事务的读取,修改,添加都是通过加锁保证事务的执行次序。


MariaDB> SELECT @@tx_isolation;

+----------------+

| @@tx_isolation |

+----------------+

| SERIALIZABLE |

+----------------


1:设置隔离级别为READ UNCOMMITTED

打开会话窗口一,设置事务隔离界别为“未提交读”。

MariaDB> set session transaction isolation level READ UNCOMMITTED;

再打开一个窗口二

## 开启事务
begin;

## 查询信息
MariaDB> select account from zz_users limit 1;
+---------+
| account |
+---------+
|         |
+---------+
1 rows in set (0.02 sec)

## 修改信息
MariaDB> update zz_users set account="lantian" where id=1;
Query OK, 1 rows affected (0.02 sec)

此时修改了数据,事务还未提交

回到原来窗口:

## 开启事务
begin;

## 查询另一个会话事务修改的数据
MariaDB> select account from zz_users where id=1;
+---------+
| account |
+---------+
| lantian |
+---------+
1 rows in set (0.02 sec)

此时查询出了其他事务没有提交的修改,此时二号窗口回滚。

## 重新执行查询
MariaDB> select account from zz_users where id=1;
+---------+
| account |
+---------+
|         |
+---------+
1 rows in set (0.01 sec)

会话一读取了未生效的数据,也就是垃圾数据,对于会话一这就是脏读。

2:设置隔离级别为READ COMMITTED

MariaDB> set session transaction isolation level READ COMMITTED;

会话二重复上面的操作,会话一分别在会话二提交前和提交后查询数据:

## 会话二未提交
MariaDB> select account from zz_users where id=1;
+---------+
| account |
+---------+
|         |
+---------+
1 rows in set (0.01 sec)

## 会话二已提交
MariaDB> select account from zz_users where id=1;
+---------+
| account |
+---------+
| lantian |
+---------+
1 rows in set (0.01 sec)

会话一读取的信息是其他事务提交的数据,此时脏读不存在。不可重复读会存在,

删除id为1 的数据,两个会话重新开启事务。

## 会话一查询id为2的数据
MariaDB> select account,id from zz_users where id=2;
+----------+----+
| account  | id |
+----------+----+
| 88888888 | 2  |
+----------+----+
1 rows in set (0.01 sec)
## 会话二插入一条数据
MariaDB> insert into zz_users (uuid, account, id) values ("uuid74298d2a3938ccb2d28067fe5817db77","666666", 1);
Query OK, 1 rows affected (0.01 sec)

MariaDB> select account,id from zz_users where id=1;
+---------+----+
| account | id |
+---------+----+
| 666666  | 1  |
+---------+----+
1 rows in set (0.01 sec)

MariaDB> commit;
Query OK, 0 rows affected (0.02 sec)
## 会话一重新查询数据发生变化
MariaDB> select account,id from zz_users where id=2;
+----------+----+
| account  | id |
+----------+----+
| 77777777 | 2  |
+----------+----+
1 rows in set (0.01 sec)

同一份数据在同一个事务两次读取不一致,就是不可重复读。

3:事务级别设置为REPEATABLE READ:

## 会话一查询数据
MariaDB> select account,id from zz_users where id=2;
+----------+----+
| account  | id |
+----------+----+
| 77777777 | 2  |
+----------+----+
1 rows in set (0.01 sec)
## 会话二更新数据操作
MariaDB> update zz_users set account="88888888" where id=2;
Query OK, 1 rows affected (0.01 sec)

MariaDB> commit;
Query OK, 0 rows affected (0.01 sec)
## 会话一再次查询数据
MariaDB> select account,id from zz_users where id=2;
+----------+----+
| account  | id |
+----------+----+
| 77777777 | 2  |
+----------+----+
1 rows in set (0.01 sec)

## 提交事务
MariaDB> commit;
Query OK, 0 rows affected (0.01 sec)

## 再次查询
MariaDB> select account,id from zz_users where id=2;
+----------+----+
| account  | id |
+----------+----+
| 88888888 | 2  |
+----------+----+
1 rows in set (0.02 sec)

此时事务为结束之前,多次读取数据都是一致的。不可重复读不存在,但是幻读会存在。

两个会话重新开启事务:

## 会话一查询id为1,2的数据。此时只存在id为2 的数据
MariaDB> select account,id from zz_users where id in (1,2);
+----------+----+
| account  | id |
+----------+----+
| 88888888 | 2  |
+----------+----+
1 rows in set (0.02 sec)
## 会话2插入一条数据id为1
MariaDB> insert into zz_users (uuid, account, id) values ("uuid74298d2a3938ccb2d28067fe5817db79","666666", 1);
Query OK, 1 rows affected (0.01 sec)

## 查询
MariaDB> select account,id from zz_users where id in (1,2);
+----------+----+
| account  | id |
+----------+----+
| 666666   | 1  |
| 88888888 | 2  |
+----------+----+
2 rows in set (0.02 sec)

## 提交数据
MariaDB> commit;
Query OK, 0 rows affected (0.01 sec)
### 会话一再次查询id为1,2的数据
MariaDB> select account,id from zz_users where id in (1,2);
+----------+----+
| account  | id |
+----------+----+
| 88888888 | 2  |
+----------+----+
1 rows in set (0.01 sec)

### 没有id为1的数据,但是此时插入数据时
MariaDB> insert into zz_users (uuid, account, id) values ("uuid74298d2a3938ccb2d28067fe5817db79","666666", 1);
Duplicate entry '1' for key 'PRIMARY'

此时没有出现幻读,读取数据还是以前查找的数据,只是插入的时候回报重复id的错误,网上其他资料RR级别是会出现幻读的,但是实验没有,可能MariaDB最新版本解决了RR级别幻读的问题。


4:事务级别设置为REPEATABLE SERIALIZABLE:

重复上面的操作,先在会话一查询:

### 会话一查询数据
MariaDB> select account,id from zz_users where id in (1,2);
+----------+----+
| account  | id |
+----------+----+
| 88888888 | 2  |
+----------+----+
1 rows in set (0.03 sec)
### 此时会话二插入数据,此时会话二进入等待状态,等到会话1提交后才会继续执行。
MariaDB> insert into zz_users (uuid, account, id) 
values ("uuid74298d2a3938ccb2d28067fe5817db79","666666", 1);

总结:事务的隔离性是数据库mvcc和锁的共同作用下实现。SERIALIZABLE级别下开销最大,会对所有查询加共享锁,即使数据不存在。达到命令一条一条执行。

最近发表
标签列表