2011-11-30 19 views
5

Me doy cuenta de que esto es más una cuestión de hibernación que Grails. En un entorno de carga equilibrada (2 nodos), veo que los identificadores de mis objetos están saltando bastante. Incluso sin reiniciar el servidor de aplicaciones veo que los números saltan 10 veces 20 números. Sospecho que la sesión de hibernación almacena en caché un bloque de valores de secuencia. ¿Hay alguna manera de controlar este comportamiento con Grails 1.3.7? Básicamente, estoy de acuerdo con el servidor que tira nextval de DB cada vez que necesita uno.Generación de secuencia de grises para Oracle 11g

Mi declaración secuencia objeto de dominio (lo mismo para los objetos 2):

static mapping = { 
     id generator:'sequence', params:[sequence:'MY_SEQ'] 
    } 

Respuesta

3

tengo ya fue a la base de datos y modificar la secuencia con la siguiente DDL :

ALTER SEQUENCE MY_SEQ NOCACHE; 

Creo que esta es la mejor solución para este problema. ¿Alguien ve problemas potenciales con este enfoque?

¡Gracias a todos!

+1

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. –

3

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

+0

¡Gracias por eso! ¿Estás diciendo que no hay forma de especificar NOCACHE o allocationSize en params para una secuencia? – dbrin

+0

No sé, ya que eso sería SQL específico de la base de datos, lo que vincularía su aplicación a una marca de base de datos específica. – schmolly159

+0

Lo siento, schmolly. Esa no es la solución que estaba buscando. Lo marcaré ya que puede ser útil para otros. Ver mi solución para una solución alternativa y fácil. ...al menos eso creo :) – dbrin

Cuestiones relacionadas