在我们的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
的组合防止了另一个连接的干扰。
您可以对新票据记录进行三阶段插入:
- 使用auto_increment为其id(主键(创建一个新记录
- 读回记录以获取其id。有了这个id,你就可以计算你的账单号码了
- 使用票据编号更新记录
但请记住,始终对账单编号列设置唯一约束!
如果这不是一个选项,你必须开发自己的序列生成器,以拥有唯一的数字。从上的mySql 5,您可以在数据库中将其实现为存储过程/函数。
这里的许多建议都很到位。
AUTO_INCREMENT
起作用。然而,如果你计划将其用于面向公众的数据,我建议你不要使用它,因为猜测下一个账单号码很简单;只需将票据编号增加1。潜在的安全问题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和列为空";部分