GVKun编程网logo

【面试题精讲】MySQL-事务隔离-幻读(mysql的事务隔离级别面试题)

1

最近很多小伙伴都在问【面试题精讲】MySQL-事务隔离-幻读和mysql的事务隔离级别面试题这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展03|事务隔离:为什么你改了我还看不见?

最近很多小伙伴都在问【面试题精讲】MySQL-事务隔离-幻读mysql的事务隔离级别面试题这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展03 | 事务隔离:为什么你改了我还看不见?、03.MySQL 实战 45 讲学习笔记 --- 事务隔离、2021最新BAT资深Java 面经合集:CMS+红黑树+线程状态+事务隔离+中间件、3 事务隔离:为什么你改了我还看不见?等相关知识,下面开始了哦!

本文目录一览:

【面试题精讲】MySQL-事务隔离-幻读(mysql的事务隔离级别面试题)

【面试题精讲】MySQL-事务隔离-幻读(mysql的事务隔离级别面试题)

有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准https://blog.zysicyj.top

首发博客地址

全网最细面试题手册,支持艾宾浩斯记忆法


1. 什么是幻读?

幻读是指在事务并发执行过程中,某个事务在读取某个范围的数据时,另一个事务在该范围内新增或删除了数据,导致前一个事务再次读取时,出现了前后两次读取结果不一致的情况。

2. 为什么会出现幻读?

幻读的出现主要是因为事务隔离级别造成的。

在读已提交(Read Committed)和可重复读(Repeatable Read)隔离级别下,事务在读取数据时会加锁,防止其他事务对其进行修改或删除。但是对于新增数据来说,并不受到加锁的限制,因此,当某个事务在读取数据时,另一个事务新增了符合该范围的数据,就会导致前一个事务再次读取时,出现了新增数据的“幻象”。

3. 幻读的实现原理?

幻读的实现主要依赖于数据库的行级锁。

在读已提交隔离级别下,数据库对被读取的数据行进行行级锁定,防止其他事务对其进行修改或删除。但是对于新增数据来说,并不受到行级锁的限制,因此,当某个事务在读取数据时,另一个事务新增了符合该范围的数据行,就会导致前一个事务再次读取时,出现了新增数据行的“幻象”。

4. 幻读的使用示例

假设有一个订单表,多个事务同时向该表插入数据,并且一个事务要求查询订单表中某个时间范围内的数据。

示例代码如下:

// 查询某个时间范围内的订单
@Transactional(isolation = Isolation.READ_COMMITTED)
public List<Order> getOrdersByTimeRange(Date startTime, Date endTime) {
    // 执行查询语句
    List<Order> orders = orderMapper.getOrdersByTimeRange(startTime, endTime);
    return orders;
}

在上述代码中,假设有两个事务同时执行 getOrdersByTimeRange 方法,一个事务查询了范围为 2021-01-01 到 2021-01-31 的订单,而另一个事务在该范围内新增了一条订单数据。当第一个事务再次查询时,就会发现出现了新增的订单数据,导致了幻读现象。

5. 幻读的优点

幻读虽然在一定程度上提高了数据的一致性,但在某些场景下也可能带来一些优势,比如:

  • 提供了更准确的数据。通过幻读,事务能够获取最新的数据情况,避免了因为读取的是旧数据而导致的错误判断。

6. 幻读的缺点

幻读也存在一些缺点,包括:

  • 降低了并发性能。由于幻读需要进行额外的锁操作,会降低系统的并发性能。
  • 增加了数据不确定性。由于幻读可能出现在事务的读取过程中,会导致前后两次读取结果不一致,增加了数据的不确定性和操作的风险。

7. 幻读的使用注意事项

在开发中,为了避免幻读问题,可以采取以下措施:

  • 尽量使用更高的事务隔离级别,比如可串行化(Serializable)隔离级别。
  • 使用行级锁或间隙锁来解决幻读问题。
  • 合理设计事务边界,减少事务的隔离范围。

8. 总结

