一、事务概述
事务的主要目的是为了保证数据的一致性,无论是单体系统还是分布式系统,使用事务的目的都是如此。从分层架构的角度来看,底层负责数据存储的数据库为上层所有事务的实现提供了支持,上层的任何事务的实现都需要底层数据库事务的支持。从JDBC再到Spring事务的实现都需要依赖于数据库。
而分布式事务由于可能涉及到分布式数据库,所以采取的措施与单体系统中使用的事务有所不同,可以结合数据 库事务也可以采用类似TCC的补偿方案实现事务。
总的来说,如果是单体系统不涉及分布式,那么我们可以通过数据库本身提供的事务结合连接工具比如JDBC等保证业务数据的一致性,如果是分布式系统的话,则在CAP理论或者BASE理论的指导下结合具体的手段实现事务的一致性。
二、事务特性
老生常谈,事务必须满足四个特性,简称ACID,如下所示:
- 原子性 (atomicity):原子性是指一个事务是一个不可分割的工作单位,事务中包括的所有操作要么都执行,要么都不执行。只有使事务中所有的数据库操作执行都成功,才算事务执行成功。
- 一致性(consistency):事务必须使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。一致性也应该是事务的主要目的,原子性与隔离性都应该是为了保证数据的一致性。
- 隔离性 (isolation):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,根据隔离的程度可以被划分为四个不同的等级,就是平时说的隔离级别。
- 持久性(durability):指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。即使接下来出现宕机等情况,也不会对其有任何影响。
一致性是事务的最终目的,原子性与隔离性都是为了保证一致性,而持久性是为了保证数据的安全性,即使发生了意外情况,也能保证数据不会出现丢失,导致数据不完成,从而破坏了一致性等,所以,从这个角度来看,持久性也有利于数据一致性,一致性的前提是有数据才行,数据都没了的话,就没有意义了。
三、数据库事务
只要涉及到了数据库事务,首先应该要确认的就是数据库所使用的的隔离级别,隔离级别是事务特性ACID中隔离性的一个可选的等级,以MYSQL为例的话,分为以下四种:
- 读未提交(Read Uncommited)
- 已提交读(Read Commited)
- 可重复读(Repeatable Read)
- 串行化
最常用的隔离级别应该是读已提交与可重复读,两者处于不加锁与加排它锁的中间状态,相比较于串行化,最大的不同在于读已提交与可重复读隔离级别使用了MVCC机制来保证读写不阻塞,所以,性能会高于串行化,而隔离性强于读未提交.
四、Spring事务
Spring的事务与数据库事务相较而言,由于Spring本身是作为应用层框架,所以,Spring不同于数据库事务之处有两点。
第一点是Spring事务为我们提供的不同风格的调用方式,根据风格可以分为编程式与声明式;
第二点就是由于应用层更多的是方法之间的调用,所以就需要有有对应的策略来处理方法调用时事务应该如何传播,在数据库层面肯定不存在这个问题的,这也相当于是Spring提供的一种增强的工具,在原有事务的基础上结合具体的场景提供了一种灵活设置事务传播策略的增强工具。
编程式与声明式
1.编程式事务
使用Spring提供的工具类Ttempleate实现对事务的控制。
简单的说就是在代码中需要直接加入处理事务的逻辑,我们可以在代码中显示的调用控制事务的处理方法。事务的粒度大小可以得到非常灵活的控制,编程式事务可以直接包括住方法内部的代码块。
优点:需要执行事务的代码块的粒度可控,比较灵活。