[Grails] SEQUENCE generator name


Если у доменного объекта не указан способ генерации айдишника тогда Hibernate подбирает его сам. Это называется native стратегия.

Если вы используете не уродскую MySQL, а настоящую базу данных типа PostgreSQL, Oracle или Firebird, то генерация айдишников будет происходить через SEQUENCE.

При генерации БД название для сиквенсов генерируется автоматически и выглядят они примерно так: SYSTEM_SEQUENCE_99A7416D_98E6_485C_8568_1DD6C99BF31C. Т.е. нейминг стратегия мягко говоря неадекватная.
Из-за неё возникает несколько проблем.

Во первых из названия такого сиквенса не понятно для какой именно он таблицы.

Во вторых, я сталкивался с проблемой когда при следующем релизе через database migration накатываются изменения и возникает необходимость сбросить сиквенс, то не ясно по какому имени к нему обращаться.

Как решать?

Переопределить нейминг

Первый вариант создать свой диалект внутри которого прописать правильную генерацию имени сиквенса.
По уму стоило бы всё таки пропатчить эту паскудную генерацию имени сиквенсов в самом хибернейте. Ставлю пивашку тому кто это сделает 🙂

Указать имя сиквенса явно

Для того чтобы обойти эту проблему можно в мапинге домена явно указать имя сиквенса:

class Book {
    String title

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

Теперь для таблицы book будет создан сиквенс book_seq.

Естественно, если вы вдруг решите запустить приложение на БД в которой нет сикенсов то отгребёте ошибку типа такой org.hibernate.MappingException: org.hibernate.dialect.MySQL5InnoDBDialect does not support sequences.

Так что такое решение не годится для использования если вам не известная используемая БД, например в плагинах.

Правильное решение

Я сначала подумал что на этом тупик, но пролистав документацию хибернейта дальше обнаружил что решение уже есть.
Если вкратце, то начиная с версии 3.2.3 в хибернейте появился SequenceStyleGenerator который в отличии от нейтив, позволяет указать опции одновременно и для SEQUENCE генератора и для Table не падает с ошибкой на старте.

class Book {
    String title

    static mapping = {
        id generator: 'org.hibernate.id.enhanced.SequenceStyleGenerator', params: [sequence_name: 'book_seq']
    }
}

В документации сказано что ещё следует включить новые генераторы. Для этого в DataSource.groovy нужно добавить опцию

hibernate.id.new_generator_mappings = true

Но если честно, то всё и без этого заработало 🙂

Теперь в MySql рядом с таблицей book создалась таблица book_seq с одной строкой и одним полем next_val которая имитирует сиквенс.

Оставьте комментарий