El problema de almacenamiento en caché se debe a los valores predeterminados de hibernación a un dialecto de Oracle, que hace dos cosas. Crea una secuencia compartida en todas las tablas para la generación de claves primarias y la secuencia almacena en caché 20 números a la vez, que si no se usan dentro de un marco de tiempo específico, Oracle descartará el resto.
La siguiente solución de Oracle proviene de una publicación de Burt Beckwith, con un tweek para evitar que la secuencia de Oracle guarde en caché los números. Por lo tanto, este dialecto hará dos cosas por usted:
- Creará una secuencia única para cada tabla, por lo que la secuencia no se comparte y los números de clave primaria no se dividen en tablas.
- Deshabilitará el almacenamiento en memoria caché de los números en Oracle, por lo que no perderá ningún número de secuencia en un caché caducado. Esto se configura en la propiedad
PARAMETERS
con el comando NOCACHE
.
Desde que está definiendo la secuencia de su mesa en el mapeo que probablemente podría despojar a cabo por la secuencia lógica de la mesa y dejar en la definición NOCACHE
secuencia para lograr los resultados deseados.
Además, deberá eliminar la secuencia de su espacio de tabla existente, ya que Grails no la volverá a crear, excepto en los escenarios create
y create-drop
. Al hacer esto, es posible que también desee aumentar el valor de inicio de la nueva secuencia para evitar problemas de claves primarias conflictivas con las claves que ya utiliza la base de datos.
Para usar el dialecto, agregue dialect = SequencePerTableOracleDialect
a su archivo DataSource.groovy
en el cierre de definición de DataSource.
import java.util.Properties;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.Oracle10gDialect;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.id.SequenceGenerator;
import org.hibernate.type.Type;
public class SequencePerTableOracleDialect extends Oracle10gDialect {
public static final String PARAMETERS = "MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 NOCACHE NOCYCLE";
/**
* Get the native identifier generator class.
*
* @return TableNameSequenceGenerator.
*/
@Override
public Class<?> getNativeIdentifierGeneratorClass() {
return TableNameSequenceGenerator.class;
}
/**
* Creates a sequence per table instead of the default behavior of one
* sequence.
*/
public static class TableNameSequenceGenerator extends SequenceGenerator {
/**
* {@inheritDoc} If the parameters do not contain a
* {@link SequenceGenerator#SEQUENCE} name, we assign one based on the
* table name.
*/
@Override
public void configure(final Type type, final Properties params,
final Dialect dialect) {
if (params.getProperty(SEQUENCE) == null
|| params.getProperty(SEQUENCE).length() == 0) {
/* Sequence per table */
String tableName = params
.getProperty(PersistentIdentifierGenerator.TABLE);
if (tableName != null) {
params.setProperty(SEQUENCE, createSequenceName(tableName));
}
/* Non-Caching Sequence */
params.setProperty(PARAMETERS, SequencePerTableOracleDialect.PARAMETERS);
}
super.configure(type, params, dialect);
}
/**
* Construct a sequence name from a table name.
*
* @param tableName
* the table name
* @return the sequence name
*/
String createSequenceName(final String tableName) {
return "seq_" + tableName;
}
}
}
Este enlace tiene un poco de historia sobre esta cuestión, con un enlace al código original de Burt, y una respuesta para PostgreSQL: Hibernate & postgreSQL with Grails
Esto debería funcionar bien. Creo que Hibernate siempre llamará a MY_SEQ.NEXTVAL independientemente de si la secuencia está en caché o no; el almacenamiento en caché ocurre internamente en Oracle, no en el nivel de Hibernate o JDBC. Tenga en cuenta que si su aplicación depende de no tener espacios en una secuencia de números, entonces el uso de una secuencia de Oracle podría no ser el enfoque correcto. No hay garantía de que no tenga lagunas en las secuencias; es posible que tenga diferentes subprocesos para obtener valores de secuencia o que tenga retrocesos. –