幻读是指在事务并发执行过程中,某个事务在读取某个范围的数据时,另一个事务在该范围内新增或删除了数据,导致前一个事务再次读取时,出现了前后两次读取结果不一致的情况。幻读的出现主要是因为事务隔离级别造成的,依赖于数据库的行级锁来实现。幻读虽然在某些场景下提供了更准确的数据,但也降低了并发性能并增加了数据不确定性。为避免幻读问题,可以采取使用更高的事务隔离级别、行级锁或间隙锁以及合理设计事务边界等措施。

本文由mdnice多平台发布

03 | 事务隔离:为什么你改了我还看不见?

03 | 事务隔离:为什么你改了我还看不见?

提到事务,你肯定不陌生,和数据库打交道的时候,我们总是会用到事务。最经典的例子就是转账,你要给朋友小王转100块钱,而此时你的银行卡只有100块钱。

转账过程具体到程序里会有一系列的操作,比如查询余额、做加减法、更新余额等,这些操作必须保证是一体的,不然等程序查完之后,还没做减法之前,你这100块钱,完全可以借着这个时间差再查一次,然后再给另外一个朋友转账,如果银行这么整,不就乱了么?这时就要用到“事务”这个概念了。

简单来说,事务就是要保证一组数据库操作,要么全部成功,要么全部失败。在MySQL中,事务支持是在引擎层实现的。你现在知道,MySQL是一个支持多引擎的系统,但并不是所有的引擎都支持事务。比如MySQL原生的MyISAM引擎就不支持事务,这也是MyISAM被InnoDB取代的重要原因之一。

今天的文章里,我将会以InnoDB为例,剖析MySQL在事务支持方面的特定实现,并基于原理给出相应的实践建议,希望这些案例能加深你对MySQL事务原理的理解。

隔离性与隔离级别

提到事务,你肯定会想到ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性),今天我们就来说说其中I,也就是“隔离性”。

当数据库上有多个事务同时执行的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)的问题,为了解决这些问题,就有了“隔离级别”的概念。

在谈隔离级别之前,你首先要知道,你隔离得越严实,效率就会越低。因此很多时候,我们都要在二者之间寻找一个平衡点。SQL标准的事务隔离级别包括:读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(serializable )。下面我逐一为你解释:

  • 读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。
  • 读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。
  • 可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
  • 串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

其中“读提交”和“可重复读”比较难理解,所以我用一个例子说明这几种隔离级别。假设数据表T中只有一列,其中一行的值为1,下面是按照时间顺序执行两个事务的行为。

mysql> create table T(c int) engine=InnoDB;
insert into T(c) values(1);


我们来看看在不同的隔离级别下,事务A会有哪些不同的返回结果,也就是图里面V1、V2、V3的返回值分别是什么。

  • 若隔离级别是“读未提交”, 则V1的值就是2。这时候事务B虽然还没有提交,但是结果已经被A看到了。因此,V2、V3也都是2。
  • 若隔离级别是“读提交”,则V1是1,V2的值是2。事务B的更新在提交后才能被A看到。所以, V3的值也是2。
  • 若隔离级别是“可重复读”,则V1、V2是1,V3是2。之所以V2还是1,遵循的就是这个要求:事务在执行期间看到的数据前后必须是一致的。
  • 若隔离级别是“串行化”,则在事务B执行“将1改成2”的时候,会被锁住。直到事务A提交后,事务B才可以继续执行。所以从A的角度看, V1、V2值是1,V3的值是2。

在实现上,数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准。在“可重复读”隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。在“读提交”隔离级别下,这个视图是在每个SQL语句开始执行的时候创建的。这里需要注意的是,“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念;而“串行化”隔离级别下直接用加锁的方式来避免并行访问。

我们可以看到在不同的隔离级别下,数据库行为是有所不同的。Oracle数据库的默认隔离级别其实就是“读提交”,因此对于一些从Oracle迁移到MySQL的应用,为保证数据库隔离级别的一致,你一定要记得将MySQL的隔离级别设置为“读提交”。

配置的方式是,将启动参数transaction-isolation的值设置成READ-COMMITTED。你可以用show variables来查看当前的值。

