4种事务隔离级别 和 7种事务传播行为 详细整理版

不考虑事务隔离产生的三大问题

 

1.脏读:

 

 

定义:一个事务处理过程里读取了另一个未提交的事务中的数据

 

事例:老板要给程序员发工资,程序员的工资是3.6万/月。但是发工资时老板不小心按错了数字,按成3.9万/月,该钱已经打到程序员的户口,但是事务还没有提交,就在这时,程序员去查看自己这个月的工资,发现比往常多了3千元,以为涨工资了非常高兴。但是老板及时发现了不对,马上回滚差点就提交了的事务,将数字改成3.6万再提交。

 

分析:实际程序员这个月的工资还是3.6万,但是程序员看到的是3.9万。他看到的是老板还没提交事务时的数据。

 

2.不可重复读:

 

定义:对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值(这是由于在查询间隔,被另一个事务修改(update)并提交了)


事例:程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他埋单时(程序员事务开启),收费系统事先检测到他的卡里有3.6万,就在这个时候!!程序员的妻子要把钱全部转出充当家用,并提交。当收费系统准备扣款时,再检测卡里的金额,发现已经没钱了(第二次检测金额当然要等待妻子转出金额事务提交完)。程序员就会很郁闷,明明卡里是有钱的…

 

分析:这就是读提交,若有事务对数据进行更新(UPDATE)操作时,读操作事务要等待这个更新操作事务提交后才能读取数据,可以解决脏读问题。但在这个事例中,出现了一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。

 

3.幻读:

 

定义:对于数据库中的某批数据,一个事务范围内多次查询却返回了不同的数据值(这是由于在查询间隔,被另一个事务插入(insert)并提交了)

 

事例:程序员某一天去消费,花了2千元,然后他的妻子去查看他今天的消费记录(全表扫描FTS,妻子事务开启),看到确实是花了2千元,就在这个时候,程序员花了1万买了一部电脑,即新增INSERT了一条消费记录,并提交。当妻子打印程序员的消费记录清单时(妻子事务提交),发现花了1.2万元,似乎出现了幻觉,这就是幻读。

 

 

注意:脏读是应该避免的(看到的是假数据),而不可重复读和幻读有时候则不是问题(看到的是会变化的真数据)

 

 

4种事务隔离级别

 

1.Read uncommitted 读未提交:

 

    一个事务可以读取另一个未提交事务的数据(安全性低,不推荐)
    造成问题:脏读、不可重复读、幻读

 

2.Read committed 读已提交:

 

    一个事务要等另一个事务提交后才能读取数据
    解决问题:脏读
    造成问题:不可重复读 、幻读

 

3.Repeatable read  可重复读:

 

    在开始读取数据(事务开启)时,不再允许修改操作
    解决问题:脏读,不可重复读
    造成问题:幻读

 

4.Serializable 可序列化:

 

    事务串行化顺序执行(效率低,不推荐)
    解决问题:脏读、不可重复读、幻读

 

注意点:

 

安全性越高,性能消耗越大
Oracle只支持 读已提交 和 可序列化,默认隔离级别为 读已提交
Mysql默认隔离级别为可重复读

 

7种事务传播行为

 

1.PROPAGATION_REQUIRED(propagation_required,事务必需,最常用的设置 )

 

定义:当前方法必须在一个事务中运行

 

做法:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务。

 

注意:如果被调用端发生异常,那么调用端和被调用端事务都将回滚

 

例子:

 ServiceB.methodB的事务级别定义为PROPAGATION_REQUIRED, 那么因为执行ServiceA.methodA的时候,ServiceA.methodA已经起了事务。这时调用ServiceB.methodB,ServiceB.methodB看到自己已经执行在ServiceA.methodA的事务内部。就不再起新的事务。而假如ServiceA.methodA执行的时候发现自己没有在事务中,他就会为自己分配一个事务。这样,在ServiceA.methodA或者在ServiceB.methodB内的不论什么地方出现异常。事务都会被回滚。即使ServiceB.methodB的事务已经被提交,可是ServiceA.methodA在接下来fail要回滚,ServiceB.methodB也要回滚

 

2.PROPAGATION_SUPPORTS(propagation_supports,事务支持)

 

定义:当前方法不必但支持在一个事务中运行


做法:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。

 

3.PROPAGATION_MANDATORY(propagation_mandatory,事务强制)

 

定义:当前方法必须在一个事务中运行,如果没有事务,将抛出异常

 

4.PROPAGATION_REQUIRES_NEW(propagation_requires_new,事务必需新建)

 

定义:当前方法必须运行在它自己的事务中

 

做法:一个新的事务将启动,而且如果有一个现有的事务在运行的话,则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行。一个新的事务将启动,而且如果有一个现有的事务在运行的话,则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行。

 

例子:

 比方我们设计ServiceA.methodA的事务级别为PROPAGATION_REQUIRED,ServiceB.methodB的事务级别为PROPAGATION_REQUIRES_NEW。那么当运行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起。ServiceB.methodB会起一个新的事务。等待ServiceB.methodB的事务完毕以后,他才继续运行。

 他与PROPAGATION_REQUIRED 的事务差别在于事务的回滚程度了。由于ServiceB.methodB是新起一个事务,那么就是存在两个不同的事务。假设ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚。ServiceB.methodB是不会回滚的。假设ServiceB.methodB失败回滚,假设他抛出的异常被ServiceA.methodA捕获,ServiceA.methodA事务仍然可能提交。

 

5.PROPAGATION_NOT_SUPPORTED(propagation_not_supported,事务不支持)


定义:该方法不支持在一个事务中运行

 

做法:如果有一个事务正在运行,他将在运行期被挂起,直到当前方法以非事务的状态执行完才恢复执行

 

例子:

 ServiceA.methodA的事务级别是PROPAGATION_REQUIRED 。而ServiceB.methodB的事务级别是PROPAGATION_NOT_SUPPORTED ,那么当执行到ServiceB.methodB时。ServiceA.methodA的事务挂起。而他以非事务的状态执行完,再继续ServiceA.methodA的事务。

 

6.PROPAGATION_NEVER(propagation_never,事务拒绝)

 

定义:当前方法不应该在一个事务中运行,如果存在一个事务,则抛出异常

 

7.PROPAGATION_NESTED(propagation_nested,事务嵌套)


定义:当前方法必须运行在它自己的嵌套事务中


做法:外层有事务,则新建嵌套事务运行其中,外层无事务,则如同PROPAGATION_REQUIRED

 

注意:如果外层事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。

 

注意点:

 

在外层事务存在的情况下,PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW和PROPAGATION_NESTED三者区别

 

PROPAGATION_REQUIRED:

 

加入已存在事务,即可视为,内层事务与外层事务同步,外影响内,内影响外

本质:一个事务

 

PROPAGATION_REQUIRES_NEW:

 

强制新建事务,即可视为,内层事务与外层事务独立,外不影响内,内不影响外

本质:两个事务,提交点独立

 

PROPAGATION_NESTED:

 

嵌套事务,即可视为,内层事务依赖于外层事务,外影响内,内不影响外

本质:两个事务,提交点统一

 

另外还需注意自调用(自己的类调用其他方法的过程)而使传播行为无效的问题

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值