2011-08-24 21 views
17

He configurado hibernate para usar la secuencia de Oracle. La secuencia se crea con caché = 20, incremento = 1.Hibernar con la secuencia de Oracle no lo usa

Todo funciona bien, hibernar entidades persistentes. El valor de identificación es extraño: 50,51 .... 76,201,202 ... 209,1008,1009,5129,5130 ....

Si solicito el valor de secuencia (seleccione hibernate_sequence.nextval de dual) me sale valor como 2,3,4 ....

Si activo hibernate sql debug, hay que llamar de vez en cuando "seleccionar hibernate_sequence.nextval from dual" pero el número asignado por hibernate a ID no se retransmite en la secuencia !

@Id 
@Column(name = "ID", insertable = false, updatable = false) 
@SequenceGenerator(name = "SequenceIdGenerator", sequenceName = "HIBERNATE_SEQUENCE") 
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SequenceIdGenerator") 
private Long id; 

Respuesta

30

Esto es debido a que el SequenceGenerator no es realmente un generador de secuencias. Es una secuencia de generador Hi-Lo. Esto significa que la primera vez que se invoca, obtiene el siguiente valor de la secuencia (6 por ejemplo), luego multiplica este valor por 50 y le da el resultado (300). La próxima vez que se invoca, devuelve 301 (sin ir a la secuencia), y así sucesivamente hasta que llega a 349. Luego pregunta a la secuencia por el siguiente valor y obtiene 7, que se multiplica por 50 nuevamente para darte 350. Mi la descripción del algoritmo podría estar desactivada en uno, pero se entiende la idea.

Si detiene e inicia su aplicación, tendrá vacíos. Pero es más eficiente que un generador de secuencia pura porque solo hace una llamada a la base de datos una vez en 50 generaciones.

Ver http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#mapping-declaration-id-enhanced-optimizers y http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#mapping-declaration-id-generator para más detalles.

+10

No necesita aumentar en 50 cada vez. Eso es solo lo predeterminado. Use @SequenceGenerator (name = "SEQ_ID", sequenceName = "SEQ_ID", allocationSize = 1) Para incrementar en solo uno. allocationSize es la clave. – dseibert

+2

¿Hay alguna forma de no usar esto? Dado que es un gran problema para mí, tengo otros factores desencadenantes que usan esta misma secuencia para esta tabla. Entonces podrían golpear este número en el futuro, ¿verdad? –

+0

Mira el comentario justo arriba del tuyo. Use allocationSize. –

6

Puedo entender que su pregunta es que los valores de la columna ID en la base de datos no son una secuencia natural, pero las brechas por las que está viendo:

Un poco de historia:

  • Cada Cuando llama al select HIBERNATE_SEQUENCE.nextval from DUAL, el valor de la secuencia aumenta.
  • Como el nombre de su secuencia es genérico en lugar de específico para la tabla, si tiene múltiples entidades que usan HIBERNATE_SEQUENCE como generador de identificaciones, los valores de las secuencias se utilizan en todas las entidades.
  • Si alguna otra aplicación usa HIBERNATE_SEQUENCE, también se omite el valor.
  • Como está usando CACHE = 20, Oracle obtendrá los números de secuencia en bloques de 20 y luego usará una memoria caché interna para devolver los números. Esto puede hacer que los números se salten si se pierde la memoria caché (por ejemplo, si la base de datos está cerrada).
  • Si filas se eliminan de la base de datos, el valor de secuencia no cambia

Por ejemplo, considere la situación siguiente:

Tienes dos entidades Entity1 y Entity2 usando hibernate_sequence como el generador de Identificación :

  1. valor hibernate_sequence actual es 100
  2. Un Entity1 se inserta (utiliza hibernate_sequence que devuelve 101)
  3. Un Entity2 se inserta (utiliza hibernate_sequence que devuelve 102)
  4. Un Entity2 se inserta (utiliza hibernate_sequence que devuelve 103)
  5. El Entity2 con ID 103 se elimina
  6. ejecutar manualmente select HIBERNATE_SEQUENCE.nextval from DUAL (devuelve 104)
  7. Un Entity1 se inserta (utiliza hibernate_sequence que devuelve 105) se inserta
  8. Un Entity2 (utiliza hibernate_sequence que devuelve 106)

Así que al final de ella se tendrá:

  • Entity1 con ID (101, 105)
  • Entity2 con ID (102, 106)

lo que explica las diferencias.

EDIT:

Incluso si el @SequenceGenerator eran configuración para utilizar la SequenceGenerator en lugar de la SequenceHiLoGenerator (como se ha señalado por JB Nizet, que creo que es una mejor explicación de las lagunas), las lagunas en los identificadores generados por las secuencias son una ocurrencia común.

1
CREATE SEQUENCE SEQ_SEQUENCENAME INCREMENT BY 1 START WITH 1 MINVALUE 1; 
grant all on SEQ_SEQUENCENAME to public; 

@Id 
@Column(name = "ID", unique = true, nullable = false) 
@SequenceGenerator(name = "SequenceIdGenerator", sequenceName = "SEQ_SEQUENCENAME") 
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SequenceIdGenerator") 
private int Id; 
Cuestiones relacionadas