|
|
@@ -0,0 +1,206 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+/**
|
|
|
+ * 手动测试脚本:验证物品冻结过程中的并发安全性
|
|
|
+ *
|
|
|
+ * 测试lock for update是否能正确处理冻结操作的并发场景
|
|
|
+ */
|
|
|
+
|
|
|
+require_once __DIR__ . '/../vendor/autoload.php';
|
|
|
+
|
|
|
+use App\Module\GameItems\Services\ItemService;
|
|
|
+use App\Module\GameItems\Enums\FREEZE_REASON_TYPE;
|
|
|
+use Illuminate\Support\Facades\DB;
|
|
|
+
|
|
|
+// 启动Laravel应用
|
|
|
+$app = require_once __DIR__ . '/../bootstrap/app.php';
|
|
|
+$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
|
|
|
+
|
|
|
+echo "=== 物品冻结并发安全性测试 ===\n\n";
|
|
|
+
|
|
|
+try {
|
|
|
+ DB::beginTransaction();
|
|
|
+
|
|
|
+ $userId = 1001;
|
|
|
+ $itemId = 1;
|
|
|
+
|
|
|
+ echo "1. 准备测试数据\n";
|
|
|
+
|
|
|
+ // 添加物品
|
|
|
+ $addResult = ItemService::addItem($userId, $itemId, 100);
|
|
|
+ echo " 添加物品: " . json_encode($addResult, JSON_UNESCAPED_UNICODE) . "\n";
|
|
|
+
|
|
|
+ // 检查初始状态
|
|
|
+ echo "\n2. 检查初始物品状态\n";
|
|
|
+ $userItems = DB::table('item_users')
|
|
|
+ ->where('user_id', $userId)
|
|
|
+ ->where('item_id', $itemId)
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ foreach ($userItems as $item) {
|
|
|
+ $frozenStatus = $item->is_frozen ? '冻结' : '可用';
|
|
|
+ echo " 物品堆ID: {$item->id}, 数量: {$item->quantity}, 状态: {$frozenStatus}\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 测试正常冻结
|
|
|
+ echo "\n3. 测试正常冻结(锁定机制)\n";
|
|
|
+ $freezeResult1 = ItemService::freezeItem(
|
|
|
+ $userId,
|
|
|
+ $itemId,
|
|
|
+ null,
|
|
|
+ 30,
|
|
|
+ FREEZE_REASON_TYPE::TRADE_ORDER->value,
|
|
|
+ [
|
|
|
+ 'source_id' => 12345,
|
|
|
+ 'source_type' => 'test_order_1',
|
|
|
+ 'operator_id' => 1
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ echo " 冻结30个成功: " . json_encode($freezeResult1, JSON_UNESCAPED_UNICODE) . "\n";
|
|
|
+
|
|
|
+ // 检查冻结后状态
|
|
|
+ echo "\n4. 检查冻结后的物品状态\n";
|
|
|
+ $userItemsAfter = DB::table('item_users')
|
|
|
+ ->where('user_id', $userId)
|
|
|
+ ->where('item_id', $itemId)
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ foreach ($userItemsAfter as $item) {
|
|
|
+ $frozenStatus = $item->is_frozen ? '冻结' : '可用';
|
|
|
+ echo " 物品堆ID: {$item->id}, 数量: {$item->quantity}, 状态: {$frozenStatus}\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 测试再次冻结
|
|
|
+ echo "\n5. 测试再次冻结剩余物品\n";
|
|
|
+ $freezeResult2 = ItemService::freezeItem(
|
|
|
+ $userId,
|
|
|
+ $itemId,
|
|
|
+ null,
|
|
|
+ 40,
|
|
|
+ FREEZE_REASON_TYPE::TRADE_ORDER->value,
|
|
|
+ [
|
|
|
+ 'source_id' => 12346,
|
|
|
+ 'source_type' => 'test_order_2',
|
|
|
+ 'operator_id' => 1
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ echo " 冻结40个成功: " . json_encode($freezeResult2, JSON_UNESCAPED_UNICODE) . "\n";
|
|
|
+
|
|
|
+ // 检查再次冻结后状态
|
|
|
+ echo "\n6. 检查再次冻结后的物品状态\n";
|
|
|
+ $userItemsAfter2 = DB::table('item_users')
|
|
|
+ ->where('user_id', $userId)
|
|
|
+ ->where('item_id', $itemId)
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ foreach ($userItemsAfter2 as $item) {
|
|
|
+ $frozenStatus = $item->is_frozen ? '冻结' : '可用';
|
|
|
+ echo " 物品堆ID: {$item->id}, 数量: {$item->quantity}, 状态: {$frozenStatus}\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 测试边界情况:冻结全部剩余数量
|
|
|
+ echo "\n7. 测试边界情况:冻结全部剩余数量\n";
|
|
|
+ $freezeResult3 = ItemService::freezeItem(
|
|
|
+ $userId,
|
|
|
+ $itemId,
|
|
|
+ null,
|
|
|
+ 30,
|
|
|
+ FREEZE_REASON_TYPE::TRADE_ORDER->value,
|
|
|
+ [
|
|
|
+ 'source_id' => 12347,
|
|
|
+ 'source_type' => 'test_order_3',
|
|
|
+ 'operator_id' => 1
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ echo " 冻结30个成功: " . json_encode($freezeResult3, JSON_UNESCAPED_UNICODE) . "\n";
|
|
|
+
|
|
|
+ // 检查完全冻结后状态
|
|
|
+ echo "\n8. 检查完全冻结后的物品状态\n";
|
|
|
+ $userItemsFinal = DB::table('item_users')
|
|
|
+ ->where('user_id', $userId)
|
|
|
+ ->where('item_id', $itemId)
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ foreach ($userItemsFinal as $item) {
|
|
|
+ $frozenStatus = $item->is_frozen ? '冻结' : '可用';
|
|
|
+ echo " 物品堆ID: {$item->id}, 数量: {$item->quantity}, 状态: {$frozenStatus}\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 测试数量不足的情况
|
|
|
+ echo "\n9. 测试数量不足的情况\n";
|
|
|
+ try {
|
|
|
+ $freezeResult4 = ItemService::freezeItem(
|
|
|
+ $userId,
|
|
|
+ $itemId,
|
|
|
+ null,
|
|
|
+ 10,
|
|
|
+ FREEZE_REASON_TYPE::TRADE_ORDER->value,
|
|
|
+ [
|
|
|
+ 'source_id' => 12348,
|
|
|
+ 'source_type' => 'test_order_4',
|
|
|
+ 'operator_id' => 1
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ echo " 意外成功: " . json_encode($freezeResult4, JSON_UNESCAPED_UNICODE) . "\n";
|
|
|
+ } catch (Exception $e) {
|
|
|
+ echo " 预期失败: " . $e->getMessage() . "\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 测试解冻后再冻结
|
|
|
+ echo "\n10. 测试解冻后再冻结\n";
|
|
|
+
|
|
|
+ // 先解冻一个
|
|
|
+ $freezeLogId = $freezeResult1['frozen_items'][0]['freeze_log_id'];
|
|
|
+ $unfreezeResult = ItemService::unfreezeItem($freezeLogId);
|
|
|
+ echo " 解冻成功: " . json_encode($unfreezeResult, JSON_UNESCAPED_UNICODE) . "\n";
|
|
|
+
|
|
|
+ // 检查解冻后状态
|
|
|
+ echo " 解冻后物品状态:\n";
|
|
|
+ $userItemsUnfrozen = DB::table('item_users')
|
|
|
+ ->where('user_id', $userId)
|
|
|
+ ->where('item_id', $itemId)
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ foreach ($userItemsUnfrozen as $item) {
|
|
|
+ $frozenStatus = $item->is_frozen ? '冻结' : '可用';
|
|
|
+ echo " 物品堆ID: {$item->id}, 数量: {$item->quantity}, 状态: {$frozenStatus}\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 再次冻结
|
|
|
+ echo " 再次冻结部分物品:\n";
|
|
|
+ $freezeResult5 = ItemService::freezeItem(
|
|
|
+ $userId,
|
|
|
+ $itemId,
|
|
|
+ null,
|
|
|
+ 15,
|
|
|
+ FREEZE_REASON_TYPE::TRADE_ORDER->value,
|
|
|
+ [
|
|
|
+ 'source_id' => 12349,
|
|
|
+ 'source_type' => 'test_order_5',
|
|
|
+ 'operator_id' => 1
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ echo " 冻结15个成功: " . json_encode($freezeResult5, JSON_UNESCAPED_UNICODE) . "\n";
|
|
|
+
|
|
|
+ // 检查最终状态
|
|
|
+ echo "\n11. 检查最终物品状态\n";
|
|
|
+ $userItemsEnd = DB::table('item_users')
|
|
|
+ ->where('user_id', $userId)
|
|
|
+ ->where('item_id', $itemId)
|
|
|
+ ->get();
|
|
|
+
|
|
|
+ foreach ($userItemsEnd as $item) {
|
|
|
+ $frozenStatus = $item->is_frozen ? '冻结' : '可用';
|
|
|
+ echo " 物品堆ID: {$item->id}, 数量: {$item->quantity}, 状态: {$frozenStatus}\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ echo "\n=== 测试完成 ===\n";
|
|
|
+
|
|
|
+ DB::rollback();
|
|
|
+ echo "已回滚测试数据\n";
|
|
|
+
|
|
|
+} catch (Exception $e) {
|
|
|
+ DB::rollback();
|
|
|
+ echo "测试失败: " . $e->getMessage() . "\n";
|
|
|
+ echo "堆栈跟踪: " . $e->getTraceAsString() . "\n";
|
|
|
+}
|