2008-09-04 1043 views
6

Tengo una aplicación Java distribuida que se ejecuta en 5 servidores de aplicaciones. Todos los servidores usan la misma base de datos Oracle 9i que se ejecuta en una sexta máquina.Cómo recuperar previamente las ID de secuencia de Oracle en un entorno distribuido

La aplicación necesita recuperar previamente un lote de 100 ID de una secuencia. Es relativamente fácil de hacer en un entorno de un solo subproceso, no distribuido, sólo puede emitir estas consultas:

select seq.nextval from dual; 
alter sequence seq increment by 100; 
select seq.nextval from dual; 

El primero seleccione Obtiene la primera secuencia ID que la aplicación puede utilizar, el segundo select regrese el último uno que se puede usar

Las cosas se ponen mucho más interesantes en un entorno multiproceso. No puede estar seguro de que antes de que el segundo seleccione otro hilo no aumente la secuencia en 100 nuevamente. Este problema se puede resolver sincronizando el acceso en el lado de Java: solo permite que un hilo comience a buscar los ID a la vez.

La situación se vuelve realmente difícil cuando no se puede sincronizar porque partes de la aplicación no se ejecutan en la misma JVM, ni siquiera en la misma máquina física. Encontré algunas referencias en los foros que otros tienen problemas para resolver este problema también, pero ninguna de las respuestas funciona realmente sin mencionar que es razonable.

¿Puede la comunidad proporcionar una solución para este problema?

Algunos más información:

  • Realmente no puedo jugar con los niveles de aislamiento de transacción. Utilizo JPA y el cambio afectaría a toda la aplicación, no solo a las consultas de recuperación previa y eso no es aceptable para mí.
  • En PostgreSQL que podía hacer lo siguiente:

    seleccione setval ('SEC', nextval ('SEC') + n - 1)

  • La solución por Matthew funciona cuando se puede utilizar un fijo valor de incremento (que es perfectamente aceptable en mi caso). Sin embargo, ¿existe una solución cuando no desea corregir el tamaño del incremento, pero desea ajustarlo dinámicamente?

Respuesta

10

¿Por qué no acaba de tener la secuencia como incremento por 100 todo el tiempo? cada "nextval" le da el 100 números de secuencia para trabajar con

SQL> create sequence so_test start with 100 increment by 100 nocache; 

Sequence created. 

SQL> select so_test.nextval - 99 as first_seq, so_test.currval as last_seq from dual; 

FIRST_SEQ LAST_SEQ 
---------- ---------- 
     1  100 

SQL>/

FIRST_SEQ LAST_SEQ 
---------- ---------- 
     101  200 

SQL>/

FIRST_SEQ LAST_SEQ 
---------- ---------- 
     201  300 

SQL> 

una nota en su ejemplo .. Cuidado con los DDL .. Se producirá un COMMIT implícito

Ejemplo de commit producido por DDL

SQL> select * from xx; 

no rows selected 

SQL> insert into xx values ('x'); 

1 row created. 

SQL> alter sequence so_test increment by 100; 

Sequence altered. 

SQL> rollback; 

Rollback complete. 

SQL> select * from xx; 

Y 
----- 
x 

SQL> 
+0

Gran respuesta: o) – Andrew

1

Matthew tiene el enfoque correcto aquí. En mi opinión, es muy raro que una aplicación restablezca el valor actual de una secuencia después de cada uso. Mucho más convencional para establecer el tamaño de incremento a cualquier cosa que necesite por adelantado.

Además, esta forma es mucho más eficiente. Seleccionar nextval de una secuencia es una operación altamente optimizada en Oracle, mientras que ejecutar ddl para alterar la secuencia es mucho más costoso.

supongo que en realidad no contesta el último punto en su pregunta editada ...

3

¿Por qué necesita para obtener los identificadores de secuencia en el primer lugar? En la mayoría de los casos, insertaría en una tabla y devolvería la ID.

insert into t (my_pk, my_data) values (mysequence.nextval, :the_data) 
returning my_pk into :the_pk; 

Parece que está intentando optimizar previamente el procesamiento.

Si REALMENTE necesita recuperar los ID, simplemente llame a la secuencia 100 veces. El punto entero de una secuencia es que maneja la numeración. Se supone que no debes asumir que puedes obtener 100 números consecutivos.

1

Para cuando no desee un incremento de tamaño fijo, las secuencias no son lo que realmente busca, todo lo que realmente garantiza es que obtendrá un número único siempre más grande que el último que obtuvo. Siempre existe la posibilidad de que termine con lagunas, y realmente no puede ajustar la cantidad de incremento sobre la marcha de forma segura o efectiva.

No puedo pensar en ningún caso en el que haya tenido que hacer este tipo de cosas, pero probablemente la forma más fácil sea almacenar el número "actual" en algún lugar y actualizarlo cuando lo necesite.

Algo como esto.

drop table t_so_test; 

create table t_so_test (curr_num number(10)); 

insert into t_so_test values (1); 
create or replace procedure p_get_next_seq (inc IN NUMBER, v_next_seq OUT NUMBER) As 
BEGIN 
    update t_so_test set curr_num = curr_num + inc RETURNING curr_num into v_next_seq; 
END; 
/


SQL> var p number; 
SQL> execute p_get_next_seq(100,:p); 

PL/SQL procedure successfully completed. 

SQL> print p; 

     P 
---------- 
     101 

SQL> execute p_get_next_seq(10,:p);  

PL/SQL procedure successfully completed. 

SQL> print p; 

     P 
---------- 
     111 

SQL> execute p_get_next_seq(1000,:p); 

PL/SQL procedure successfully completed. 

SQL> print p; 

     P 
---------- 
     1111 

SQL> 
Cuestiones relacionadas