mysql> show variables like ''transaction_isolation'';

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

| Variable_name | Value |

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

| transaction_isolation | READ-COMMITTED |

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

总结来说,存在即合理,哪个隔离级别都有它自己的使用场景,你要根据自己的业务情况来定。我想你可能会问那什么时候需要“可重复读”的场景呢?我们来看一个数据校对逻辑的案例。

假设你在管理一个个人银行账户表。一个表存了每个月月底的余额,一个表存了账单明细。这时候你要做数据校对,也就是判断上个月的余额和当前余额的差额,是否与本月的账单明细一致。你一定希望在校对过程中,即使有用户发生了一笔新的交易,也不影响你的校对结果。

这时候使用“可重复读”隔离级别就很方便。事务启动时的视图可以认为是静态的,不受其他事务更新的影响。

事务隔离的实现

理解了事务的隔离级别,我们再来看看事务隔离具体是怎么实现的。这里我们展开说明“可重复读”。

在MySQL中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。

假设一个值从1被按顺序改成了2、3、4,在回滚日志里面就会有类似下面的记录。


当前值是4,但是在查询这条记录的时候,不同时刻启动的事务会有不同的read-view。如图中看到的,在视图A、B、C里面,这一个记录的值分别是1、2、4,同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)。对于read-view A,要得到1,就必须将当前值依次执行图中所有的回滚操作得到。

同时你会发现,即使现在有另外一个事务正在将4改成5,这个事务跟read-view A、B、C对应的事务是不会冲突的。

你一定会问,回滚日志总不能一直保留吧,什么时候删除呢?答案是,在不需要的时候才删除。也就是说,系统会判断,当没有事务再需要用到这些回滚日志时,回滚日志会被删除。

什么时候才不需要了呢?就是当系统里没有比这个回滚日志更早的read-view的时候。

基于上面的说明,我们来讨论一下为什么建议你尽量不要使用长事务。

长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。

在MySQL 5.5及以前的版本,回滚日志是跟数据字典一起放在ibdata文件里的,即使长事务最终提交,回滚段被清理,文件也不会变小。我见过数据只有20GB,而回滚段有200GB的库。最终只好为了清理回滚段,重建整个库。

除了对回滚段的影响,长事务还占用锁资源,也可能拖垮整个库,这个我们会在后面讲锁的时候展开。

事务的启动方式

如前面所述,长事务有这些潜在风险,我当然是建议你尽量避免。其实很多时候业务开发同学并不是有意使用长事务,通常是由于误用所致。MySQL的事务启动方式有以下几种:

  1. 显式启动事务语句, begin 或 start transaction。配套的提交语句是commit,回滚语句是rollback。

  2. set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个select语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行commit 或 rollback 语句,或者断开连接。

有些客户端连接框架会默认连接成功后先执行一个set autocommit=0的命令。这就导致接下来的查询都在事务中,如果是长连接,就导致了意外的长事务。

因此,我会建议你总是使用set autocommit=1, 通过显式语句的方式来启动事务。

但是有的开发同学会纠结“多一次交互”的问题。对于一个需要频繁使用事务的业务,第二种方式每个事务在开始时都不需要主动执行一次 “begin”,减少了语句的交互次数。如果你也有这个顾虑,我建议你使用commit work and chain语法。

在autocommit为1的情况下,用begin显式启动的事务,如果执行commit则提交事务。如果执行 commit work and chain,则是提交事务并自动启动下一个事务,这样也省去了再次执行begin语句的开销。同时带来的好处是从程序开发的角度明确地知道每个语句是否处于事务中。

你可以在information_schema库的innodb_trx这个表中查询长事务,比如下面这个语句,用于查找持续时间超过60s的事务。

select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60

小结

这篇文章里面,我介绍了MySQL的事务隔离级别的现象和实现,根据实现原理分析了长事务存在的风险,以及如何用正确的方式避免长事务。希望我举的例子能够帮助你理解事务,并更好地使用MySQL的事务特性。

我给你留一个问题吧。你现在知道了系统里面应该避免长事务,如果你是业务开发负责人同时也是数据库负责人,你会有什么方案来避免出现或者处理这种情况呢?

