大发时时彩官网_网络大发时时彩平台_网络大发时时彩网站 - 大发时时彩官网,网络大发时时彩平台,网络大发时时彩网站是知名的中文新闻门户网站,大发时时彩官网,网络大发时时彩平台,网络大发时时彩网站也是全球互联网中文新闻资讯最重要的原创内容供应商之一。依托中新社遍布全球的采编网络,每天24小时面向广大网民和网络媒体。

记一次线上问题 → 事务去哪了

  • 时间:
  • 浏览:2

开心一刻

  小羊:哎呀,前面有奶喝

  狗妈:这谁呀,走开

  小羊:不用喝点,能怎样会的嘛

  狗妈:你喝就喝,咋还上头了呢?

  小羊:真香!

  狗妈:这羊犊子,真硬核!

现象报告 背景

  一天早上,楼主兴致勃勃的逛着园子的刚刚,右下角的 QQ 头像嘀嘀嘀的闪了起来,定睛一看,哎我去,肾要结速英语 了了疼了,就有,头要结速英语 了了疼了

  客服 MM:太躺,有个客户充值成功后,赠送的积分这样 到账

  楼主:是就有客户等级过高 ,不满足资格 ?

  客服 MM:客户等级是够的,他刚刚的积分都正常到账了

  楼主:刚刚的积分都到账了 ? 哪个客户,我去看看

  客服 MM:客户名是:xxx,对应的单号是:xxx,找到由于了跟你说下

  楼主:好的,找到由于了第一时间通知你

泰坦是楼主在公司内的花名,也是楼主的 LOL 本命英雄,慢慢的被传成太躺了,楼主也很无奈;
有小伙伴问楼主,你和客服 MM 哪几种关系,光看得人头像闪动就肾疼了 ?

  你這個 现象报告 问得好,改天楼主不用加鸡腿,着实楼主和客服着实挺熟悉的,工作交流挺多的,假如有一天仅限于同事关系! 吾乃心系天下之人,岂能被儿女情长所困 ? 只可惜客服 MM 已名花有主,不然就,嘿嘿嘿,大伙儿儿懂的(是那姓吾的小子心系天下,楼主不姓吾!)

现象报告 外理

  积分赠送是最近新上的另另一个功能,上了就有另另一个多星期了,到目前为止,也就你這個 客户反馈了你這個 现象报告 ,另外你這個 客户刚刚的积分就有赠送到账了的,应该是触发了這個 未考虑到的边界条件,产生了异常,由于积分未写入成功,照理来说,这应该是另另一个事务,要么都成功,要么就有成功呀

  肯能你這個 功能就有楼主开发的,出于快速外理现象报告 的考虑,楼主就找到了对应的开发同事小李,跟你说明了下状态,不用去排查下哪几种由于

  过了一会,小李找到了楼主,结速英语 了了了他的排查分享

  小李:太躺,我看得人下日志,肯能 xxx 状态未考虑到,由于加积分记录的刚刚抛异常了

  楼主:xxx 状态着实比较特殊,一般比较慢考虑到,假如有一天为哪几种存款成功了,积分却没加成功,你用了异步不 care 结果的外理 ?

  小李:我是同步外理的,照理来说,应该要回滚的

  楼主:那就奇了怪了,你把写入积分的法律土辦法 给我下,我去看看代码

  几分钟刚刚,楼主找到了小李,跟你说了下怎样会改,假如有一天不用把边界限制的外理也加进去去,走紧急流程升到了线上

  现象报告 外理后,小李又找到了楼主

  小李:太躺啊,为哪几种刚刚事务未回滚,而按你说的这样 改刚刚事务就会回滚了 ?

  楼主:你去把你的椅子拿过来,我跟你好好讲讲!

现象报告 复现

  注意啊,这就有说升级了刚刚线上又出现了同样的现象报告 ,并且 楼主为了让大伙儿儿更好的了解你這個 现象报告 ,模拟下当时的场景

  数据库版本 5.7.21 、存储引擎 InnoDB 、隔离级别 RR 、spring的传播机制 REQUIRED 、声明式事务 @Transactional 

  完整代码:data-init,后边的 TransactionMissTest ,关键代码如下

/**
 * 存款
 * 引入积分刚刚的外理
 * @param loginName
 * @param amount
 * @return
 */
@Override
@Transactional(rollbackFor = Exception.class)
public TranMissCredit deposit(String loginName, BigDecimal amount) {
    TranMissCredit credit = creditMapper.getByLoginName(loginName);
    BigDecimal creditAfter = credit.getCredit().add(amount);

    TranMissCreditLog creditLog = new TranMissCreditLog(loginName, credit.getCredit(),
            amount, creditAfter, "充值: " + amount);
    credit.setCredit(creditAfter);

    creditMapper.update(credit);
    int count = creditLogMapper.insert(creditLog);

    return credit;
}

