insertGetId 并发 返回重复id

windthesky

问题描述

用的webman/database 模型

eventLoop使用 Workerman\Events\Fiber::class;
并发上传,用insertGetId返回数据库id,会重复,数据库里面是正常自增字段

截图
截图
截图

程序代码或配置

/**
     * 上传文件
     * @param Request $request
     * @return Response
     */
    public function upload_file(Request $request): Response
    {
        try {
            add_log('上传文件');
            $user = $request->token_user;
            $file = $request->file('file');
            $type = $request->post('type');
            $位置 = $request->post('位置');
            if ($file && $type && $file->isValid()) {
                $ext = $file->getUploadExtension();
                if (in_array($ext, ['php', 'html', 'sql', 'json'])) {
                    return response('文件类型错误', 503);
                }

                if (in_array($type, ['头像', '头图', '详情图'])) {
                    if (!in_array($ext, ['jpg', 'jpeg', 'png', 'gif'])) {
                        return response('非图片格式', 503);
                    }
                    if ($file->getSize() > 1024 * 1024 * 10) {
                        return response('图片大小不能超过10M', 503);
                    }
                } else if ($type === '附件') {
                    if (!in_array($ext, ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'zip', 'rar', 'jpg', 'jpeg', 'png', 'gif'])) {
                        return response('附件格式错误', 503);
                    }
                    if ($file->getSize() > 1024 * 1024 * 100) {
                        return response('附件大小不能超过100M', 503);
                    }
                } else {
                    return response('参数错误', 503);
                }
                $format      = $file->getExtension();
                $upload_name = $file->getUploadName();
                if (empty($upload_name)) return response('文件名错误,请修改文件名', 503);
                $name = Tool::get_microtime();
                $dir  = public_path() . '/files/upload/' . date('Ym') . '/' . date('d') . '/';
                if (!is_dir($dir)) mkdir($dir, 0777, true);
                $file->move($dir . $name . '.' . $ext);
                $file_url = 'files/upload/' . date('Ym') . '/' . date('d') . '/' . $name . '.' . $ext;
                $path2    = public_path() . '/' . $file_url;

                switch ($type) {
                    case '头像':
                        Image::load($path2)
                            ->optimize()
                            ->fit(Fit::Stretch, 100, 100)
                            ->quality(75)
                            ->save();
                        break;
                    case '详情图':
                        Image::load($path2)
                            ->optimize()
                            ->fit(Fit::Max, 800)
                            ->quality(75)
                            ->save();
                        break;
                    case '头图':
                        Image::load($path2)
                            ->optimize()
                            ->fit(Fit::Max, 500)
                            ->quality(75)
                            ->save();
                        break;
                    default:
                        break;
                }

                $imageInfo = getimagesize($path2);
                $fileSize  = filesize($path2);
                $sha1      = sha1_file($path2);

                $file_id = UploadFile::insertGetId([
                    '类型'     => $type,
                    '名称'     => $upload_name,
                    '网址'     => $file_url,
                    '目录'     => $path2,
                    '位置'     => $位置,
                    '文件大小' => $fileSize,
                    '文件格式' => $format,
                    '后缀'     => $ext,
                    '录入人'   => $user['姓名'],
                    'sha1'     => $sha1,
                    'width'    => $imageInfo[0] ?? 0,
                    'height'   => $imageInfo[1] ?? 0,
                ]);

                return res_success([
                    'id'   => $file_id,
                    'name' => $upload_name,
                    'url'  => $file_url,
                    'size' => $fileSize,
                    'type' => $ext,
                ], '上传成功');
            }
            return response('参数错误', 503);
        } catch (Throwable $e) {
            write_log('exception', 'error', '上传文件', $e);
            return response('上传失败', 503);
        }
    }

重现问题的步骤

并发同时请求就会

操作系统环境及workerman/webman等具体版本

这里写具体的系统环境相关信息
截图

383 9 0
9个回答

tanhongbin

不会吧,你不用fiber 试试呢

  • windthesky 4天前

    'eventLoop' => ''也一样

  • tanhongbin 4天前

    不可能,绝对不可能,你用的那个orm,lv的还是tp的?

  • windthesky 4天前

    webman/database 是 用laravel的illuminate/database

  • tanhongbin 4天前

    这个我测试过 真没发现还有这个问题呢,我也压力测试过,没出现重复的

  • windthesky 4天前

    并发有小于10毫秒以下吗?

  • tanhongbin 4天前

    webman内网测试基本都是5ms以内的,除非你的mysql太垃圾了

  • windthesky 4天前

    那就奇怪了,而且数据库是正常的

  • tanhongbin 4天前

    你在linux测试的嘛,能不能在测试测试截个图,多少并发能复现?

  • windthesky 4天前

    在window测试,就一个上传,同时上传几个文件,就会发生

windthesky

截图
截图
截图
截图
截图
多个上传都是有重复的

  • 暂无评论
windthesky

截图
数据库配置

  • tanhongbin 4天前

    你开启协程了嘛???

  • windthesky 4天前

    window不知道有没有,但这个配置是默认的,不管有没有协程

  • tanhongbin 4天前

    如果开启协程 或者 你使用swon 那个就会自动变成协程,本地可以卸载然后evenloop => '' windows更不会并发处理就一个进程 你想用多进程必须linux代理多端口 才行,我测试没问题

windthesky

截图
截图
版本如截图所示

  • 暂无评论
hub_rb

linux上并发设置都没问题建议你看下mysql配置
或者在每个请求结束也就是response上吧lastId写入log文件 也有可能是opcache缓存的问题

  • tanhongbin 3天前

    这个明显不符合mysql的逻辑 它就不可能返回两个相同的id 主键自增的情况下

  • hub_rb 3天前

    这个也确实 毕竟入库数据没问题 基本应该就是业务代码层面的问题了

windthesky

测试了,跟长id有关系,1000000000000001不会,10000000000000001会重复

截图
截图

  • lsmir2 3天前

    数据库表结构,id字段类型.

  • windthesky 3天前

    bigint本身数据库是没问题的,是获取的id有问题

TomMilk

js数字处理的问题吧

  • 暂无评论
nitron

楼上说的,JS对bigint的处理问题,要么就用json-bigint包,要么就将id返回时转成string

  • 暂无评论
damao

截图

上面说的对,js支持不了那么大的数字,打印下就能看出来,是乱的重复的。

  • tanhongbin 2天前

    这还真是js问题,看来打印的时候他没用webman的窗口打印,直接用的js打印的

🔝