You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Terawallet插件并发下单致负余额,禁止负余额过滤器无效求助

解决Woo Wallet并发下单导致负余额的问题

问题根因

你使用的woo_wallet_disallow_negative_transaction过滤器仅在交易发起前做静态余额校验,但并发场景下两个请求会同时通过检查——第一个请求尚未完成余额扣减时,第二个请求读取到的仍是初始的20美元余额,最终导致超额扣减出现负余额。

修复方案

需要在余额扣减环节加入数据库级锁机制,确保同一用户的钱包操作串行执行,同时强化实时余额校验逻辑。

步骤1:替换原有过滤器,添加并发安全校验

移除之前的两个过滤器,改用以下代码:

add_filter('woo_wallet_disallow_negative_transaction', '__return_true', 10);

add_action('woo_wallet_before_debit', 'secure_wallet_debit_concurrent_check', 10, 3);
function secure_wallet_debit_concurrent_check($amount, $user_id, $note) {
    global $wpdb;
    
    // 对应Woo Wallet的钱包数据表,默认前缀为wp_
    $wallet_table = $wpdb->prefix . 'woo_wallet';
    // 数据库行锁:锁定当前用户的钱包记录,直到当前事务完成
    $user_wallet = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wallet_table WHERE user_id = %d FOR UPDATE", $user_id));
    
    if (!$user_wallet) {
        wp_die('钱包不存在');
    }
    
    // 实时校验:确保扣减后余额不小于0
    if ($user_wallet->balance - $amount < 0) {
        wp_die('余额不足,无法完成支付');
    }
}

步骤2:代码逻辑说明

  • FOR UPDATE语句:在数据库层面锁定当前用户的钱包行,其他并发请求必须等待当前事务结束才能读取/修改该记录,从根源避免竞态条件。
  • woo_wallet_before_debit钩子:在实际执行余额扣减前触发,做最终的实时余额校验,确保扣减操作安全。

步骤3:前置拦截优化(可选)

在 checkout 环节提前拦截,避免用户走到支付步骤:

add_action('woocommerce_checkout_process', 'pre_check_wallet_balance');
function pre_check_wallet_balance() {
    if (isset($_POST['payment_method']) && $_POST['payment_method'] === 'woo_wallet') {
        $user_id = get_current_user_id();
        $cart_total = WC()->cart->total;
        $wallet_balance = woo_wallet()->wallet->get_balance($user_id);
        
        if ($wallet_balance < $cart_total) {
            wc_add_notice('钱包余额不足,无法完成订单', 'error');
        }
    }
}

注意事项

  • 代码需添加到主题的functions.php文件或自定义插件中,禁止直接修改Woo Wallet核心文件。
  • 测试并发场景:可通过Postman等工具模拟同时发起的支付请求,验证余额不会出现负数。

内容的提问来源于stack exchange,提问作者Ahmed Salah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 10:35:24