你可以把你的思考和观点写在留言区里,我会在下一篇文章的末尾和你讨论这个问题。感谢你的收听,也欢迎你把这篇文章分享给更多的朋友一起阅读。

上期问题时间

在上期文章的最后,我给你留下的问题是一天一备跟一周一备的对比。

好处是“最长恢复时间”更短。

在一天一备的模式里,最坏情况下需要应用一天的binlog。比如,你每天0点做一次全量备份,而要恢复出一个到昨天晚上23点的备份。

一周一备最坏情况就要应用一周的binlog了。

系统的对应指标就是 @尼古拉斯·赵四 @慕塔 提到的RTO(恢复目标时间)。

当然这个是有成本的,因为更频繁全量备份需要消耗更多存储空间,所以这个RTO是成本换来的,就需要你根据业务重要新来评估了。

03.MySQL 实战 45 讲学习笔记 --- 事务隔离

03.MySQL 实战 45 讲学习笔记 --- 事务隔离

   简单来说,事务就是要保证一级数据库操作,要么全部成功,要么全部失败。在 MySQL 中,事务支持是在引擎层实现的,但 MySQL 中并不是所有引擎都支持事务,比如 Mysql 原生的 MyISAM 引擎就不支持事务。

  下面,我们将心 InnoDb 为例,剖析 MySQL 在事务支持方面的特定实现。

隔离性与隔离级别

   提到事务,你一定会想到 ACID(Atomicity、Consistency、Isolation、Durability), 即原子性、一致性、隔离性、持久性,下面我们就来说说其中的 I,也就是隔离性。

  当数据库上有多个事务同时执行的时候,就会可能会出现脏读、不可重复读、幻读的问题,为了解决这些问题,就有了 “隔离级别” 的概念。

  在谈隔离级别之前,你首先要知道,你隔离得越严实,效率就会越低。因此很多时间,我们要在二者之间找一个平衡点。SQL 标准的事务隔离级别有:读未提交、读已提交、可重复读和串行化。

  • 读未提交:一个事务还没有提交时,它做的变更能被别的事务看到。
  • 读已提交:一个事务提交之后,它做的变更才能被其它事务看到。
  • 可重复读:一个事务执行过程中看到的数据,总是和这个事务启动时看到的事务一致。

串行化:对同一行记录,“写” 会加 “写锁”,“读” 会加 “读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

其中 “读提交” 和 “可重复读” 比较难理解,所以我用一个例子说明这几种隔离级别。假设数据表 T 中只有一列,其中一行的值是 1,下面按时间顺序执行两个事务的行为。

mysql>create table T(c int) engine=InnoDb;
mysql>insert into T(c) values(1);

先做好相关准备工作,如下:

#查看一下mysql版本
mysql> select version();
+------------+
| version()  |
+------------+
| 5.7.11-log |
+------------+
1 rows in set (0.03 sec)

#查看一下MySQL的当前的事务隔离级别
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 rows in set (0.04 sec)

#关闭MySQL的自动提交功能
mysql> set autocommit=0;
Query OK, 0 rows affected (0.04 sec)

#查看是否关闭成功
mysql> show variables like ''autocommit'';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | OFF   |
+---------------+-------+
1 rows in set (0.04 sec)


我们来看一下不同的事务隔离级别下,事务 A 会有哪些不同的返回结果,也就是说图中的 V1、V2、V3 的返回值分别是多少。

  • 若事务隔离级别是 “读示提交”,则 V1=2,V2=2,V3=2;
  • 若事务隔离级别是 “读已提交”,则 V1=1,V2=2,V3=2;
  • 若事务隔离级别是 “可重复读”,则 V1=1,V2=1,V3=2;
  • 若事务隔离级别是 “串行化”,则在事务 B 执行 “将 1 改成 2” 的时候,会被锁住,直到事务 A 提交之后事务 B 才能继续执行。所以从 A 的角度来看,V1=1,V2=1,V3=2;

