tp5 处理并发问题

在TP5框架中,为解决并发查询可能导致的数据不一致问题,文章通过实例展示了如何在查询test表时使用加锁机制。在未加锁的情况下,并发请求导致数据表出现多条记录。而加入锁后,通过ab测试验证并发操作已得到正确处理,确保了数据表始终只有一条记录。

数据库创建test表,我们的需求是这样的,查询test表是否存在数据,不存在,就插入1条,保证数据表只有1条数据。

我们首先尝试查询不加锁,代码如下

   public function test_trans()
    {
        Db::startTrans(); // 启动事务
        try {
            $res = db('test')->find();
            if (!$res) {
                //执行你想进行的操作, 最后返回操作结果 result
                Db::name('test')->insert(array('age'=>20));
                $result = true;
                if (!$result) {
                    db('test')->rollback();//回滚
                }
            }
            Db::commit();
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();
        }
    }

用ab并发测试工具,请求10次,并发为5

数据库为显示5条数据,说明并发问题还存在.

 

我们加锁再试试

然后ab测试,结果如下,ok

结论:考虑到并发对表进行操作的时候,查询需要加锁

### 使用 ThinkPHP5 和 Redis 解决高并发问题的综合方案 #### 一、Redis 队列与异步处理ThinkPHP5 中集成 Redis 可以为系统提供高效的异步任务处理能力。通过结合 Redis 的数据结构(如 List 或 Stream),可以实现可靠的消息队列机制,从而缓解高并发压力并提升系统的可扩展性。 ```php <?php namespace app\index\controller; use think\Controller; use think\facade\Cache; class Order extends Controller { public function placeOrder() { $orderData = [ 'userId' => input('post.userId'), 'productId' => input('post.productId'), 'quantity' => input('post.quantity') ]; // 将订单信息推送到 Redis 队列中 Cache::store('redis')->rpush('order_queue', json_encode($orderData)); return ['status' => 'success', 'message' => 'Order placed successfully']; } } ``` 上述代码展示了如何将用户的订单请求写入 Redis 列表型队列 `order_queue` 中[^1]。 #### 二、消费者端的任务处理 为了确保消息队列中的任务能够被及时处理,在后台需要启动一个或多个消费者进程来持续拉取和执行这些任务。 ```php <?php // 消费者脚本 example_consumer.php while (true) { $orderDataJson = \think\facade\Cache::store('redis')->lpop('order_queue'); if (!$orderDataJson) { sleep(1); // 如果没有新任务,则休眠一秒再继续轮询 continue; } $orderData = json_decode($orderDataJson, true); try { processOrder($orderData['userId'], $orderData['productId'], $orderData['quantity']); } catch (\Exception $e) { logError("Failed to process order: " . $e->getMessage()); } } function processOrder($userId, $productId, $quantity) { // 处理具体业务逻辑,比如扣减库存、记录日志等操作... Db::name('products')->where(['id' => $productId])->dec('stock', $quantity); Db::name('orders')->insert([ 'user_id' => $userId, 'product_id' => $productId, 'quantity' => $quantity, 'created_at' => date('Y-m-d H:i:s') ]); } ``` 这段脚本会不断从 Redis 队列中取出待处理的订单,并调用相应的服务完成后续动作[^2]。 #### 三、分布式锁控制资源竞争 当面临大量用户同时访问同一份有限资源的情况时,仅依靠简单的数据库查询可能不足以完全杜绝超卖等问题的发生。此时可以引入基于 Redis 的分布式锁技术作为补充手段之一。 ```php <?php public static function acquireDistributedLock(string $resourceKey): bool { $ttlInSeconds = config('app.redis_lock_ttl'); // 锁定的有效期时间长度,默认单位为秒 return \think\facade\Cache::store('redis')->setNxEx($resourceKey, $ttlInSeconds, uniqid('', true)) !== false; } public static function releaseDistributedLock(string $resourceKey): void { \think\facade\Cache::store('redis')->del($resourceKey); } ``` 上面的方法实现了最基本的加解锁功能,适用于大多数场景下的独占式访问需求管理[^3]。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值