带有大量数据库修改和事务的业务操作,要批量操作怎么实现最好?

我有一个功能,和余额变动相关,保守估计至少要同时修改5张表。

单独做这个功能并不复杂,但是我现在有个批量操作的需求,比如一次性提交100条,那我就得一次性修改5张表*100次,执行最少500次sql,这显然不太科学。

可以把它放到队列里执行,但是消费到这条队列消息可能需要时间,且执行这条队列消息一定会消耗时间,就会出现用户提交请求,也提示成功,但是刷新后这些数据还是显示未处理的情况。

如果提交时sql加in一次性先把这些数据加状态隐藏起来,慢慢等业务执行完,又有点头疼,因为执行可能需要时间,应该收到余额的用户和操作人可能会出现一时半会对不上账的情况。其次如果执行失败再退回去对用户也不太友好,因为之前已经提示他成功了。

有没有老哥有什么优雅的方式完美解决这个问题

:) wink
唐章明
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 6

放队列,用户提交后换个说法就行了

1周前 评论

在批量操作的地方直接告诉用户批量操作是非实时的,数据更新会有延迟

1周前 评论

看这个批量能不能批量进行修改

1周前 评论

使用 case 聚合更新 五张表的话就是5条sql 。更新条件走主键id的话没什么问题

Laravel
模型类 use 后使用:

// $update = [["id"=>1,"filed"=>"更新字段",....]]
app()->make(Table::class)->updateBatch($update);

方法:

 /**
     * 批量更新方法
     * @param $multipleData
     * @return int
     * @throws Exception
     */
    public function updateBatch($multipleData = []): int
    {
        try {
            if (empty($multipleData)) {
                throw new Exception("数据不能为空");
            }
            $tableName = DB::getTablePrefix() . $this->getTable(); // 表名
            $firstRow = current($multipleData);
            $updateColumn = array_keys($firstRow);
            // 默认以id为条件更新,如果没有ID则以第一个字段为条件
            $referenceColumn = isset($firstRow['id']) ? 'id' : current($updateColumn);
            unset($updateColumn[0]);
            // 拼接sql语句
            $updateSql = "UPDATE " . $tableName . " SET ";
            $sets = [];
            $bindings = [];
            foreach ($updateColumn as $uColumn) {
                $setSql = "`" . $uColumn . "` = CASE ";
                foreach ($multipleData as $data) {
                    $setSql .= "WHEN `" . $referenceColumn . "` = ? THEN ? ";
                    $bindings[] = $data[$referenceColumn];
                    $bindings[] = $data[$uColumn];
                }
                $setSql .= "ELSE `" . $uColumn . "` END ";
                $sets[] = $setSql;
            }
            $updateSql .= implode(', ', $sets);
            $whereIn = collect($multipleData)->pluck($referenceColumn)->values()->all();
            $bindings = array_merge($bindings, $whereIn);
            $whereIn = rtrim(str_repeat('?,', count($whereIn)), ',');
            $updateSql = rtrim($updateSql, ", ") . " WHERE `" . $referenceColumn . "` IN (" . $whereIn . ")";
            // 传入预处理sql语句和对应绑定数据

            return DB::connection($this->connection)->update($updateSql, $bindings);
        } catch (Exception $e) {
            throw new Exception($e->getMessage());
        }
    }
1周前 评论

参考一下某些银行的做法, 转账的时候有一个等待窗口, 然后转账后提示不要在此页面离开, xs 后自动查询结果

代码上锁, 处理完成写一条消息余额变动, 然后界面轮询这个消息状态

1周前 评论

涉及到钱?涉及到钱的别做什么批量,安安心心一条条处理。与产品经理互怼,提交的100条第90条格式错误怎么办,执行到90条时OOM意外退出怎么办,用户在两个窗口提交两次100条怎么办,执行到90条余额不够了怎么办,第90余额只够一部分不够全部怎么办,用户在一个页面提交完又刷新提交了一次怎么办,有没有办法识别两次处理的同一个100条,处理100条时间长怎么告诉用户要等。并不是银行可以做你们就可以做。银行也是提交个代发工资excel 晚上才一起发的。为了鲁棒付出的代价到底值不值得。

1周前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!