在实现上,数据库里会创建一个视图,访问的时候以视图的逻辑结果为准。在 “可重复读” 隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。在 “读已提交” 隔离级别下,这个视图是在 SQL 语句开始执行的时候创建的,在 “读未提交” 隔离级别下,直接返回记录上的最新值,没有视图的概念。而 “串行化” 直接用加锁的方式来避免并行访问。

我们可以看到,在不同的事务隔离级别下,数据库的行为是有所不同的,Oracle 数据库的默认隔离级别其实就是 “读提交”,因此对于一些从 Oracle 迁移到 MySQL 的应用,为了保证数据库隔离级别一致,一定要记得把 Mysql 的隔离级别设置成 “读提交”。

事务隔离的实现

在 MySQL 中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,可以得到前一个状态值。

假设一个值从 1 被顺序改成了 2、3、4,在回滚日志里面就会有类似下面的记录。

当前值是 4,但是在查询这条记录的时候,不同时刻启动的事务会有不同的 read-view。如上图,在视图 A、B、C 里面,这个记录的值分别是 1、2、4,同一条记录在系统中存在多个版本,这就是数据库的多版本并发控制(MVCC)。对于 read-view A 要得到 1,就必须将当前值依次执行图中所有的回滚段得到。同时你会发现,即使现在有另外一个事务正在将 4 改成 5,这个事务对 read-view A、B、C 对应的事务是不会有冲突的。

回滚段会在不需要的时候删除,也就是说,系统会判断,当没有事务再需要用到这些回滚日志时,回滚日志会被删除。

基于上面的说明,我们来说一下为什么建议你尽量不要使用长事务。长事务意味着系统里会存在很老的事务视图,所以在这个事务提交之前,数据库里面它可能用到的回滚记录都会被保留,这就会导致大量占用存储空间。除了回滚段的影响,长事务还占用锁资源,可能拖垮整个库。

事务的启动方式

MySQL 中启动事务有以下几种:

  • 显示启动事务语句,begin 或 start transaction。配套的提交语句是 commit, 回滚语句是 rollback。

set autocommit=0, 这个命令会将这个线程的自动提交关掉,意味着如果你执行一个 select 语句,这个事务就启动了 (没错执行 select 语句也会开启一个事务),而且并不会自动提交,这个事务持续存在直到你主动执行 commit 或 rollback 语句,或者断开连接。

因此,建议你总是使用 set autocommit=1, 通过显示语句的方式来启动一个事务。

  • 你可以在 information_schema 库的 innodb_trx 这个表中查询长事务,比如下面这个语句,查询持续时间通过 60s 的事务
mysql> SELECT * FROM information_schema.INNODB_TRX where TIME_TO_SEC(timediff(now(),trx_started))>60;

 

那么我们如何避免长事务呢?

从应用开发端来看:

  • 确认是否使用了 set autocommit=0, 这个确认工作可以在测试环境中展开,把 Mysql 的 general_log 开起来。通过 general_log 的日志来确定,我们的目标是要把 autocommit 的值设置成 1。
  • 确认是否有不必要的只读事务,有些业务把好几个 select 语句放到了事务中,这些只读事务可以去掉。
  • 业务连接数据库的时候,根据业务本身的预估,通过 SET MAX_EXECUTION_TIME 命令,来控制每个语句执行的最长时间,避免单个语句意外执行的最长时间。

从数据库端来看:

  • 监控 information_schema.Innodb_trx 表,设置长事务阀值,超过就报警或者 kill;
  • Percona 的 pt-kill 这个工具不错,推荐使用。
  • 在业务功能测试阶段要求输出所有的 general_log, 分析日志行为提前发现问题。

 

2021最新BAT资深Java 面经合集:CMS+红黑树+线程状态+事务隔离+中间件

2021最新BAT资深Java 面经合集:CMS+红黑树+线程状态+事务隔离+中间件


马上进入求职招聘高峰,总结了一份BAT(阿里、百度、字节跳动、美团等)资深Java相关的面试题合集给到大家。

文末有相关的2021最新BAT资深java面试题答案~用于参考

