请确保count(*)select不会为两个调用方返回相同的值



在我们的web应用程序(Java/JDBC(中,我们使用MySQL,我们需要它来存储个人付款账单。每张票据必须有一个唯一的票据编号。目前,在存储新票据时,通过以下SELECT语句计算新票据的票据编号:

SELECT COUNT(*) FROM bills;

我的问题是:我们如何确保没有两张账单的账单编号相同?

AUTO_INCREMENT是;右";实现目标的方法。

如果一行被删除,COUNT(*)将不起作用!

这里有一种方法可以让你的尝试奏效:

START TRANSACTION;
SELECT MAX(bill_num)+1 FROM Bills  FOR UPDATE;
...
INSERT ... INTO Bills;
COMMIT;

使用事务和FOR UPDATE的组合防止了另一个连接的干扰。

您可以对新票据记录进行三阶段插入:

  1. 使用auto_increment为其id(主键(创建一个新记录
  2. 读回记录以获取其id。有了这个id,你就可以计算你的账单号码了
  3. 使用票据编号更新记录

但请记住,始终对账单编号列设置唯一约束!

如果这不是一个选项,你必须开发自己的序列生成器,以拥有唯一的数字。从上的mySql 5,您可以在数据库中将其实现为存储过程/函数。

这里的许多建议都很到位。

  1. AUTO_INCREMENT起作用。然而,如果你计划将其用于面向公众的数据,我建议你不要使用它,因为猜测下一个账单号码很简单;只需将票据编号增加1。潜在的安全问题
  2. COUNT(*)不起作用。当你有很多记录时,性能会受到影响,如果有删除,那么COUNT(*)实际上可能会倒退,你会得到相同的账单编号

在不知道账单号码要求的情况下,我会选择p.Salmon推荐的UUID路线。这样,不仅没有人能猜到下一个账单号码,而且也很容易做到。插入账单表将类似于:

INSERT INTO bills VALUES (UUID(), ...)

或者,如果你有AUTO_INCREMENT字段,你可能想做一些类似的事情

START TRANSACTION;
INSERT INTO bills VALUES (NULL, UUID(), ...);
SELECT LAST_INSERT_ID(); -- To get the last inserted id
COMMIT;

如果UUID字符串对您不起作用,您可能需要使用其他方案,例如附加客户的号码和/或生成类似于信用卡/礼品卡生成号码的编号方案。

如果账单号码不是敏感信息,那么最简单的方法就是使用AUTO_INCREMENT作为您的账单号码。

如果您想在不使用Auto Increment等的情况下为Bill创建唯一的数字,一种方法是使用Java函数System.currentTimeMillis((将时间戳转换为Bill id,它将始终是唯一和安全的,除非您的账单以超过每毫秒一张的速度生成;(

SELECT COUNT(*(可以计算出两张票据的相同票据号,如果不想计算,可以在票据号上设置唯一索引

COUNT(arg(本身是一个MySQL函数。如果括号中的参数(列或整行(不为NULL,则计算COUNT++,否则不计算该行。有关详细信息,请访问";Evaluate_join_record和列为空";部分

最新更新