重复支付是一个订单客户支付多次,造成重复支付。
在扫码支付中,可能存在重复支付的问题,通过以下方式去避免重复支付:
1、同一个订单同一个支付渠道只生成一个支付二维码。
2、在请求第三方支付下单使用分布式锁控制不会重复请求第三方下单。
3、切换支付渠道时先关闭原渠道的交易单再生成新渠道的交易单。
4、使用定时任务每天扫描交易单表,如果存在多个支付成功的交易单则进行自动退款。
1. 背景
在支付服务中,目前共设计了四张表。
1.1 支付渠道表 (pay_channel)
用于存储支付渠道的配置信息,主要记录了支付相关的密钥、加密参数以及回调地址等,确保可以根据不同支付渠道选择相应的配置。
1.2 交易单表 (trading)
记录每一笔交易的详细信息,包括支付渠道、金额、状态、收付款双方的基本信息等。还设计了退款的相关字段,用于跟踪订单是否已发起退款及退款金额。
1.3 退款记录表 (refund_record)
详细记录了每次退款的申请和处理结果,特别是在部分退款或多次退款的情况下,保证退款信息的完整性和可追溯性。
1.4支付日志表(payment_log)
为确保支付的安全性和可靠性,可以考虑增加支付日志表记录每次请求与响应。
2. 同一个订单同一支付渠道只生成一个支付二维码
2.1 关联数据库设计
trading
表中的trading_order_no
(交易订单号)是每次支付的唯一标识符。通过该字段可以确保一个订单在一个支付渠道下只能生成一个二维码。pay_channel
表中保存了不同支付渠道的信息,确保每个支付渠道只关联一个二维码。
2.2 控制措施
- 每次支付时,查询该订单的支付渠道(如微信、支付宝),并通过
trading_channel
确认该支付渠道下是否已经生成了二维码。 - 如果该支付渠道已经有对应的支付记录,则不再生成新的二维码,避免生成多个二维码导致用户重复支付。
3. 使用分布式锁防止重复请求第三方下单
3.1 关联数据库设计
trading_order_no
和transaction_id
字段在trading
表中用作订单和支付平台订单的唯一标识。
3.2 控制措施
- 每次向第三方支付平台请求下单时,使用分布式锁来锁定该
trading_order_no
或product_order_no
。 - 锁的生效时间持续到支付请求处理完毕,避免多个支付请求同时向第三方支付平台发起下单,导致多个支付订单生成。
3.3 锁实现
- 可使用 Redis 分布式锁或其他基于数据库的锁机制来保证同一时间只有一个支付请求可以处理该订单。
4. 切换支付渠道时,关闭原渠道交易单再生成新渠道交易单
4.1 关联数据库设计
- 在
trading
表中,trading_channel
字段保存了不同的支付渠道,而trading_state
字段表示当前交易状态。
4.2 控制措施
- 当用户切换支付渠道时,系统首先会更新当前渠道的
trading_state
为“关闭”或“失效”,确保该订单在原支付渠道下不会再进行支付操作。 - 然后,为新选择的支付渠道生成一个新的交易记录,并生成新的支付二维码,确保每个渠道只有一个有效的支付请求。
5. 定时任务扫描交易单并自动退款
5.1 关联数据库设计
trading
表中trading_state
和is_refund
字段表示订单支付状态以及是否发生退款。refund_record
表记录了退款信息。
5.2 控制措施
- 系统通过定时任务(如每天凌晨)扫描
trading
表,检查是否有相同product_order_no
的多条交易记录支付成功。 - 如果发现某个订单有多条成功的支付记录,系统自动调用第三方支付平台的退款接口,生成相应的退款单,并在
refund_record
表中记录退款信息。
6. 总结
在扫码支付中,可能存在重复支付的问题,通过以下方式去避免重复支付:
1、同一个订单同一个支付渠道只生成一个支付二维码。
2、在请求第三方支付下单使用分布式锁控制不会重复请求第三方下单。
3、切换支付渠道时先关闭原渠道的交易单再生成新渠道的交易单。
4、使用定时任务每天扫描交易单表,如果存在多个支付成功的交易单则进行自动退款。
通过上述措施,系统可以避免由于支付二维码重复生成、支付请求重复发起或支付渠道切换导致的重复支付问题,确保每笔订单只会有一次有效的支付结果。