JVM

  • JVM内存模型结构
  • 方法区和直接内存什么时候会oom?
  • JVM收集器G1的内存模型和CMS的内存模型有什么不同?
  • jvm调优用过吗?
  • 如何查看java内存使用情况(jconsole、命令jmap、jstack等等)

    集合

  • Arraylist、linkedlist差异,应用场景;
  • HashMap在JDK1.8有哪些改动?
  • HashCurrentMap和HashMap的区别在哪里?
  • Hashmap什么时候使用红黑树?

    多线程

  • 线程的几种状态,请画出具体的状态流转图?
  • Java wait、sleep的区别?
  • volatile如何实现指令重排序?
  • 线程池中的阻塞队列如果满了怎么办(拒绝策略)?
  • Synchronized和AQS异同,AQS公平非公平如何实现;
  • 多线程里面对一个整型做加减为啥不能用volatile;
  • voliatile和synchonized有什么区别?synchonized和jdk提供的Lock包又有什么区别?

    算法

  • 二叉树宽度遍历
  • 红黑树
  • 数据结构的话,链表,树,图的基本知识得懂
  • 了解树的先序遍历,中序遍历,后序遍历。图的广度优先搜索算法,深度优先搜索算法。

    Spring

  • Bean的生命周期;
  • 什么是DI、为什么DI、DI的类型(构造器注入、方法注入);
  • Spring boot和spring的差别,tomcat如何嵌入spring boot的/spring boot中的tomcat是如何启动的;
  • Spring如何解决循环依赖问题;

    数据库

  • Join(inner、left、right)的区别?
  • Union和union all区别?
  • ACID,具体是啥意思?
  • 事务隔离级别?
  • 幻读和不可重复读的区别?
  • Mysql和mongodb有啥区别?

    计算机网路

  • RPC和http的区别
  • 详细描述TCP四次挥手过程
  • 中间件
  • 秒杀项目会使用到哪些中间件?
  • 为什么Redis是单线程?
  • 如何保证Redis和数据库双写一致?
  • 如何设计一个消息队列中间件?
  • 分库分表后,id主键如何处理?
  • 如何设计一个类似Dubbo的RPC?

Redis

  • Redis五种基本数据类型的使用场景
  • 缓存穿透、缓存击穿、缓存雪崩
  • Redis的过期策略和内存淘汰机制
  • Redis的zset底层数据结构,为什么用跳跃表而不用红黑树

设计模式

  • 代理模式(应用:一是创建多线程的方式之使用Runnable接口应用了静态代理;二是Spring AOP应用了动态代理)
  • 适配器模式(应用:一是创建多线程的方式之使用Callable接口;二是SpringMVC中的HandleAdapter)
  • 工厂模式(应用:一是Spring IOC;二是Mybatis中的SqlSessionFactory就用到了简单工厂模式)
  • 单例模式(一般会需要手撕单例模式的代码,主要谈DCL模式关于指令重排的问题,以及反射可以破坏除枚举以外的几种方式;单例模式的应用有:一是Spring Bean的作用域默认就是使用单例模式;二是Mybatis中的ErrorContext类也使用了单例模式,这个类用于记录线程执行环境的错误信息)
  • 装饰器模式(应用:JAVA的IO流就用到了装饰器模式)
  • 装饰器模式和代理模式的区别?
  • 策略模式(应用:Arrays类的sort方法就用到了策略模式,Comparator接口就是一个策略接口,将排序方法定义成一个策略,用户可以自定义排序策略,可以是升序也可以是降序)
  • 观察者模式与发布订阅模式的区别?(JDK源码已经为我们提供好了一套观察者模式,Observer就是观察者接口,Observable类是被观察者,是一个具体类,提供了一个存放所有观察者角色的集合,并且也提供了添加观察者、移除观察者、通知观察者等方法)

还有很多面试题我在这里就不一一展示了,需要上述BAT资深Java面试题答案可【点击此处】获取!以下还有一些Java学习笔记以及BAT高频面试题可供参考~

3 事务隔离:为什么你改了我还看不见?

3 事务隔离:为什么你改了我还看不见?

