分布式事务一致性

1、什么是事务? 
做一件事情分为几个步骤,这几个步骤要么都成功要么都失败! 

2、事务的特性?
  a) 原子性 b) 隔离性 c) 一致性 d) 持久性 

3、不考虑事务的隔离性,会产生哪些读问题?                                                                                       a)不可重复读: 一个事务读取到了另一个事务提交的数据                                                                        b)脏读: 在一个事务处理过程中读取到了另一个事务未提交的数据                                                         c) 虚读:T1事务把一条数据的id从1修改为2,并添加了一条id为1的数据,T2事务去读取自己之前添加的id为1的数据,但实际上读取到的是T1修改后的数据;     

4、SQL的隔离级别有四种                                                                                                                         a)  Serializable(串行化,mysql事务的最高级别);                                                                                  b)  Repeatable read(可重复读,mysql默认隔离级别);                                                                         c)  Read Commit(读取已提交数据,避免脏读;Oracle的默认隔离级别);                                             d) read uncommit(读取未提交数据)             

5、 分布式事务初探                                                                                                                       
 a)需求,用户注册成功后需要给添加 1000 积分!                                                                           b)分析:涉及连个不同库里的两张表,又分属于两个业务系统 
 A 库--用户表:tb_user 
 B 库--积分表:tb_score                                                                                                                      c)  用户系统服务  UserService addUser(User user);     

public class UserService {
    @Autowired
    private UserRepository userRepository;
    public User addUser(User user) {
       return userRepository.sava(user);
    }
}

 d)  积分系统服务  ScoreService  addScore(int userId , int socre) 

public class ScoreService  {
    @Autowired
    private ScoreRepository scoreRepository;
    public int addScore(int userId , int socre)  {
       return scoreRepository.addScore(userId,socre);
    }
}

6、 思考如下伪代码实现的业务对还是不对?为什么? 
 注册系统中: 

 Start Transaction; 
 addUser(User user) ;  anyException  rollback;
 addScore(int userId, int socre);   anyException  rollback;  
 commit; 

 如果对用户,积分表的 SQL 操作全部成功,则全部提交,如果任何一个出现问题,则全部回 滚,以保证数据的一致性。   互联   网的业务特点,数据量较大,并发量较大,经常使用拆库的方式提升系统的性能。如果 进行了拆库,用户表,积分表可能分布   在不同的数据库上,甚至不同的数据库实例上,此时 就不能用事务来保证数据的一致性了。这种情况下如何保证数据的一致   性?

7、方案一:补偿事务 
 补偿事务是一种在业务端实施业务逆向操作事务,来保证业务数据一致性的方式。 
 添加用户的事务: 

public class UserService {
    @Autowired
    private UserRepository userRepository;
    public int addUser(User user) {
       start transaction; 
       //调 dao 添加用户  异常 rollback  return 0;
       commit;  
       return 1; 
    }
}

 添加用户的补偿事务 

public class UserService {
    @Autowired
    private UserRepository userRepository;
    int Compensate_addUser(User user){ 
       //调 dao 删除新添加用户; 
    } 
}

添加积分的事务: 

public class ScoreService  {
    @Autowired
    private ScoreRepository scoreRepository;
    public int addScore(int  userId  ,int Score){ 
       start transaction;  
       //调 dao 给指定用户添加积分  异常 rollback  return 0;  
       commit;  
       return 1; 
    } 
}

 添加积分的补偿事务 

public class ScoreService  {
    @Autowired
    private ScoreRepository scoreRepository;
    int Compensate_addScore(int userId,int score){ 
      //调 dao 删除给定id 的积分 
    } 
}

8、要保证添加用户和增加积分一致性过程 

int  register(User user){ 
  //执行第一个事务 
  Int flag =addUser( user); 
  If(flag=1){  
    //第一个添加用户的事务执行成功,执行第二个事务加积分!  
    flag=addScore(userid, score);  
    if(flag=1){   
      //第二个事务成功,则成功!  
      return 1; 
    }else{  
      //第二个事务执行失败,执行第一个事务的补偿事务  
      compensate_addUser(User user) 
    } 
  } 
} 

该方案的不足是:                                                                                                                             (1)不同的业务要写不同的补偿事务,不具备通用性                                                                          (2)没有考虑补偿事务的失败                                                                                                                       (3)如果业务流程很复杂,if/else 会嵌套非常多层  

9、方案二:两阶段提交 
单库操作是通过一个大事务来保证数据的一致性,如果分库操作的话就会变成多个小事务 ,如上例 

Start Transaction;
addUser(User user) ;  anyException  rollback;   
addScore(int userId, int socre);   anyException  rollback; 
commit; 

 1)一个事务,分成执行与提交两个阶段,执行的时间其实是很长的,而 commit 的执行其实 是很快的,于是整个执行过程的时间轴 :第一个事务执行 200ms, 提交 1ms; 第二个事务执行 300ms, 提交 1ms; 那在什么时候系统出现问题,会出现不一致呢? 回答:第一个事务成功提交之后,最后一个事务成功提交之前,如果出现问题 (例如服务器重启,数据库异常等),都可能导致数据不一致。 
 2)如果改变事务执行与提交的时序,变成事务先执行,最后一起提交,情况会变成什么样呢:第一个事务执行 200ms; 第二个事务执行 300ms; 第一个事务提交 1ms; 第二个事务提交 1ms; 


3)那在什么时候系统出现问题,会出现不一致呢? 问题的答案与之前相同:第一个事务成功提交之后,最后一个事务成功提交之 前,如果出现问题(例如服务器重启,数据库异常等),都可能导致数据不一 致。 

 
10、这个变化的意义是什么呢?                                                                                                           1方案一总执行时间是 502ms,最后 301ms 内出现异常都可能导致不一致; 方案二总执行时间也是 502ms,但最后 1ms 内出现异常才会导致不一致; 虽然没有彻底解决数据的一致性问题,但不一致出现的概率大大降低了!   事务提交后置降低了数据不一致的出现概率。                                                                                                                                                                                                        11、会带来什么副作用呢?                                                                                                                  事务提交时会释放数据库的连接,第一种方案,第一个库事务提交,数 据库连接就释放了,后置事务提交的方案,所有库的连接,要等到所有事务执 行完才释放。这就意味着,数据库连接占用的时间增长了,系统整体的吞吐量 降低了。 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值