安全生成每日重置的顺序订单号

时间:2012-08-21 00:20:08

标签: java oracle hibernate

我需要以yyyyMMddxxxxxx的格式生成订单号,其中xxxxxx是自午夜以来的订单数。

20120821000004是2012年8月21日的第四个订单。每秒最多可以创建5个订单,因此这是性能考虑因素。

一个明显的解决方案是执行以下操作以查找要递增的最新订单:

SELECT MAX (id) FROM table_name WHERE id LIKE '2012-08-21%'

但这可能会遇到性能问题。

我探索的另一个选项是创建一个序列,用于驱动数字组件并使用插入触发器。这种方法的问题在于你需要一些安全的方法在一天开始时将序列滚动到零,如果序列没有在午夜重置,则可能导致碰撞/竞争条件。

我可以在这里使用Oracle的一些技巧,使其密不透风,但也具有高性能吗?

5 个答案:

答案 0 :(得分:1)

您可以为每个新的一天生成新的序列。 给他们一个有意义的名字,比如' order_seq_20120821'。

  • 检查今天的序列是否存在
  • 如果没有创建它(在这里处理并发,另一个线程可以创建它)
  • 然后使用它

这里不是一个真正的java问题,客户端无法处理数据库并发

答案 1 :(得分:1)

如果你只是在没有任何外部工具的情况下在SQL中执行此操作,我可能会保留两个表:

  • 绝对订单ID
  • 日期/订单偏移

第一个表将用于生成单调递增的唯一ID值。第二个表将用于跟踪从第一个表到每日ID的每日偏移量。将在当天的第一个订单中插入一行,并且该行将是第一个表中的日期和最高ID。然后可以通过从第一个表中提取的新ID中减去第二个表中的ID偏移量来计算订单ID。

您可以考虑使用整数绝对订单ID在内部跟踪订单,只需使用日期/偏移数据即可生成日期和每日订单编号的人性化信息,或作为交叉引用。

答案 2 :(得分:0)

这不是一个特别的Oracle解决方案,但我想有一个包含三列的订单号表:date,xxxxxx(作为int)和订单号。

保持索引(日期,xxxxxxx)。现在,将查询作为:

select max(id) from OrderNumbers where date = <date>

这将使用索引并加速操作。

另一个想法是保留一个类似的表,但仅限于当前日期。在这个版本中,你将有一个序列/自动增量列自动生成xxxxxx。然后,您可以使用触发器计算订单编号并获取最后插入的值以创建新订单编号。这可能是最快的方法,尤其是当您考虑锁定数据的问题时。

答案 3 :(得分:0)

您可以创建一个以下一个订单ID

开头的序列
CREATE SEQUENCE orders_seq
 START WITH     201208210000001
 INCREMENT BY   1
 NOCACHE
 ;

并通过作业将序列在午夜增加到第一天的第一天ID:

 declare
  v_curr_id NUMBER;
  v_inc     NUMBER;
  v_next_val NUMBER;
 begin 
  select orders_seq.nextval into v_curr_id from dual;
  v_next_val := to_number(to_char(SYSDATE+1, 'yyyymmdd') || '000000');
  v_inc := v_next_val - v_curr_id;
  execute immediate ' alter sequence orders_seq increment by ' || v_inc ;
  select orders_seq.nextval into v_curr_id from dual;
  execute immediate ' alter sequence orders_seq increment by 1';
 end;
 /

答案 4 :(得分:0)

为一周中的每一天创建一个Oracle序列,即

创建序列SEQ_MON
 从1开始  增量1  令;

创建序列SEQ_TUE
 从1开始  增量1  令;

ETC到SEQ_SUN

创建一个返回的Oracle存储过程:
1.日期时间
2.对应于上述日期时间的星期几的序列号

逻辑如下:
- 将当前日期和时间存储在变量中 - 获取与变量中的日期对应的星期几 注意:使用独立于NLS_TERRITORY设置的公式。您可以使用:1 + TRUNC(DT) - TRUNC(DT,'IW')为Mon获得1.
- 从对应于一周上一天的序列中获取下一个序列
- 返回变量中的日期时间和上面获得的新序列号。

安排工作:
创建一个每天凌晨1点(不是午夜)运行的预定作业,以重置前一天的seq。

通过上述方法,您可以安全地进行24X7操作。

重要:
返回的日期时间应用于为传入的请求添加时间戳,以便请求的时间戳与分配给它的序列号相匹配。这对于午夜前的请求非常重要。