一篇文章看懂事务的一致性

一、前言

    事务一直以来是一个玄之又玄的东西,非常难以理解。难以理解倒不是因为事务本身有多难,而是事务这个概念被各种刻意包装,以至于让人晕头转向,摸不着头脑。例如各种抽象的概念,一致性、持久性、原子性、持久性、读未提交、读已提交、可重复读、序列化,Spring也抽象了事务的传播属性,数据库本身又有各种锁,于是我们就晕头了。今天我们就来扒一扒事务,看看事务华丽外衣下的本质。本篇博客结合沈询的分享,加上自己的一些总结。

二、事务要解的最终问题——“一致性”

    一致性是一个名词,其实这里实际上应该当成一个动词来理解,多个参与者达成一致,达成了共识,相互之间不扯皮。这样说可能比较抽象,举个生活中的例子。

     一天,老王和老王老婆,同时去银行取钱,老王查了银行卡账号有1w块钱,于是取了出来,假设老王老婆和老王同时查询,也看到有1w块钱,于是点击取款,最后发现没钱可取了,于是要扯皮了,这就不一致了。

    用一句通俗的话来描述事务的一致性:所有事务的参与方,眼所见,便是心所得。上面的例子中,老王老婆看到了卡上有1w,却没法取,于是就要扯皮了。这就是严苛的一致性所定义的内容。

    下面我们来具体分析一下上面的例子。

    首先引出事务单位的概念,事务单元就是完成一个具体的业务的最小单元,上面的例子中包含两个事务单元。按照正常的时间线,要想不扯皮,应该看到如下执行顺序。

    1ad40d20844abadab1bfcb557fe42950f3a.jpg

        但是扯皮的事情发生了,两个事务单元并行了,于是出现如下的执行顺序。事务单元二左移,与事务单元一并行。

    9838a1d53c7b5d5bb85754f0b31c1143a28.jpg

    上面的场景似曾相识,其实就是和线程安全所描述的内容一摸一样,《一篇文章看懂Java并发和线程安全》,要想不扯皮,必须让访问的共享资源互斥,用Java代码可以描述成如下的代码:

public class Consistency {

	public static void main(String[] args) {
		ReentrantLock lock = new ReentrantLock();
		lock.lock();
		try {
			int balance = query();// 查询余额
			if (balance > 0) {
				drawingOutCash();// 取出现金
			}
		} catch (Exception e) {

		} finally {
			lock.unlock();
		}
	}
}

   要想强一致,所有的事务单元串行着执行,这就是事务隔离级别中的SERIALIZABLE,于是就引出了事务的隔离级别。

三、事务的隔离级别

    强一致,必须让所有事物单元串行执行,这便是隔离级别中的SERIALIZABLE(序列化),但是这样系统的性能是可想而知的,几乎不可用,于是需要放宽对锁的要求,所以出现了其他的隔离级别。事务的隔离级别是以性能为由对一致性的破坏,它的出现是为了破坏一致性,而不是维持一致性。

    事务单元与事务单元的关系只有四种:读读、读写、写读、写写

    SERIALIZABLE(序列化)

    33b1bb0dc8837f856064c9d1637481fb473.jpg

    要想进一步提升性能,于是出现了读写锁,这里就出现了两种隔离级别:REPEATABLE_READ(可重复读)和READ_COMMITED(读已提交)

    REPEATABLE_READ(可重复读):

    读锁不能被升级为写锁,那么对共享资源的写,就进不来,这样“读读”是可并行的,这样会出现幻读,因为在这个级别,表是不会被看做是共享资源的,所以可以insert

    bb07b6c7fb259b9fa74ba37917fc021d113.jpg

    READ_COMMITED(读已提交):

    读锁可以被升级为写锁,那么当对共享资源正在读时,可以被写请求升级为写锁,那么这样“读读”、“读写”可以并行,于是出现了幻读、不可重复读等等现象

    021bac60288f9476861ef183ead2342e0d9.jpg

    READ_UNCOMMITTED

    只加写锁,读不用申请锁,这样“读读”、“读写”、“写读”都可以并行,但“写写”还不能并行,于是所有的写都是串行,于是就有了脏读、不可重复读、幻读等等。

    9a0beefeda5e4d66471bff0cf8d0c5afc06.jpg

    这就是事务隔离级别的真相,事务隔离级别越低,并行度越好,一致性越低。

四、一句话总结

    事务的一致性和线程安全所面对的问题一模一样,要想维持一致性,需要保证两点:共享变量的可见性、临界区代码访问的顺序性。

 

快乐源于分享。

   此博客乃作者原创, 转载请注明出处

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值