我有一个 Spring Boot 应用程序,它通过 REST API 获取请求。
收到这样的请求后,我为我的对象生成了一个 offerID。这不是数据库的主键,它只是我们与客户交流的人类可读数字,而不是普通的数据库 ID。
对于我们在 2016 年 5 月 18 日收到的第一个请求,此优惠 ID 类似于“16051801”。
这在数据库中存储为字符串以选择当前“最大值”,类似 SELECT count(r) FROM Request as r WHERE r.offerId LIKE ?1%
我只是输入当前日期“160518”并获取存储在那里的请求数,然后将计数 + 1 作为下一个值。
您可能已经猜到,这会带来一些问题。
一方面,这工作正常,因为我们现在在这个网站上没有那么多流量。
但是,如果我们有两个请求几乎同时进入,我会得到类似“竞争条件”的东西,并且我创建了相同的 offerId 两次,这不是很酷。
我已经为此列添加了一个唯一约束,它可以防止创建具有相同值的多个条目,但在那种情况下,两个请求之一会失败。
我已经尝试过类似的东西:
try {
super.create(customerRequest);
} catch (DataIntegrityViolationException ex) {
if (ex.getCause() instanceof ConstraintViolationException) {
ConstraintViolationException constraintViolationException = (ConstraintViolationException) ex.getCause();
if (constraintViolationException.getCause().getMessage().contains("'UC_CUSTOMERREQUESTOFFERNUMBER_COL'")){
customerRequest.setOfferNumber(generateOfferNumber(customerRequest));
super.create(customerRequest);
}
}
}
但在那种情况下,我总是得到类似Do not flush the session if an Exception occurs
基本上在那种情况下我能够处理和解决问题,但 Spring/Hibernate 阻止我这样做。
所以真正的问题是,以一种不老套的方式处理这种“问题”的最佳实践是什么(我也尝试过使用 Thread.sleep() 的东西,感觉不太好......)并且还具有可扩展性(将来也应该适用于应用程序的多个实例)。
作为数据库,我们使用 MySQL,据我所知,我们无法将此“ID 生成”移动到数据库中。
最佳答案
MySQL 本身就没有序列的概念。 最接近的是 AUTO_INCREMENT。
对于 MyISAM 表,您需要一种简单的方法。只需将订单的日期保存在表中,并根据日期自动递增。
MYSQL手册是这样说的:
“对于 MyISAM 表,您可以在多列索引的辅助列上指定 AUTO_INCREMENT。在这种情况下,AUTO_INCREMENT 列的生成值计算为 MAX(auto_increment_column) + 1 WHERE prefix=given-prefix。当您想将数据放入有序组时,这很有用”
查看此链接以获取更多信息。 http://dev.mysql.com/doc/refman/5.7/en/example-auto-increment.html
关于java - 如何防止在两个事务中产生重复值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37291446/