Генерация последовательности Grails для Oracle 11g - PullRequest
5 голосов
/ 01 декабря 2011

Я понимаю, что это скорее спящий вопрос, чем Граальс. В среде с балансировкой нагрузки (2 узла) я вижу, что идентификаторы моих объектов довольно часто меняются. Даже не перезагружая сервер приложений, я вижу, что числа пропускают 10, иногда 20 номеров. Я подозреваю, что сессия hibernate кэширует блок значений последовательности. Есть ли способ контролировать это поведение с помощью grails 1.3.7? По сути, я в порядке, когда сервер извлекает nextval из БД каждый раз, когда он ему нужен.

Объявление последовательности моего объекта домена (то же самое для 2 объектов):

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

Ответы [ 2 ]

3 голосов
/ 01 декабря 2011

С тех пор я зашел в базу данных и изменил последовательность с помощью следующего DDL:

ALTER SEQUENCE MY_SEQ NOCACHE;

Я думаю, что это лучшее решение для этой проблемы.Кто-нибудь видит потенциальные проблемы с этим подходом?

Спасибо всем!

3 голосов
/ 01 декабря 2011

Проблема кеширования заключается в том, что Hibernate по умолчанию использует диалект Oracle, который выполняет две функции.Он создает последовательность, общую для всех таблиц, для генерации первичного ключа, и последовательность кэширует по 20 чисел за раз, которые, если они не используются в течение определенного периода времени, Oracle отбросит остаток.

Следующее решение Oracleвзято из поста Берта Беквита с твиком по предотвращению кэширования чисел в последовательности Oracle.Таким образом, этот диалект сделает для вас две вещи:

  • Он создаст одну последовательность для каждой таблицы, поэтому последовательность не будет общей, а номера первичных ключей не распределены по таблицам.
  • Это отключит кеширование чисел в Oracle, поэтому вы не потеряете порядковые номера в просроченном кеше.Это задается в свойстве PARAMETERS с помощью команды NOCACHE.

Поскольку вы определяете последовательность своей таблицы в отображении, вы, вероятно, можете удалить последовательность для каждой логики таблицы и оставить вNOCACHE определение последовательности для достижения желаемых результатов.

Кроме того, вам нужно будет удалить последовательность из существующего табличного пространства, поскольку Grails не создаст ее заново, за исключением create и create-dropсценарии.При этом вам также может понадобиться увеличить начальное значение новой последовательности, чтобы предотвратить конфликтующие проблемы первичных ключей с ключами, уже используемыми базой данных.

Чтобы использовать диалект, добавьте dialect = SequencePerTableOracleDialect к вашему DataSource.groovy файл в закрытии определения источника данных.

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

Эта ссылка имеет некоторую историю по этому вопросу со ссылкой на оригинальный код Берта и ответом для PostGreSql: Hibernate & postgreSQL с Grails

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...