如何在微服务下保证事务的一致性

随着业务的快速发展、业务复杂度越来越高,传统单体应用逐渐暴露出了一些问题,例如开发效率低、可维护性差、架构扩展性差、部署不灵活、健壮性差等等。而微服务架构是将单个服务拆分成一系列小服务,且这些小服务都拥有独立的进程,彼此独立,很好地解决了传统单体应用的上述问题,但是在微服务架构下如何保证事务的一致性呢?

1、事务的介绍
1.1 事务
1.1.1 事务的产生
数据库中的数据是共享资源,因此数据库系统通常要支持多个用户的或不同应用程序的访问,并且各个访问进程都是独立执行的,这样就有可能出现并发存取数据的现象,这里有点类似Java开发中的多线程安全问题(解决共享变量安全存取问题),如果不采取一定措施会出现数据异常的情况。列举一个简单的经典案例:比如用户用银行卡的钱还京东白条,银行卡扣款成功了,但是白条因为网络或者系统问题没有还款成功,就会出大问题,这时候我们就需要使用事务。

1.1.2 事务的概念
事务是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作;这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行;事务是一组不可再分割的操作集合(工作逻辑单元)。例如:在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序。

1.1.3 事务的特性
事务的四大特征主要是:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability),这四大特征大家或多或少都听说过,这里我做下简单介绍。

(1)原子性(Atomicity):事务内的操作要么全部成功,要么全部失败,不会在中间的某个环节结束。假如所有的操作都成功了,那么事务是成功的,只要其中任何一个操作失败,那么事务会进行回滚,回滚到操作最初的状态。

begin transaction;

update activity_acount set money = money-100 where name = ‘小明’;

update activity_acount set money = money+100 where name = ‘小红’;

commit transaction;

(2)一致性(Consistency):事务的执行使数据从一个状态转换为另一个状态,但是对于整个数据的完整性保持稳定。换一种说法是数据按照预期生效,数据的状态是预期的状态。比如数据库在一个事务执行之前和执行之后,都必须处于一致性状态,如果事务执行失败,那么需要自动回滚到原始状态,也就是事务一旦提交,其他事务查看到的结果一致,事务一旦回滚,其他事务也只能看到回滚前的状态。

举个通俗一点的例子:小明给小红转账100元,转账前和转账后数据是正确的状态,这叫一致性,如果小红没有收到100元或者收到金额少于100元,这就出现数据错误,就没有达到一致性。

(3)隔离性(Isolation):在并发环境中,不同事务同事修改相同的数据时,一个未完成的事务不会影响另外一个未完成的事务。

例如当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

(4)持久性(Durability):事务一旦提交,其修改的数据将永远保存到数据库中,改变是永久性,即使接下来数据库发生故障也不应对其有任何影响。

通俗一点例子:A卡里有2000块钱,当A从卡里取出500,在不考虑外界因素干扰的情况下,那么A的卡里只能剩1500。不存在取了500块钱后,卡里一会剩1400,一会剩1500,一会剩1600的情况。

1.1.4 Mysql隔离级别
如果不考虑事务隔离性产生问题:脏读、不可重复读和幻读。

Mysql隔离级别分为4种:Read Uncommitted(读取未提交的)、Read Committed(读取提交的)、Repeatable Red(可重复读)、Serializaable(串行化)

(1)Read Uncommitted是隔离级别最低的一种事务级别。在这种隔离级别下,一个事务会读到另一个事务更新后但未提交的数据,如果另一个事务回滚,那么当前事务读到的数据就是脏数据,这就是脏读(Dirty Read)。

(2)在Read Committed隔离级别下,一个事务可能会遇到不可重复读(Non Repeatable Read)的问题。不可重复读是指,在一个事务内,多次读同一数据,在这个事务还没有结束时,如果另一个事务恰好修改了这个数据,那么,在第一个事务中,两次读取的数据就可能不一致。

(3)在Repeatable Read隔离级别下,一个事务可能会遇到幻读(Phantom Read)的问题。幻读是指,在一个事务中,第一次查询某条记录,发现没有,但是,当试图更新这条不存在的记录时,竟然能成功,并且,再次读取同一条记录,它就神奇地出现了,就好象发生了幻觉一样。

(4)Serializable是最严格的隔离级别。在Serializable隔离级别下,所有事务按照次序依次执行,因此,脏读、不可重复读、幻读都不会出现。虽然Serializable隔离级别下的事务具有最高的安全性,但是,由于事务是串行执行,所以效率会大大下降,应用程序的性能会急剧降低。如果没有特别重要的情景,一般都不会使用Serializable隔离级别。

如果没有指定隔离级别,数据库就会使用默认的隔离级别。在MySQL中,如果使用InnoDB,默认的隔离级别是Repeatable Read。

1.1.5 启动事务
在说明启动事务之前,首先大家先想一下事务的传播行为,事务传播行为用于解决两个被事务管理的方法互相调用问题。实际开发中将事务在service控制,如以下方法调用存在传播行为,如果serviceB也会产生一个代理对象,同时也会进行事务管理,执行serviceA和serviceB分别开启事务,上边的serviceA中funA方法内容不处于一个事务中了。

class serviceA{
//此方法进行事务控制
f

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值