总结几个问题啦

第一个问题

一个用户下了单,然后用户无奈的发现自己支付成功的订单变成已失效了。
其中代码的流程是:
支付回调时序图

支付系统将支付结果 回调传给SOA服务,SOA服务去更改用户订单状态为 已支付。这一过程要失败了,定时任务就会将这个订单状态置为 已失效,然后用户就懵逼了,明明支付成功了,却变成无效订单了。要是我,肯定急眼了。

导致的问题:

支付系统在回调失败时是会基于一定策略继续尝试的。
1. 第一次回调在第6步时没有查到数据,程序抛出一个空指针异常终止了程序;
2. 在进行第二次回调时,查到了流水数据,但在第7步没有查到订单数据,程序没有抛出异常或告知支付系统回调失败,没有更改订单状态。但更新了流水表,订单表没有更新,导致两个表的订单状态不一致了。

原因:

数据库是主从集群配置的,SELECT的SQL会发往从库,INSERT、UPDATE、DELETE的SQL发往了主库,后面从DBA了解到主从是有一些时间delay的。这就能解释为什么查不到数据了。

改进措施:

  1. 对于这种涉及到金钱的,并且数据一致性要求高的,可以直接去查询主库,避免出现这种意外的情况;
  2. 在没有查到数据的时候,程序及时抛出异常并报警,或告知支付系统回调失败,方便排查问题;
  3. 将更新流水表和更新订单表放在一个事务里,保证两个表 订单的状态是一致的。

哈哈,缅怀下那个定律:

Anything that can go wrong will go wrong!

第二个问题

来段伪代码(在工作中就写了这样一段代码):

  @Transactional(rollbackFor = Exception.class)
  public void invokeRemote() {
      insert();   // 数据库插入操作 加锁
      update();   // 更新操作 加锁
      insert();   // 插入操作 加锁
      executePost(URL, data);  // 发送https的请求
  }

一旦这个事务方法被调用,insert和update都会加锁,然后发送https的POST请求,不靠谱的https接口超时了,让这个事务一直不能commit, 如果这个事务方法被并发调用就惨了,多个事务一直挂着等待锁然后就超时报错了。还会影响到其他的业务,由于锁一直未释放,其他业务请求获取不到锁出现超时或死锁。

改进1

  @Transactional(rollbackFor = Exception.class)
  public void invokeRemote() {
      executePost(URL, data);  // 发送https的请求
      insert();   // 数据库插入操作 加锁
      update();   // 更新操作 加锁
      insert();   // 插入操作 加锁
  }

将https的请求提前,因为时间耗费都在这一步,这样数据库层面就不会先去加锁,避免后续事务的等待。

改进2

public void invokeRemote() {
      executePost(URL, data);  // 发送https的请求
      oneService.operateDb()
}

@Transactional(rollbackFor = Exception.class)
public void operateDb() {
      insert();   // 数据库插入操作 加锁
      update();   // 更新操作 加锁
      insert();   // 插入操作 加锁
}

这种方式的改进比较好一些,事务方法中不要出现网络调用、比较耗时的处理程序,事务中数据库的连接是不会释放的,如果每个事务的处理时间都非常长,那宝贵的数据库连接资源将消耗殆尽。

第三个问题

 <sql id="where">
     <where>
         <if test="id != null">
             id = #{id}
         </if>
     </where>
 </sql>

 <select id="selectOrderById" resultType="me.jiaocchong.Order">
     select * from tb_order <include refid="where" />
 </select>

这是mybatis的mapper里写的一段sql, 如果代码里面传的id为null会发生什么?意外就是tb_order表里数据全查出来堆在了内存里(tb_order表上千万的数据),这时看见的错误就是OutOfMemoryError了。很可怕,直接导致线上机器宕机。
所以写代码一定要细心。

参考链接:
http://tech.meituan.com/innodb-lock.html
https://my.oschina.net/hcliu/blog/397281
http://tech.lede.com/2017/02/06/rd/server/SpringTransactional/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值