[Grails] Ещё пару GORM gotchas


Короткая заметка-черновик где хочу зафиксировать некоторые подводные камни с ипользованием GORM. Чуть позже докидаю примеров кода.
Это продолжение заметок:

И напоследок, обязательно изучите руководство по GORM’у чтобы не плодить проблем. Именно запросы в БД чаще всего являются узким местом в вашем приложении из-за которого проседает производтельность.
К сожалению в GORM очень много ловушек многих из которых избежать вам помогут три статьи евангелиста Grails Питера Ледбрука (Peter Ledbrook):

  1. GORM GOTCHAS (PART 1) Перевод на русский
  2. GORM GOTCHAS (PART 2) Перевод на русский
  3. GORM GOTCHAS (PART 3) (перевода на русский нет)

Advanced GORM — Performance, Customization and Monitoring

Implementing Burt Beckwith’s GORM Performance – No Collections

1. Всегда указывайте максимальный размер строковых полей

Если вы явно не указали максимальный размер строкового поля то GORM создаст таблицу с полем VARCHAR(255):

class Book {
  String title
}

grails schema-export:

create table book (
  id bigint generated by default as identity, 
  version bigint not null,
  title varchar(255) not null,
  primary key (id)
);

Наверное каждая база данных поддерживает VARCHAR до 255 символов, как этого требует стандарт ANSI SQL.
Проблема возникает при валидации объекта: поскольку максимальный размер поля не указан, то Grails его и не валидирует, пропуская объект дальше пока он не вызовет исключение при сохранении в БД. И то, я не проверял, но например MySQL может молча обрезать значение поля если не включен строгий режим. Хотя может на уровне Hibernate это и не допустится, я не в курсе.
Поэтому указывайте явно максимальный размер поля в секции constraints:

class Book {
    String title
    static constraints = {
        title maxSize: 255
    }
}

Кстати если вам требуется больше 255 символов, то вам следует использовать мапинг на текстовый блоб (CLOB):

class Book {
    String title
    static mapping = {
        title type: 'text'
    }
}

Правда вы теряете при этом возможность строить индексы по этому полю.
Но и в этом случае нужно указывать максимальный размер строки для валидации.

Проверка уникальности происходит только при сохранении

Ещё одна похожая ошибка. Так же как и размер строки, уникальные поля проверяются только момент сохранения, так что вы можете получить исключения уровня БД вместо ошибки на этапе валидации.

Лучше явно прописывайте Long id

Ключевое поле id создаётся динамически, то наверное лучше всё таки прописать его явно

class Book {
    Long id
    String title
}

Во первых, просто так становится меньше неявных мест. Ведь у вас могут быть другие доменные объекты у который ключ составной а поля id нет вовсе.
Это точно придётся сделать если вы захотите использовать это поле в выводе метода toString() или equals. А ведь бывают такие доменные объекты которые можно проверить на равенство только по id.

Лучше явно указывать тип полей hasMany

Тут ситуация схожая с явным id — иногда лучше избегать невного поведения.
По умолчанию поля генерируемые через hasMany имеют тип Set (PersistentSet).
Т.е. вам не гарантируется порядок например и каждый раз при вставке записи будут выгружены все объекты из ассоциации чтобы проверить на уникальность.
Если вы укажите тип в List то хибернейт тоже выгребет все записи, потому что он вынужден будет сохранить порядок. Поэтому самый лёгкий вариант указывать просто как Collection.
Это фича хибернейта как такового.
Так что лучше явно указать тип который вы желаете, чтобы хотя бы знать отчего проседает скорость:

class Book {
    Long id
    String title
    Set<Author> authors
    static hasMany = [authors: Author]
}
Реклама

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s