作者:手机用户2502929291_707 | 来源:互联网 | 2023-09-25 19:46
初识事务隔离事务隔离级别的出现都是针对数据库的具体问题的,SQL92标准对事务并发处理会存在的异常情况进行了分级,分别为脏读(DirtyRead)、不可重复读(Unrepeatab
初识事务隔离
事务隔离级别的出现都是针对数据库的具体问题的, sql-92标准对事务并发处理会存在的异常情况进行了分级, 分别为脏读(dirty read)、不可重复读(unrepeatable read)和幻读(phantom read).
三种异常
举个例子, 有个heros_temp表, 中有三条数据:
先说脏读, 现在访问数据库, 对数据库进行了一次insert操作, 插入一条"吕布"的记录, 事务未提交, 现在重新开启一个事务, 查询数据库可以将吕布的记录查询出来. 这个就是脏读.
不可重复读呢? 现在先查询数据库记录, 之后重新开启一个事务, 修改一条记录, 现在在前一个事务中再次查询可以查询出修改后的数据, 前后查询出的数据不一致. 这个就是不可重复度.
幻读呢? 现在先查询数据库, 之后开启新事务insert一条记录, 在第一个事务中再次查询会多出插入的记录, 这个就是"幻读".
脏读: 读到事务中还没有提交的数据(可能事务回滚, 这个时候读到的数据无意义)
不可重复读: 对某数据进行读取, 发现两次读取的结果不同, 也就是没有读到相同的内容.(重点在于一条数据的修改, 也就是update 和 delete) 这个因为有其他事务对这个数据同时进行了修改和删除.
幻读: 事务a根据条件查询得到了n条数据, 但此时事务b更改或者增加了m条符合事务a查询条件的数据, 这样当事务a再次进行查询的时候大仙有n + m条数据, 产生了幻读.(重点在于新增多条记录insert)
事务的隔离级别有哪些?
解决异常数量从少到多的顺序决定了隔离级别的高低, 这四种隔离级别从低祷告分别是: 读未提交(read uncommitted)、读已提交(read committed)、可重复读(repeatable read)和可串行化(serializable). 这个隔离级别解决的异常情况如下:
读未提交,也就是允许读到未提交的数据,这种情况下查询是不会使用锁的,可能会产生脏读、不可重复读、幻读等情况。
读已提交就是只能读到已经提交的内容,可以避免脏读的产生,属于 rdbms 中常见的默认隔离级别(比如说 oracle 和 sql server),但如果想要避免不可重复读或者幻读,就需要我们在 sql 查询的时候编写带加锁的 sql 语句。
可重复读,保证一个事务在相同查询条件下两次查询得到的数据结果是一致的,可以避免不可重复读和脏读,但无法避免幻读。mysql 默认的隔离级别就是可重复读。
可串行化,将事务进行串行化,也就是在一个队列中按照顺序执行,可串行化是最高级别的隔离等级,可以解决事务读取中所有可能出现的异常情况,但是它牺牲了系统的并发性。
模拟异常
模拟的数据库表如下:
-- ---------------------------- -- table structure for heros_temp -- ---------------------------- drop table if exists `heros_temp`; create table `heros_temp` ( `id` int(11) not null, `name` varchar(255) character set utf8 collate utf8_general_ci not null, primary key (`id`) using btree ) engine = innodb character set = utf8 collate = utf8_general_ci row_format = dynamic; -- ---------------------------- -- records of heros_temp -- ---------------------------- insert into `heros_temp` values (1, '张飞'); insert into `heros_temp` values (2, '关羽'); insert into `heros_temp` values (3, '刘备');
开启两个客户端, 由于mysql的默认隔离级别是可重复度, 所以需要先将级别设为读未提交:
mysql> show variables like 'transaction_isolation'; // 查询当前隔离级别 mysql> set session transaction isolation level read uncommitted; // 设置隔离级别为读未提交 mysql> set autocommit = 0; // 设置事务不自动提交(由于mysql的事务是自动提交的, 这里需要改一下)
脏读
客户端2中开启事务, 写入新英雄, 不要提交
客户端1中查看
模拟不可重复读
客户端1查询
客户端2修改
客户端1再次查询
模拟幻读
客户端1查询
客户端2新增
客户端1再次查询
隔离级别都是针对对应的异常问题, 并且隔离级别针对每种rdbms都是相同的, 不同的是实现的原理不同.
需要了解更多数据库技术:事务的隔离级别- 极客时间(),都可以关注数据库技术分享栏目—编程笔记