因此,本文面向初学者,特对乐观事务与悲观事务作以尽量形象易理解的解释。
首先,需要强调的是,必须清楚:无论是乐观事务,还是悲观事务,其事务的执行结果都是一样的,即一个事务中的 *** 作,对ACID级别的要求,完全一样,无论是原子性、一致性、隔离性或者持久性,都是完全一致,不存在乐观事务就宽松一些,悲观事务就严格一些的情况。
在此基础上,再来理解两种事务类型,其实:最为直接有效准确的方法,就是纯字面理解。所谓乐观事务,就是指执行者在执行前对事务的估计“乐观”一些时选用它,悲观事务就是执行者在执行前对事务的估计“悲观”一些时选用它。怎么解释呢?当编程者用分布式数据库来处理事务需求时,需要对所面对业务的状态有一个判断:就是并发事务的写冲突是否频繁?如果判断不频繁,就是“乐观”,应该用乐观事务方法;如果判断频繁,就是“悲观”,应该用悲观事务方法。而无论选择“乐观”还是“悲观”,都只是根据实际面对的问题选择一个尽量效率高的两阶段提交执行策略,而不是对事务结果的妥协。
这里举一个形象的例子。比如我们国家进行核酸检测,有报道说在很短时间内就检测了几千万次,其效率之高很惊人!这其实就是用到了类似乐观事务的执行策略:我们事先判断感染的人数比例是很少的,因此就采用批量检测的方案,就是把很多待检测样本混成一个批次,一个批次做一次检测,只有当检测到有感染的批次,才对那个批次进行单个的分拆检测。由于感染的人数非常小,因此大部分批次的检测都是合格的,不合格的批次只是少数,因此比全样本单个检测效率高很多。但可以想见,如果实际的情况是感染人数比例很高(悲观),那么,这种基本乐观判断的批次检测策略就明显会比单个检测更慢。在这个例子中,如果对感染人数是乐观判断,就采用“乐观”的处理方案:批量检测;如果对感染人数是悲观判断,就采用“悲观”的处理方案:单个检测。但无论什么检测方法,都不能对检测的准确度做出任务妥协:一个都不能放过!当然,这个例子并不是说乐观事务就是用批处理方法来处理事务,而是对基于乐观判断的策略选择做以形象的解释。
这就是乐观事务与悲观事务的区别,它只是两阶段提交基于待处理业务状态的不同执行策略,其选择基于执行者的判断,其效率高低基于被处理业务的实际状态(并发事务的写冲突频繁度),而其结果则是完全一样的。就顺着你老师给的例子汇款的流程
步骤A 你的账户划出一笔钱
步骤B 你的账户正常划账的判断
步骤C 对方账户进账一笔钱
步骤D 对方账户进账验证
步骤E 上述 *** 作写入日志(银行记录)
完整 流程是A->E 其中一个缓解发生错误 那么数据库事务就把 *** 作记录回滚到步骤A之前的状态 这个过程就是事务
就跟你安装一个程序一样 到其中的一步 发生错误 安装程序会执行一个 installing rolling back process 把你的系统还原到没有安装这个程序的状态TCC是分布式事务实现的一种方式
TRYING 阶段主要是对业务系统做检测及资源预留
CONFIRMING 阶段主要是对业务系统做确认提交,TRYING阶段执行成功并开始执行CONFIRMING阶段时,默认CONFIRMING阶段是不会出错的。即:只要TRYING成功,CONFIRMING一定成功。
CANCELING 阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。
而幂等性则是指业务方法调用一次与调用多次的执行返回结果是一样的。
举个支付项目的例子:
支付系统接收到会员的支付请求后,需要扣减会员账户余额、增加会员积分(暂时假设需要同步实现)增加商户账户余额
再假设:会员系统、商户系统、积分系统是独立的三个子系统,无法通过传统的事务方式进行处理。
TRYING阶段:我们需要做的就是会员资金账户的资金预留,即:冻结会员账户的金额(订单金额)
CONFIRMING阶段:我们需要做的就是会员积分账户增加积分余额,商户账户增加账户余额
CANCELING阶段:该阶段需要执行的就是解冻释放我们扣减的会员余额
以上所有的 *** 作需要满足幂等性,幂等性的实现方式可以是:
1、通过唯一键值做处理,即每次调用的时候传入唯一键值,通过唯一键值判断业务是否被 *** 作,如果已被 *** 作,则不再重复 *** 作
2、通过状态机处理,给业务数据设置状态,通过业务状态判断是否需要重复执行1、会话可以创建多个事务
比如:使用客端连接数据库,这样你就可以执行很多个事务了
2、一个事务只能由一个会话产生
在数据库里的事务,如果在执行的SQL都是由会话发起的,哪怕是自动执行的JOB也是由系统会话发起的
3、一个事务可能会产生一个或多个线程
比如RMAN备份,是可以创建多个线程可加快备份速度
4、一个线程在同一时间内只能执行一个事务
而一个线程,在没结束当前事务是无法释放资源来执行第二个事务
事务、会话与线程的关系和区别
我一直没弄明白数据库中的这三个概念之间的关系。
事务:简单理解局势一个业务需求的最小处理单位。
如:从Ayhk转账500元到Byhk,事务就包括两部分,1、从A卡减掉500元 2、从B卡加上500元
这两个部分只要一个部分出错,就要整体“回滚”,那这就是一个事务
会话:可以包含N个事务
如:你登陆网银之后,可以重复转账步骤2次,第二次转账失败,并不影响你第一次转账成功。
线程:一个事情,一个人干和多个人干的问题
如:比如植树,任务是植树500棵,一个人(线程)干5天,那五个人(线程)干1天。
至于会话和线程的关系,个人理解,植树任务就是一个session
一个会话中可以由多个事务。
线程是 *** 作系统概念。定义:数据库一致性(database
consistency)是指事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。
数据库状态如何变化?每一次数据变更就会导致数据库的状态迁移。如果数据库的初始状态是c0,第一次事务t1的提交就会导致系统生成一个system
change
number(scn),这是数据库状态从c0转变成c1。执行第二个事务t2的时候数据库状态从t1变成t2,以此类推,执行第tn次事务的时候数据库状态由c(n-1)变成cn。
定义一致性主要有2个方面,一致读和一致写。
一致写:事务执行的数据变更只能基于上一个一致的状态,且只能体现在一个状态中。t(n)的变更结果只能基于c(n-1),c(n-2),
c(1)状态,且只能体现在c(n)状态中。也就是说,一个状态只能有一个事务变更数据,不允许有2个或者2个以上事务在一个状态中变更数据。至于具体一致写基于哪个状态,需要判断t(n)事务是否和t(n-1),t(n-2),t(1)有依赖关系。
一致读:事务读取数据只能从一个状态中读取,不能从2个或者2个以上状态读取。也就是t(n)只能从c(n-1),c(n-2)
c(1)中的一个状态读取数据,不能一部分数据读取自c(n-1),而另一部分数据读取自c(n-2)。
摆事实
一致写:
定义100个事务t(1)t(100)实现相同的逻辑
update
table
set
i=i+1,i的初始值是0,那么并发执行这100个事务之后i的值是多少?可能很容易想到是100。那么怎么从一致性角度去理解呢?
数据库随机调度到t(50)执行,此时数据库状态是c(0),而其它事务都和t(50)有依赖关系,根据写一致性原理,其它事务必须等到t(50)执行完毕后数据库状态变为c(1)才可以执行。因此数据库利用锁机制阻塞其它事务的执行。直到t(50)执行完毕,数据库状态从c(0)迁移到c(1)。数据库唤醒其它事务后随机调度到t(89)执行,以此类推直到所有事务调度执行完毕,数据库状态最终变为c(100)。
一致读:
还是上面的例子,假设t(1)t(100)顺序执行,在不同的时机执行select
i
from
table,我们看到i的值是什么?
1
t(1)的执行过程中。数据库状态尚未迁移,读到的i=0
2
t(1)执行完毕,t(2)的执行过程中,数据库状态迁移至c(1),读到的i=1
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)