已解决【webman】数据库没有真正写入数据

深蓝

出现一个让我很废脑的问题,我有一个接口,使用了ThinkORM,有事务,当请求后,会增加用户的余额。

刚开始启动webman运行,很正常,可以按照正常的流程去运行,数据也能正常的更新到数据库里。

但是过一会,假定为1个小时,我再次请求这个接口,接口能正常返回,返回接口能看到增加后的余额,增加余额后,我再去余额列表查看,数据也能获取到最新增加的余额增加记录。

我反复请求接口,都能正常运行,余额列表也能获取到最新的订单信息,但是奇怪的是,这个数据好像只存在于内存中,只有当前的连接能调用,我用另外的接口去请求最新的余额订单,返回的却是1个小时之前的数据。

我所有接口的读操作正常,所有的写操作都会出现这个问题。

我使用数据库软件,phpMyadmin和HeidiSQL查看数据库,均无法查到我后面接口请求的数据,只能查到1个小时前的数据。

程序是正常运行的,没有任何报错,运行逻辑也很清晰。

但是当我重新启动webman,我请求余额列表的数据,包括用户余额的数据,后面新增的数据都不存在了,请求的都是1个小时前的数据,因为后面的数据根本就没有实际写入到数据库里面。重启webman导致了数据库重新连接。

我使用了redis缓存,但是这个问题不是缓存的问题,我清除缓存,会出现一样的问题,缓存不可能在我重启后,就失效。

我被这个问题困扰了2天,后面我尝试使用webman/log这个插件,分析一下SQL数据,奇怪的是,竟然不会出现之前那种,请求正常,但是不会实际写入数据库这种情况了,竟然一切都恢复正常了。

当我将webman/log设置成false,不运行的时候,问题又会出现。

我之前也怀疑是事务没提交,但是根据运行流程,事务是肯定运行了,并且也能成功返回数据,只要我不重启webman,这些数据会一直存在,也会新增,只不过,只要我重启webman,一切都会回到之前。

因为webman/log会产生大量的日志,调试的时候能用一下,但是生产的时候不想使用,我想知道可能出现这个问题的原因,或者解决办法,有没有大神能告知一二,万分感谢,下面有一些具体的信息。

我论坛里面找到了二个类似的贴子
https://www.workerman.net/q/8570
https://www.workerman.net/q/7476

我使用的库

"require": {
    "php": ">=7.2",
    "workerman/webman-framework": "^1.5.0",
    "monolog/monolog": "^2.0",
    "tinywan/exception-handler": "^1.1",
    "webman/think-orm": "^1.0",
    "psr/container": "^2.0",
    "illuminate/redis": "^10.5",
    "symfony/cache": "^6.2",
    "webman/console": "^1.2",
    "topthink/think-log": "^2.0",
    "workerman/crontab": "^1.0",
    "kreait/firebase-php": "^7.2",
    "zjkal/time-helper": "^1.1",
    "tinywan/validate": "^0.0.6",
    "ext-openssl": "*",
    "yzh52521/webman-lock": "^1.0",
    "ext-pdo": "*",
    "yzh52521/webman-throttle": "^1.0",
    "google/apiclient": "^2.13",
    "symfony/translation": "^6.2",
    "webman/redis-queue": "^1.2",
    "vlucas/phpdotenv": "^5.5",
    "webman/log": "^1.1"
}

运行伪代码

// 增加硬币,然后写入订单凭证
$call_info = $request->all();
$datedCoins = UserModel::getCacheUserInfo($call_info['user_id'], 'coins') ?? 0;

