事务
- 概念:一系列不可分割的操作(sql),要么全都执行,要么全都不执行
一、ACID
-
ACID:原子性、一致性、隔离性、持久性
- Atomic原子性:
- 事务必须是同一个原子的操作序列单元,事务中包含的各项操作在一次执行的过程中,要么同时成功,要么完全不执行,任何一项失败,整个事务回滚,只有全部都执行成功,整个事务才算成功
- Consistency一致性:
- 事务的执行不能破坏数据库数据的完整性和一致性,事务在执行之前和之后,数据库都必须处于一致性状态。
- Isolation隔离性:
- 在并发环境中,并发的事务是相互隔离的,一个事务的执行不能被其他事务干扰。
- 即不同的事务并发操纵相同的数据时,每个事务都有各自完整的数据空间,即一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能相互干扰。
- Durability持久性:
- 持久性也称永久性,指一个事务一旦提交,它对数据库中对应数据的状态的变更就应该是永久性的、
- 即使发生系统崩溃或机器宕机,只要数据库能够重新启动,那么一定能够将其恢复到事务成功结束时的状态
- Atomic原子性:
二、SQL的4个隔离级别:
隔离级别 | 脏读(DirtyRead) | 不可重复读(NonRepeatableRead) | 幻读(PhantomRead) |
---|---|---|---|
读未提交(Read uncommitted) | 可能 | 可能 | 可能 |
读以提交(Read committed) | 不可能 | 可能 | 可能 |
可重复读(Repeatable read) | 不可能 | 不可能 | 可能 |
可串行读(Serializable) | 不可能 | 不可能 | 不可能 |
- 读未提交:
- 如果一个事务正在处理每一事务,并对其进行了更新,但同时尚未完成事务,或者说事务没有提交,与此同时允许另外一个事务也能够访问该数据
- 例如:A将变量n从0累加到10才提交事务,此时B可能读到n变量从0到10之间的所有中间值。
- 允许脏读。在读未提交隔离级别下,允许脏读的情况发生。
- 脏读指的是读到了其他事务未提交的数据,
- 未提交意味着这些数据可能会回滚,也就是可能最终不会存到数据库中,也就是不存在的数据
- **脏读:**读到了并不一定最终存在的数据,这就是脏读
- 读以提交:
- 只允许读到已经提交的数据。
- 即事务A在将n从0累加到10的过程中,B无法看到n的中间值,之中只能看到10
- 在 读已提交隔离级别下,禁止了 脏读,但是 允许不可重复读的情况发生
- 事务 A 多次读取同一数据,但事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
- **不可重复读:**指的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据出现不一致的情况。
- 可重复读:
- 保证在事务处理过程中,多次读取同一个数据时,其值都和事务开始时刻时是一致的。
- 在可重复读隔离级别下,禁止了:脏读、不可重复读。但是,允许幻读。
- 在可重复读中,该sql第一次读取到数据后,就将这些数据加锁(悲观锁),其它事务无法修改这些数据,就可以实现可重复读了。
- **幻读:**但这种方法却无法锁住insert的数据,所以当事务A先前读取了数据,或者修改了全部数据,事务B还是可以insert数据提交,这时事务A就会发现莫名其妙多了一条之前没有的数据,这就是幻读,不能通过行锁来避免。
- 幻读一般使用MVCC(多版本并发控制)解决
- 可串行读:
- 最严格的事务,要求所有事务被串行执行,不能并发执行。
- 读的时候加共享锁,也就是其他事务可以并发读,但是不能写。写的时候加排它锁,其他事务不能并发写也不能并发读。
幻读和不可重复读的区别:
幻读:在同一事务中,相同条件下,两次查询出来的记录数 不一样;
不可重复读:在同一事务中,相同条件下,两次查询出来的数据 不一样;
三、事务隔离级别设置
查看事务隔离级别:在MySQL8中该参数为 transaction_isolation,在MySQL5中该参数为 tx_isolation
MySQL5:
-- 查看系统隔离级别:
SELECT @@global.transaction_isolation;
-- 查看当前会话隔离级别
SELECT @@transaction_isolation;
-- 设置当前会话事务隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- 设置全局事务隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
最终一致性
四、事务开启命令
#开启事务
begin/START TRANSACTION
#提交事务
commit;
#回滚事务
rollback
在innoDB中上一下表锁
#对一张表上读锁/写锁格式
lock table 表名 read/write;
#例子
lock table tb_book read;
#查看当前会话对所有表的上锁情况
show open tables;
#释放当前会话的所有锁
unlock tables;
在innoDB中上行锁:
MySAM无法上行锁!
- 只要线程1不进行提交该行操作的事务,其他线程就无法对这行的数据进行操作
#方式1:通过修改进行上行锁,
update tb set name = 'zhangsan' where id = 3;
#方式2:通过查询加 for update;
select * from tb where id = 5 for update;
五、分布式事务
分布式事务的理论基础:CAP定理
- 一致性(Consistency) : 客户端知道一系列的操作都会同时发生(生效)
- 可用性(Availability) : 每个操作都必须以可预期的响应结束
- 分区容错性(Partition tolerance) : 即使出现单个组件无法可用,操作依然可以完成
- 一致性:
- 分布式环境中,一致性是指多个副本之间能否保持一致的特性。在一致性的需求下,当一个系统在数据一致的状态下执行更新操作后,应该保证系统的数据仍然处理一致的状态。
- 例如对于电商系统用户下单操作,库存减少、用户资金账户扣减、积分增加等操作必须在用户下单操作完成后必须是一致的。不能出现类似于库存已经减少,而用户资金账户尚未扣减,积分也未增加的情况。如果出现了这种情况,那么就认为是不一致的。
- 数据一致性分为强一致性、最终一致性、弱一致性
- 如果的确能够像上面表述的那样时刻保证客户端看到的数据都是一致的,那么称之为强一致性
- 如果允许存在中间状态,只要求经过一段时间后,数据最终是一致的,则称之为最终一致性
- 此外,如果允许存在部分数据不一致,那么称之为弱一致性
- 可用性:
- 系统提供的服务必须一直处于可用的状态,对于用户的每个操作请求总是能够在有限的时间内返回结果
- 两个量级的维度:
- 有限时间内
- 对于用户的一个操作请求,系统必须能够在指定的时间(响应时间)内返回对应的处理结果,如果超过了这个时间范围,那么系统就被认为是不可用的。即这个响应时间必须在一个合理的值内,不让用户感到失望。
- 试想,如果一个下单操作,为了保证分布式事务的一致性,需要10分钟才能处理完,那么用户显然是无法忍受的,所以出现这种情况一般会采用降级熔断处理
- 返回正常结果:
- 要求系统在完成对用户请求的处理后,返回一个正常的响应结果。正常的响应结果通常能够明确地反映出对请求的处理结果,即成功或失败,而不是一个让用户感到困惑的返回结果。比如返回一个系统错误如OutOfMemory,则认为系统是不可用的。
- “返回结果”是可用性的另一个非常重要的指标,它要求系统在完成对用户请求的处理后,返回一个正常的响应结果,不论这个结果是成功还是失败、
- 有限时间内
- 分区容错性:
- 即分布式系统在遇到任何网络分区故障时,仍然需要能够保证对外提供满足一致性和可用性的服务,除非是整个网络环境都发生了故障。
- 网络分区,是指分布式系统中,不同的节点分布在不同的子网络(机房/异地网络)中,由于一些特殊的原因导致这些子网络之间出现网络不连通的状态,但各个子网络的内部网络是正常的,从而导致整个系统的网络环境被切分成了若干孤立的区域。组成一个分布式系统的每个节点的加入与退出都可以看做是一个特殊的网络分区。
CAP 理论告诉我们:
任何一个分布式系统都无法同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition
tolerance),最多只能同时满足两项。在互联网领域的绝大多数的场景中,都需要牺牲强一致性来换取系统的高可用性,系统往往只需要保证最终一致性。
- 为什么分布式系统中无法同时保证一致性和可用性?
- 首先一个前提,对于分布式系统而言,分区容错性是一个最基本的要求,因此基本上我们在设计分布式系统的时候只能从一致性(C)和可用性(A)之间进行取舍。
- 如果保证了一致性(C):对于节点N1和N2,当往N1里写数据时,N2上的操作必须被暂停,只有当N1同步数据到N2时才能对N2进行读写请求,在N2被暂停操作期间客户端提交的请求会收到失败或超时。显然,这与可用性是相悖的。
- 如果保证了可用性(A):那就不能暂停N2的读写操作,但同时N1在写数据的话,这就违背了一致性的要求。
BASE定理
概念:CAP是分布式系统设计理论,BASE是CAP理论中AP方案的延伸,对于C我们采用的方式和策略就是保证最终一致性;
构成:BASE是Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语的缩写。BASE基于CAP定理演化而来,核心思想是即时无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
-
Basically Available(基本可用)
- 基本可用是指分布式系统在出现不可预知的故障时候,允许损失部分可用性,但不等于系统不可以
- 响应时间上的损失
- 当出现故障时,响应时间增加
- 功能上的损失
- 当流量高峰时。屏蔽一些功能的使用以保证系统稳定性(服务降级)
-
Soft stata(软状态)
- 指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性
- 与硬状态相对,即是指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。
-
Eventually consistent(最终一致性)
- 强调系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。其本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
六、spring 事务失效
-
抛出检查异常导致事务不能正确回滚
- 原因:spring默认只会回滚非检查异常
- 解法:配置rollbackFor属性,直接设置为
Exception.class
@Transactional(rollbackFor = Exception.class)
-
业务方法内自己try-catch异常,导致事务不能正确回滚
- 原因:事务通知只能捉到目标抛出的异常,才能进行后续的回滚处理,如果目标自己处理掉异常,事务通知无法看到
- 解决:异常原样抛出
- 在 catch 块添加
throw new RuntimeException(e);
- 在 catch 块添加
-
非pubilc方法导致的事务失效
- 原因:spring为方法创建代理,添加事务通知,前提条件都是该方法是public的
- 解决:改为public