我正在创建票务系统。我希望每个条目在指定范围内都是唯一的数字。我已经创建了函数,其中将包括这些函数以演示如何处理事物。如果我一次性购买所有门票,该功能通常会有3或4个重复号码。
我尝试过此操作,但如果有人一次购买所有门票,最终失败,并得到一些重复。我认为,如果一次也购买几个,可能会发生这种情况。这需要更强大。
已购买票证,该票证返回已获取的一组数字
function takenNumbers($drawID){
$connect = new mysqli("localhost", "root", "", "dream");
$stmt = $connect->prepare("SELECT * FROM transaction WHERE DrawID = ?");
$stmt->bind_param("i", $drawID);
$stmt->execute();
$result = $stmt->get_result();
$tickets = array();
while($row = $result->fetch_assoc()){
$id = $row['ID'];
$tickets[] = $row['TicketNumber'];
}
return $tickets;
}
未获取的数字也会在数组中返回
function freeNumbers($drawID){
$minTickets = 1;
$maxTickets = totalTickets($drawID);
$takenNumbers = takenNumbers($drawID);
$freeNumbers = array();
$allTickets = range(1, $maxTickets);
$freeNumbers = array_values(array_diff($allTickets, $takenNumbers));
return $freeNumbers;
}
然后我有一个基于这些功能的随机票证生成器
function randomTicket($drawID){
$num = freeNumbers($drawID);
$random = array_rand($num, 1);
return $random;
}
付款处理后,我调用此函数与randomTicket一起插入数据库。
for($i = 0; $i < $quantity; $i++){
echo paymentMade($paymentId, $token, $payerID, $drawID) . "<br>";
}
我收到重复的邮件。这在实时应用程序中不会发生。我尝试了很多事情,发现这是一个很容易编程的问题。任何和所有输入将不胜感激。预先感谢大家。
答案 0 :(得分:1)
您的数据库是这里的真理源,它是所有可能的票证编号和已分配的票证的存储库。
当您尝试在Web应用程序中执行此操作时,在有多个并发用户的情况下,总是存在冲突的可能性,而当您的应用程序分布在多个服务器上时,则更可能发生冲突。
也就是说,最好找到一种数据库解决方案来发行这些票证。
首先要实现的是在交易表上记录票证号码的UNIQUE INDEX
,然后数据库将始终保持号码的完整性:
您尚未提供完整的架构,因此我假设您的
transaction
表同时具有DrawID
和TicketNumber
列
CREATE UNIQUE INDEX UX_DrawTicketNumbers
ON transaction (DrawID,TicketNo);
现在,当您插入重复的票证编号时,数据库将使操作失败。一个基本的开始方法是简单地处理故障,并使用当前逻辑继续尝试下一个数字,直到它起作用为止。
您可以使用CTE直接从数据库中查询下一个票证号:
MySQL自版本8(于2016年发布)开始支持
WITH
,如果您使用的是旧版本,则可以在混凝土表或临时表中填充所有可能的票证编号,以代替此{{ 1}}子句
WITH
默认情况下,MYSQL将递归限制为1000,因此您可能需要将当前会话递归限制设置为大于或等于
的数字。SET @DrawID := 1; -- set your drawId here SELECT TotalTickets into @MaxTicketNo FROM Draw WHERE ID = @DrawID; WITH RECURSIVE TicketNumbers (n) AS ( SELECT 1 UNION ALL SELECT n + 1 FROM TicketNumbers WHERE n < @MaxTicketNo ) SELECT n FROM TicketNumbers WHERE n NOT IN (SELECT TicketNo FROM transaction WHERE DrawID = @DrawID) ORDER BY RAND() LIMIT 1;
totalTickets
现在,您可以利用数据库的原子性来获取上述查询的结果,并直接在您的插入语句中使用它,在使用CTE的SQL Server中,我将为事务更新做类似的事情:(我可以使其无法在DB Fiddle中使用,但该概念应该可以使用)
SET SESSION cte_max_recursion_depth = 1000000;
为确保原子性,请找到一种方法将此过程移至数据库,创建存储过程以封装分配票证号并将其与付款确认过程合并的过程。