本文主要是介绍webman 事务回滚失效问题记录,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
webman 事务回滚失效问题记录
简单介绍下webman
webman是一款基于workerman开发的高性能HTTP服务框架。webman用于替代传统的php-fpm架构,提供超高性能可扩展的HTTP服务。你可以用webman开发网站,也可以开发HTTP接口或者微服务。
除此之外,webman还支持自定义进程,可以做workerman能做的任何事情,例如websocket服务、物联网、游戏、TCP服务、UDP服务、unix socket服务等等。
是否推荐大家使用
首先,小编不会推荐看到的朋友使用,不是因为它不好,而是因为有更多的选择.
事务回滚失效问题排查
一段很普通的代码逻辑:更新订单退款状态字段+新增退款申请记录.然后在一个事务里就行原子操作.
return Db::transaction(function () use ($order, $explain) {$order->refund_status = OrderEnum::ORDER_REFUND_STATUS_ING;$order->save();$orderRefundModel = new OrderRefund();$orderRefundModel->refund_id = 'R' . date('YmdHis') . random_int(10000, 99999);$orderRefundModel->order_id = $order->order_id;$orderRefundModel->status = OrderEnum::ORDER_REFUND_APPLY_STATUS_ING;$orderRefundModel->refund_price = $order->paid_amount;$orderRefundModel->refund_num = 1;$orderRefundModel->refund_phone = $order->user_mobile;$orderRefundModel->refund_explain = $explain;$orderRefundModel->save();return $orderRefundModel->id;});
这样的代码在我们的laravel项目上是一点问题没有,但是在webman框架使用却出现了事务回滚失败的问题.
问题的原因
其实这个问题还是因为小编没有认真阅读官方文档导致的,而上面的代码导致了一个什么错误让回滚失效的呢?
当事务中操作模型时,特别需要注意模型是否设置了连接。如果模型设置了连接开启事务的时候要指定连接,否则事务无效(think-orm类似)。例如
<?phpnamespace app\model;
use support\Model;class User extends Model
{// 这里给模型指定了连接protected $connection = 'mysql';protected $table = 'users';protected $primaryKey = 'id';}
当模型指定了连接时,开启事务、提交事务、回滚事务必须指定连接
Db::connection('mysql')->beginTransaction();
try {// 业务处理$user = new User;$user->name = 'webman';$user->save();Db::connection('mysql')->commit();
} catch (\Throwable $exception) {Db::connection('mysql')->rollBack();
}
排错之路
通过代码是无法发现问题的,小编通过打开mysql 查询日志general_log来观察执行的sql
打开查询日志配置
[mysqld]
general_log = ON
# 这个日志文档路径必须要有权限写入,否则general_log打开失败
general_log_file = /path/to/your/logfile.logSHOW VARIABLES LIKE 'general_log%';
将 general_log 设置为 ON表示启用查询日志,general_log_file 指定了日志文件的路径,重启 MySQL 服务器:在修改了配置文件后,需要重启 MySQL 服务器以使更改生效。查看日志文件:启用查询日志后,MySQL 会将所有执行过的 SQL 语句记录到指定的日志文件中。您可以查看该文件以获取所有 SQL 语句以及它们对应的连接信息。
查询日志
从上面的日志我们可以看到,事务和业务sql对应的线程ID是不一样的,那么这就是事务回滚两个业务sql不启用的原因了
为啥是不同的线程ID呢
线程ID不一样,肯定是两边分别创建了各自的连接,那我们就开始排查.通过查找了,我发现了webman admin 插件所有的model 都继承了Base类,而Base类指定了连接名,这下就破案了,也对应了官方的那句话:当模型指定了连接时,开启事务、提交事务、回滚事务必须指定连接
因此我们正确的代码:
Db::connection('plugin.admin.mysql')->transaction(...)
再看看连接的源码,默认的连接指向我们配置文件`database.php`的default属性值
DB manager 源码:
/*** Get a database connection instance.** @param string|null $name* @return \Illuminate\Database\Connection*/public function connection($name = null){[$database, $type] = $this->parseConnectionName($name);$name = $name ?: $database;// If we haven't created this connection, we'll create it based on the config// provided in the application. Once we've created the connections we will// set the "fetch mode" for PDO which determines the query return types.if (! isset($this->connections[$name])) {$this->connections[$name] = $this->configure($this->makeConnection($database), $type);}return $this->connections[$name];}/*** Parse the connection into an array of the name and read / write type.** @param string $name* @return array*/protected function parseConnectionName($name){$name = $name ?: $this->getDefaultConnection();return Str::endsWith($name, ['::read', '::write'])? explode('::', $name, 2) : [$name, null];}/*** Make the database connection instance.** @param string $name* @return \Illuminate\Database\Connection*/protected function makeConnection($name){$config = $this->configuration($name);// First we will check by the connection name to see if an extension has been// registered specifically for that connection. If it has we will call the// Closure and pass it the config allowing it to resolve the connection.if (isset($this->extensions[$name])) {return call_user_func($this->extensions[$name], $config, $name);}// Next we will check to see if an extension has been registered for a driver// and will call the Closure if so, which allows us to have a more generic// resolver for the drivers themselves which applies to all connections.if (isset($this->extensions[$driver = $config['driver']])) {return call_user_func($this->extensions[$driver], $config, $name);}return $this->factory->make($config, $name);}
这篇关于webman 事务回滚失效问题记录的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!