两笔收据编号相同的交易

时间:2018-09-20 04:41:10

标签: php mysqli

我有一个支付系统,为此我会为每笔交易生成一个收据编号(以递增方式工作)。过程类似于用户点击付款时,然后向服务器发送请求,服务器从数据库中获取最新的收据编号,将其递增1,然后立即将其保存到数据库中以进行进一步的交易,依此类推。正在以xx000001格式生成收据编号,其中xx是字符。

问题:-有时两个或多个交易正在使用相同的收据编号处理。

可能的情况:-我想出的情况是-假设有人按了一下,然后服务器获取了最新的收据编号,而服务器正在做增量操作,则有新交易进入并获取了相同的收据编号就像前一个一样,他们两个都进行递增操作,并且得到相同的收据编号。

我们将不胜感激!

谢谢

1 个答案:

答案 0 :(得分:1)

听起来像是经典的问题:您没有线程安全!并发请求(通常是http服务器,通常会处理并发请求),以防止关键步骤(可能会造成冲突)并行执行。 >

您可以通过多种方法来解决此问题:

  1. 在您的逻辑中创建线程安全性

请小心创建某种形式的锁,该锁可以阻止一次处理多个进程,尽管这仅用于关键步骤,此处是该计数器的增量。 php没有提供类似Java的synchronized关键字那样的功能,因此您必须自己实现。最简单的方法是基于文件系统的经典Unix锁定文件:需要唯一访问的进程将请求锁定文件。如果它确实不存在,则将生成它(通常以进程的进程ID作为内容),并且该进程将执行其操作,直到完成为止,并注意再次释放锁/再次删除锁文件。只有这样,第二个进程才能创建该文件,直到该文件被阻止(挂起)。重试以获得唯一日志可以通过原始的轮询策略来实现,因此锁定获取请求每隔几百毫秒就会尝试一次,或者您可以实现一个排队系统,该系统还应注意将请求进程保持在定义的顺序中。处理,并且可以处理清除程序,例如删除过时的锁定文件(在某些程序崩溃或过时之后)。

  1. 使用信号量进行锁定

与上述相同,但是您依靠php的“信号量”来实现锁定本身: http://php.net/manual/en/ref.sem.php

  1. 在数据库内部使用表锁定

与上面相同,但是您依赖数据库引擎的锁定功能(取决于您使用的数据库引擎的类型)。最后,这样做更快,更容易实现,因为无论如何您都需要与数据库进行交互。

  1. 使用存储过程

您还可以将关键部分移动到数据库内部的存储过程中。这允许在单个数据库事务中执行所需的步骤,可以保证每个定义完全执行或完全不执行。因此,您将在计数器表中生成一个新的ID作为主键。然后,如果您将该键用于在数据库中执行的同一事务中的 中的其他查询(插入),那么您会很安全,因为任何提交该事务的尝试都会导致主键冲突将被数据库拒绝。在这种情况下,您可以简单地重新开始该过程。

  1. 使用sync PECL扩展名

php有一个PECL扩展名,它确实提供了与Java的synchronized关键字相当的功能:

http://php.net/manual/en/threaded.synchronized.php

这允许在您的php代码内部使用锁定机制。但是您需要有一个单一的流程才能工作,因此如何执行此操作取决于http服务器环境中您的工作程序设置。如果您依赖基于线程的php工作模型(所有php请求都在一个进程中处理但有多个线程),那么您就可以开始了。但是,如果您使用多进程工作程序模型(通常使用“ prefork php模块”或“快速cgi容器”完成此操作),则需要实现其他基于单进程的锁管理器(如上述队列管理器) 。因此,您可以在内部使用类似微服务的东西。在我看来,这听起来不值得麻烦:-)