Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 每日重置顺序订单号的安全生成_Java_Oracle_Hibernate - Fatal编程技术网

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

Java 每日重置顺序订单号的安全生成,java,oracle,hibernate,Java,Oracle,Hibernate,我需要生成YYYYMMDDXXXXX格式的订单号,其中xxxxxx是自午夜以来的订单数 例如20120821000004是2012年8月21日的第四份订单。每秒最多可以创建5个订单,因此这是一个性能考虑因素 一个显而易见的解决方案是执行以下操作,以查找要增加的最新订单: SELECT MAX (id) FROM table_name WHERE id LIKE '2012-08-21%' 但这可能会遇到性能问题 我探索的另一个选项是创建一个序列,用于驱动数字组件并使用插入触发器。这种方法的问题

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

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

一个显而易见的解决方案是执行以下操作,以查找要增加的最新订单:

SELECT MAX (id) FROM table_name WHERE id LIKE '2012-08-21%'
但这可能会遇到性能问题

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


在这里,我可以使用Oracle的一些技巧使其不透气,但也能发挥性能吗?

这不是一个专门的Oracle解决方案,但我正在考虑使用一个订单号表,该表有三列:日期、xxxxxx(作为整数)和订单号

在(日期xxxxxxx)上保存索引。现在,按照以下步骤执行查询:

select max(id) from OrderNumbers where date = <date>
从日期=
这将使用索引,并应加快操作


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

您可以为每一个新的一天生成新的序列。 给他们一个有意义的名字,比如“order\u seq\u 20120821”

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

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

如果只在SQL中执行此操作,而没有任何外部实用程序,我可能会保留两个表:

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


您可以考虑使用整数绝对订单ID跟踪DB中的订单,并且只使用日期/偏移数据来生成日期和每日订单号的友好信息,或者作为交叉引用。< / P> < P>您可以从下一个订单ID/P>开始创建SEQ。

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;
 /

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

创建序列序号
从1开始
增加1
秩序

创建顺序序列
从1开始
增加1
秩序

ETC至SEQ_SUN

创建返回以下内容的Oracle存储过程:
1.日期时间
2.与上述日期时间相对应的一周中某一天的序列号

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

计划作业:
创建每天凌晨1点(不是午夜)运行的计划作业,以重置前一天的顺序

使用上述方法,您可以安全地进行全天候操作

重要提示:

返回的datetime应用于为传入请求添加时间戳,以便请求的时间戳与分配给它的序列号匹配。这对于午夜前到达的请求很重要。

最大(id)是否将成为同步订单的竞争条件?相反,您可以在
OrderNumbers
表中插入,然后获取最后一次插入的ID(
SCOPE\u IDENTITY
在SQL Server中,不确定它在Oracle中是什么)。这样你就知道你总是有一个唯一的ID。所以你想使用一个唯一的序列吗?可能您可以保存前一天的序列最后一个值。使用此选项可以重新计算id的顺序。但是注释仍然有效:客户端无法处理数据库并发!它必须在数据库端处理。您是否打算生成一个无间隙序列?如果是这样的话,这将强制对订单进行序列化--如果您试图每秒处理5个订单,这可能会有问题。此外,除了序列化带来的性能问题外,不可能有无间隙的序列,因为可能会出现倒退。如果我处在你的位置,我会回去质疑要求。为什么他们需要这种格式的订单号?为什么他们需要无间隙呢?他们需要按顺序订购吗?换句话说,我建议只使用一个简单的序列来生成一个简单的唯一订单ID,并为订单日期设置一个单独的列。严格来说,这些数字不是无间隙的要求。我的工作方式与pizen的方法非常相似,没有无间隙数字。如果作业无法运行会发生什么?作业运行并将序列设置回0后,可能会发生冲突。@anger:我们的想法不是将序列设置回0,而是