3 事务隔离:为什么你改了我还看不见?

在数据库中,事务是要保证一组数据库操作,要么全部成功,要么全部失败,在mysql中,事务在引擎层实现,innodb支持事务

隔离性与隔离级别

事务,ACID(atomicityconsistencyisolationdurability),分析i,隔离性

当数据库上有多个事务同时执行的时候,就可能出现脏读,不可重复读,幻读的问题,为了解决这些问题,有了”隔离级别”的概念

SQL标准的事务隔离级别包括:读未提交read uncommitted)、读已提交read committed)、可重复读repeatable read)和串行化serializable

--读未提交,一个事务还没提交,它做的变更就能被别的事务看到

--读已提交,一个事务提交后,它的变更才会被其他事务看到

--可重复读,一个事务在过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的,当然在可重复读隔离级别下,未提交变更对其他事务通用不可见

--串行化,对同一行记录,写会加写锁,读为加读锁,当出现读写锁冲突的时候,后方为的事务必须等前一个事务执行完成,才能继续执行。

mysql> create table T(c int) engine=InnoDB;

insert into T(c) values(1);

事务A

事务B

启动事务,查询得到值1

启动事务

 

查询得到值1

 

1改成2

查询得到值V1

 

 

提交事务B

查询得到是V2

 

提交事务A,查询得到值V3

 

分别在其事务隔离级别下,V1V2V3的值

--读未提交,则v1=2,虽然事务b没提交,但结果已经被a看到,v2v3=2

--读提交v1=1v2=2v3=2

--可重复读v=1v2=1v3=2

--串行化v1=1v2=1v3=2

在实现上,数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准,在可重复读隔离级别,这个事务是在事务启动时创建的,整个事务存在期间都在用这个事务。

读已提交隔离级别,这个事务是在每个SQL语句开始执行的时候创建的。在读未提交级别下直接返回记录上的最新值,没有试图这个概念。串行化隔离级别直接用加锁的方式来避免并行访问。

mysql> show variables like ''transaction_isolation'';

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

| Variable_name | Value |

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

| transaction_isolation | READ-COMMITTED |

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

总结来说,存在即合理,那个隔离级别都有它自己的应用场景,要根据自己的业务情况来定

事务隔离的实现

mysql中,实际上每条记录在更新的时候都会同时记录一条回滚操作,记录上的最新值,通过回滚操作,都可以得到前一个状态的值。

 

当前值是4,但是在查询这条记录的时候,不同时刻启动的事务会有不同的read-view,图中,在视图A\B\C里面,这一个记录的值分别是124,同一条记录在系统中可以存在多个版本,

就是数据库的多版本并发控制(MVCC),对于read-view a,要得到1,就必须将当前值依次执行图中所有的回滚操作得到。

  回滚日志在不需要的时候删除,系统判断,当没有实物再需要用到这些回滚日志时,回滚日志会被删除。

建议不要采用长事务。

mysql5.5及以前的版本,回滚日志是根据数据字典一起放在ibdata文件里,即使长事务最终提交,回滚段被清理,文件也不会变小,如果回滚段特别大,最终只好为了清理回滚段,重建整个库。

事务的启动方式

--1 显示启动事务语句,begin/start transaction,,commitrollback

--2 set autocommit=0,这个命令会将这个线程的自动提交关掉,如果只执行一个select语句,这个事务就启动了,而且并不会自动提交,直到commit/rollback或者断开连接。

建议总是使用set autocommit=1,通过显示语句的方式来启动事务。

查询持续时间超过60s的事务

(system@127.0.0.1:3306) [test]> select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60-> ;

Empty set (0.00 sec)

关于【面试题精讲】MySQL-事务隔离-幻读mysql的事务隔离级别面试题的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于03 | 事务隔离:为什么你改了我还看不见?、03.MySQL 实战 45 讲学习笔记 --- 事务隔离、2021最新BAT资深Java 面经合集:CMS+红黑树+线程状态+事务隔离+中间件、3 事务隔离:为什么你改了我还看不见?的相关信息,请在本站寻找。

本文标签: