情况是这样的,今天测试反馈一个bug,说是用户上课签到完成后为嘛奖励的积分没有好好反馈过来,用户的积分还是保持着原样。
    其实,对用户积分的计算我是放在一个定时任务中的,任务中遍历课程和用户,只要课程都有效签到的用户才奖励对应的积分,都未有效签到则扣除。

    然后我调用任务日志,发现了这句:
    2018-12-05 16:01:28-执行【签到积分计算】报名惩罚发生异常:更新用户积分失败【…….】

    很显然,就是这个用户在写数据时出了问题
    然后一个人的问题影响了所有人….
    这个肯定是要不得的

    罢了,先看下我原来的代码

    1. //.....
    2. # 开启事务
    3. $transaction = Yii::$app->db->beginTransaction();
    4. try {
    5. # 更新该培训所有上课用户的未到场次数
    6. if (!empty($endTrains)) {
    7. /** @var Train $items */
    8. foreach ($endTrains as $items) {
    9. # 更新培训用户未到场次数
    10. $sql = "UPDATE tb_users_train SET not_num = should_num - already_num WHERE train_id = {$items->train_id}";
    11. Yii::$app->db->createCommand($sql)->execute();
    12. # 只有有积分规则的才能更新用户积分情况
    13. if ($items->point_rule > 0) {
    14. //$trainIds[] = $item->train_id;
    15. # 更新用户积分情况:全到场加分,一次都未到场减分(有效签到一次为一次到场)
    16. ## 必参到场奖励
    17. $must_sign_honor = isset($pointsRules[$items->point_rule]['must_sign_honor']) ? round($pointsRules[$items->point_rule]['must_sign_honor']) : 0;
    18. if ($must_sign_honor > 0) {
    19. //这有一大坨代码...
    20. #更改用户积分并写入用户-积分记录表
    21. $change_res = MCommonFunc::ChangeUserPoints($item->user_id, 1, $must_sign_honor, $item->org_id, 1, $items->train_id, 0, $items->train_name, $items->train_type, "校内课程{$items->train_name}签到奖励");
    22. if ($change_res === false) {
    23. $transaction->rollBack();
    24. $errMessage = "更新用户积分失败【train_id:{$items->train_id},train_name:{$items->train_name},user_id:{$item->user_id}";
    25. LogUtils::writeTask('执行【积分任务】发生异常:'.$errMessage);
    26. return false;
    27. }
    28. #积分变动:通知消息入库
    29. //这有一大坨代码...
    30. ## 报名到场奖励
    31. //这有一大坨代码...
    32. if (!$item->update()) {
    33. $transaction->rollBack();
    34. $errMessage = "更新用户培训积分状态失败【train_id:{$items->train_id},train_name:{$items->train_name},user_id:{$item->user_id}";
    35. LogUtils::writeTask('执行【积分任务】发生异常:'.$errMessage);
    36. return false;
    37. }
    38. //这有一大坨代码...
    39. }
    40. }catch (\Exception $exception){
    41. $transaction ->rollBack();
    42. echo "异常:".$exception->getMessage();
    43. return false;
    44. }
    45. $transaction ->commit();
    46. //.....

    由此可见,循环中某个用户出错,就会直接return掉,后面的用户就没机会执行了


    那么要解决这种问题,肯定不能用用return,应该直接用continue;

    于是我所有的return false 改为 continue。


    结果还是报错了:
    2018-12-05 16:01:25-执行【计算积分任务】发生异常:Failed to commit transaction: transaction was inactive.

    查阅资料知道是事务的原因。在同事的帮助下说我每个事务都应该重新弄,意思是每个循环都得独立一个事务。然后在他的建议下,终于解决问题。

    1. # 更新该培训所有上课用户的未到场次数
    2. if (!empty($endTrains)) {
    3. /** @var Train $items */
    4. foreach ($endTrains as $items) {
    5. # 开启事务
    6. $transaction = Yii::$app->db->beginTransaction();
    7. try{
    8. //计算积分的处理
    9. $res = self::dealPoints($items,$pointsRules);
    10. if(!$res){
    11. $transaction->rollBack();
    12. continue;
    13. }
    14. else{
    15. $transaction ->commit();
    16. }
    17. }catch (\Exception $exception){
    18. $transaction ->rollBack();
    19. echo "异常:".$exception->getMessage();
    20. return false;
    21. }
    22. }
    23. }
    24. //...

    这样一来也简单清晰得多,也不用那么多rollback。