/**
 * 存款
 * 引入积分后的新增的法律土辦法

 * @param loginName
 * @param amount
 * @param integration
 * @return
 */
@Override
public TranMissCredit deposit(String loginName, BigDecimal amount, int integration) {
    TranMissCredit credit = deposit(loginName, amount);             // 复用刚刚的存款逻辑

    // 下面是新增的积分业务
    int integrationAfter = credit.getIntegration() + integration;
    TranMissIntegrationLog log = new TranMissIntegrationLog(loginName, credit.getIntegration(),
            integration, integrationAfter, "充值赠送积分: " + integration);
    credit.setIntegration(integrationAfter);

    creditMapper.update(credit);
    integrationLogMapper.insert(log);
    return credit;
}


// 调用的地方,离米

Controller
@Autowired
private IDepositService depositService;

@Test
public void deposit() {

    // 积分引入前的调用
    // TranMissCredit credit = depositService.deposit("zhangsan", new BigDecimal(50));

    // 积分引入后的调用
    TranMissCredit credit = depositService.deposit("zhangsan", new BigDecimal(50), 10);

}
View Code

  看上去好像没毛病吧,楼主你就有蒙我了把 ? 蒙没蒙你,咱们找焦点访谈

  大伙儿儿先看下初始状态,目前只有客户 zhangsan ,其额度 50 ,积分 10 

  大伙儿儿来手动造个异常,模拟边界条件的触发,修改新增的 deposit 法律土辦法

  大伙儿儿来看看结果

  哟嚯,额度加成功了,积分却没加成功,事务没生效!是就有有点懵 ?

现象报告 分析

  大伙儿儿仔细观察下 deposit 法律土辦法 ,另另一个有 @Transactional 修饰,另另一个这样 ,就这另另一个差别;虽说只有这另另一个差别,但 Spring 却在幕后替大伙儿儿完成了并且事情

  Spring 事务原理

    关于你這個 ,我相信大伙儿儿都能答上来這個 ,底层实现并且 动态代理(你还告诉我动态代理 ?那还不赶紧去看:设计模式之代理,手动实现动态代理,揭秘原理实现)

    当 Spring 检查到 @Transactional ,会给目标对象创建另另一个代理对象,假如有一天在代理对象中给目标对象中被 @Transactional 修饰的法律土辦法 织入事务增强外理,类事并且

    肯能目标对象中这样 被 @Transactional 修饰的法律土辦法 ,在代理类中是怎样的了 ? 既然这样 被 @Transactional ,说明不时需事务增强外理嘛,那就直调呗

    回到大伙儿儿的案例,代理对象与被代理对象之间的调用如下

    能只有看出来,目标对象新增的法律土辦法  TranMissCredit deposit(String loginName, BigDecimal amount, int integration) 在代理对象内是这样 织入事务的,也并且 默认的自动提交,这样 异常抛出刚刚的数据库操作就有自动提交的,不用因后边的异常而回滚

    着实就有事务丢失了,并且 根本就没哟另另一个事务中

  再次校验

    不并且 Spring 事务,并且的 AOP 也都一样,代码中直接操作的往往就有目标对象,并且 目标对象的代理,通过代理对象来间接操作目标对象,而在代理对象中大伙儿儿能只有做這個 前置肯能后置的增强外理,不信 ? 大伙儿儿再次找焦点访谈

    打个断点,看看就知道了

    注入到 TransactionMissTest 的着实是代理对象

    大伙儿儿在 TranMissCredit deposit(String loginName, BigDecimal amount) 上打个断点,假如有一天四种 法律土辦法 各调用一次,来看看调用链有哪几种不一样

    以 depositService.deposit("zhangsan", new BigDecimal(50)); 法律土辦法 调用时

    此时调用链蕴含事务拦截器,有事务的调用链

    以 depositService.deposit("zhangsan", new BigDecimal(50), 10) 法律土辦法 调用时

    此时调用链中这样 事务拦截器,这样 事务的调用链

    是就有很明了了,so easy

总结

  1、正常上线流程

    线上现象报告 → 现象报告 定位 → 现象报告 复现 → 现象报告 修复 → 转测试 → 测试通过升线上

    而就有像文中说的这样 轻描淡写

  2、事务去哪了

    Spring 事务的底层实现并且 动态代理,是通过代理的法律土辦法 对目标对象做前后的增强外理,前置开启事务、后置提交(回滚)事务;

    增强外理在代理对象内,而就有在目标对象内,若目标对象的法律土辦法 这样 被 @Transactional 修饰,则在代理对象的代理法律土辦法 内不用有关于事务的增强外理,并且 直接调用目标对象的法律土辦法 ,这样 后续的数据库操作就就有在另另一个事务中了

    就有事务消失了,并且 没哟同另另一个事务了