简介
本文章是作者朋友去阿里面试时的几道事务相关的面试题,相信大多数猿友们,在找工作的时候,往往避免不了各种各样的面试题,和面试官提出的各种奇葩的问题,也相信大家肯定遇到过很多面试问题,比如:多线程、高并发、高可用、事务、海量数据优化、算法、IO流等等,太多了,在这里给大家分享一下事务相关的问题,希望能够帮助大家面试顺利。
以下面试题是作者简单又高效的记忆解答。
事务的四大特性
分别是原子性、一致性、隔离性、持久性;世面上也称为ACID。如果出去面试人家面试官问ACID是什么,到时候千万别跟没见过世面的样子,相信看到这里,这四个特性应该深深的记到心里了吧。
那好,我们来具体了解一下这四个特性:
1.原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
筱白记忆法:原子性就是所有操作要么执行成功,要么执行失败回滚。
2.一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
举例:假设用户A和用户B两者的钱加起来一共是1000,那么不管A和B之间如何转账、转几次账,事务结束后两个用户的钱相加起来应该还得是1000,这就是事务的一致性。
3.隔离性(lsolation)
隔离性是当多个用户并发访问数据库时,比如同时操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
4.持久性(Durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
例如:我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务已经正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成。否则的话就会造成我们虽然看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。这是不允许的。
事务的四种隔离级别
分别是读未提交(Read uncommitted)、读已提交(Read committed)、可重复读(Repeatable read)、串行读(Serializable)。
1.Read uncommitted(未授权读取、读未提交)
如果一个事务已经开始写数据,则另外一个事务则不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可以通过“排他写锁”实现。这样就避免了更新丢失,却可能出现脏读。也就是说事务B读取到了事务A未提交的数据。
2.Read committed(授权读取、读提交)
读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。该隔离级别避免了脏读,但是却可能出现不可重复读。事务A事先读取了数据,事务B紧接了更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。
3.Repeatable read(可重复读取)
可重复读是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,即使第二个事务对数据进行修改,第一个事务两次读到的的数据是一样的。这样就发生了在一个事务内两次读到的数据是一样的,因此称为是可重复读。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。这样避免了不可重复读取和脏读,但是有时可能出现幻象读。(读取数据的事务)这可以通过“共享读锁”和“排他写锁”实现。
4.Serializable(序列化)
提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。序列化是最高的事务隔离级别,同时代价也花费最高,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻像读。
快速记忆示例图: (建议这样记忆)
隔离级别 | 脏读 | 不可重复读 | 幻读 | 默认隔离级别 |
Read uncommitted(读未提交) | 允许 | 允许 | 允许 | |
Read committed(读已提交) | 不允许 | 允许 | 允许 | Oracle默认隔离级别 |
Repeatable read(可重复读) | 不允许 | 不允许 | 允许 | Mysql默认隔离级别 |
Serializable(串行读) | 不允许 | 不允许 | 不允许 |
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免脏读取,而且具有较好的并发性能。
大多数数据库的默认级别就是Read committed,比如Sql Server , Oracle。MySQL的默认隔离级别就是Repeatable read。
什么是脏读,不可重复读,幻读?
脏读:简单来说,就是一个事务读取到了另一个事务未提交的数据。
不可重复读:就是说,比如在A事务中进行多次相同的查询,B事务在A事务多次查询之间修改对应表中的数据,导致A事务多次读取的结果不一致。
幻读:举例来说,就是A事务将表中'性别'列的值都更改为1,B事务在A事务修改之后又添加了一条记录,而'性别'的值为0,回过来A再查询所以的记录时会发现有一条记录的'性别'为0,这种情况就是所谓的幻读
什么是事务的传播行为?
事务传播行为用来描述由某一个事务传播行为修饰的方法被嵌套进另一个方法的时事务如何传播。
事务的七种传播行为
1.PROPAGATION_REQUIRED(propagation_required)
PROPAGATION_REQUIRED 表示当前方法必须在一个具有事务的 上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。( 如果被调用端发生异常,那么调用端和被调用端事务都将回滚)
2.PROPAGATION_SUPPORTS (propagation_supports)
PROPAGATION_SUPPORTS 表示当前方法不必需要具有一个事务 上下文,但是如果有一个事务的话,它也可以在这个事务中运行。
3.PROPAGATION_MANDATORY(propagation_mandatory)
PROPAGATION_MANDATORY 表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常。
4.PROPAGATION_REQUIRES_NEW(propagation_requires_new)
PROPAGATION_REQUIRES_NEW 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
5.PROPAGATION_NOT_SUPPORTED
PROPAGATION_NOT_SUPPORTED 总是非事务地执行,并挂起任何存在的事务。
6.PROPAGATION_NEVER
PROPAGATION_NEVER 总是非事务地执行,如果存在一个活动事务,则抛出异常。
7.PROPAGATION_NESTED
PROPAGATION_NESTED表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中 ,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。如果封装事务不存在,则同propagation. required的一样。
以上希望能够帮助到大家,以后会继续分享更多的面试题和文章。大家多多支持。
作者:筱白爱学习!!
欢迎关注转发评论点赞沟通,您的支持是筱白的动力!