Log::error('开始事务');
Db::startTrans();
try {
    $mysql_data = [
        'user_id' => $call_info['user_id'],
        'coins' => $call_info['reward_amount'],
        'dated_coins' => $datedCoins,
        'type' => 1,
    ];

    // 将硬币更新到用户表,增加硬币
    Log::error('准备更新user表');
    $result = (new UserModel())->where('user_id', '=', $call_info['user_id'])->cache(3600)->update(['coins'  => ['inc', $call_info['coins']]]);
    Log::error('user表更新成功');
    if ($result){
        // 写入订单表
        Log::error('user表硬币增加成功,开始写入订单表');
        (new AdOrderModel())->create($mysql_data);
        Log::error('订单表写入成功,准备提交事务');
        Db::commit();
        Log::error('事务提交成功');
        return show('Success');
    }else{
        Db::rollback();
        Log::error('coins增加失败');
        return show('fail');
    }
} catch (DbException $e) {
    Db::rollback();
    Log::error('coins增加失败');
} catch (\Exception $e) {
    Db::rollback();
    Log::error('coins增加失败');
}  finally {
    Log::error('广告硬币增加成功--------------------');
}

打印请求流程,有异常前和没有异常前都能正常执行这个流程。

[2023-06-08 09:37:27][error]:开始事务
[2023-06-08 09:37:27][error]:准备更新user表
[2023-06-08 09:37:27][error]:user表更新成功
[2023-06-08 09:37:27][error]:user表硬币增加成功,开始写入订单表
[2023-06-08 09:37:27][error]:订单表写入成功,准备提交事务
[2023-06-08 09:37:27][error]:事务提交成功
[2023-06-08 09:37:27][error]:返回成功
[2023-06-08 09:37:27][error]:广告硬币增加成功--------------------

已经解决,确实是事务的问题,如果大家不知道哪里事务有问题,安装webman/log插件,会自动报事务的异常,解决掉异常问题就解决了。

1101 6 2
6个回答

walkor

应该是事务没提交。安装 webman/log 后会自动检测未提交的事务,回滚并记录日志。
在runtime/logs/下的日志里找下ERROR 或 Uncommitted transaction关键字,看下是哪个请求没提交事务。

  • workers 2023-06-09

    webman/log是否可以增加一个配置项,可以配置是否启用日志记录?

  • Le 2023-06-09

    自己改下插件启用状态,或者自己弄个变量,是否启用插件就行了

  • 深蓝 2023-06-09

    确实是这样,我解决了Uncommitted transaction found and try to rollback的异常后,暂时还没有发现问题。

  • workers 2023-06-09

    找到了,这个插件自带有配置项

Tinywan

ThinkORM 事务如果使用 Db 的话,是不支持模型的,必须都是Db类才可以

  • Le 2023-06-09

    文档有说吗?一直都是DB类开启里面也会有model交叉。。

  • Tinywan 2023-06-09

    自己试试就知道了

  • Le 2023-06-09

    刚测试有效啊。。try里面用model 更新数据,然后后面报错,回滚,数据也没提交成功

  • Le 2023-06-09

    开启用的Db 开启

  • walkor 2023-06-09

    默认都有效。
    不过模型如果设置了connection要注意下,Db使用的时候也要指定相同的connection

  • Le 2023-06-09

    老大揭秘了,如果是多个connection要在同一个connection下,目前都是默认,,

  • 深蓝 2023-06-09

    感谢指点。

Le

这种情况,多数是事务没提交

  • 深蓝 2023-06-09

    感谢指点,正是事务的问题,使用webman/log插件后,会有提示异常,解决掉异常问题就解决了。

banro512

遇到过类似问题,事务没提交,回滚了。
解决方法

  1. 模型改成 Db
  2. 异常捕获使用 Throwable

catch (\Exception $e)
改成

catch (\Throwable $e)
  • Le 2023-06-09

    模型没办法用事务吗,测试没问题啊

  • walkor 2023-06-09

    模型可以事务

  • 深蓝 2023-06-09

    感谢指点。

JackDx

mark~

  • 暂无评论
Le

是因为Exception 没捕获到异常吗

  • 深蓝 2023-06-10

    因为事务没有提交,会出现事务错误,但是这个在当前请求不会出问题,会影响后面事务的运行,一直报错,安装webman/log后,会自动检测并回滚事务,并会给出错误提示,你根据提示,找到没运行事务的入口,解决掉,之前所有的问题就都解决了。

  • Le 2023-06-10

    哦哦,webman/log 还会自动回滚事务。。以为只能记录。。

🔝