Автор оригинала: Vlad Mihalcea.
Традиционно и MySQL, и MariaDB полагались на столбцы AUTO_INCREMENT для создания первичного ключа ИДЕНТИФИКАЦИИ. Хотя столбцы идентификаторов очень эффективны при создании значения первичного ключа, когда дело доходит до использования JPA и гибернации, генератор идентификаторов не позволяет нам использовать пакетные вставки JDBC .
Для автоматической регистрации нескольких инструкций INSERT, UPDATE или DELETE в Hibernate требуется отложить выполнение инструкции SQL до тех пор, пока не будет сброшен контекст сохранения. Это очень хорошо работает для идентификатора ПОСЛЕДОВАТЕЛЬНОСТИ, так как идентификатор сущности может быть извлечен до выполнения инструкции INSERT.
Однако для столбцов идентификаторов единственный способ узнать идентификатор сущности-это выполнить инструкцию SQL INSERT. И Hibernate нуждается в идентификаторе сущности при сохранении сущности, потому что в противном случае он не сможет создать ключ, который используется для определения местоположения сущности в текущем контексте сохранения.
Учитывая, что у нас есть следующий Пост
объект:
@Entity(name = "Post") @Table(name = "post") public class Post { @Id @GeneratedValue( strategy = GenerationType.IDENTITY ) private Long id; private String title; //Getters and setters omitted for brevity }
Если мы включим пакетирование JDBC, используя следующее свойство конфигурации:
И сохранятся 3 Должности
организации:
for (int i = 0; i < 3; i++) { Post post = new Post(); post.setTitle( String.format( "High-Performance Java Persistence, Part %d", i + 1 ) ); entityManager.persist(post); }
Hibernate создаст следующие инструкции SQL:
Query:[" insert into post (title) values (?) "], Params:[ (High-Performance Java Persistence, Part 1) ] Query:[" insert into post (title) values (?) "], Params:[ (High-Performance Java Persistence, Part 2) ] Query:[" insert into post (title) values (?) "], Params:[ (High-Performance Java Persistence, Part 3) ]
Таким образом, операторы SQL INSERT не были пакетными и выполнялись один за другим.
Теперь давайте посмотрим, что произойдет, если мы изменим стратегию идентификации на ПОСЛЕДОВАТЕЛЬНОСТЬ
:
@Id @GeneratedValue( strategy = GenerationType.SEQUENCE ) private Long id;
До MariaDB 10.3 использование ПОСЛЕДОВАТЕЛЬНОСТИ
или АВТОМАТИЧЕСКОГО
генератора было бы действительно плохой идеей, потому что вместо этого в режиме гибернации использовался бы генератор ТАБЛИЦЫ
.
Как я объяснил в этой статье , следует избегать генератора ТАБЛИЦ
идентификаторов, поскольку он плохо работает и может привести к проблемам с масштабируемостью.
При повторном запуске предыдущего тестового набора с использованием MariaDB102Dialect
Hibernate генерирует следующие инструкции SQL:
select next_val as id_val from hibernate_sequence for update update hibernate_sequence set next_val= 2 where next_val=1 select next_val as id_val from hibernate_sequence for update update hibernate_sequence set next_val= 3 where next_val=1 select next_val as id_val from hibernate_sequence for update update hibernate_sequence set next_val= 4 where next_val=2 Query:[" insert into post (title, id) values (?, ?) "], Params:[ (High-Performance Java Persistence, Part 1, 1), (High-Performance Java Persistence, Part 2, 2), (High-Performance Java Persistence, Part 3, 3) ]
Как вы можете видеть, Hibernate использовал генератор ТАБЛИЦЫ
, а таблица hibernate_sequence
базы данных используется в качестве генератора последовательности идентификаторов.
Даже если на этот раз использовались пакетные вставки JDBC, для генерации идентификатора требуются блокировки на уровне строк, выполняемые в hibernate_sequence
, а также отдельное подключение к базе данных, чтобы гарантировать, что операция генерации идентификатора выполняется до того, как будут вставлены сущности.
К счастью, MariaDB 10.3 добавляет поддержку последовательностей баз данных , поэтому, если мы изменим диалект гибернации на MariaDB103Dialect
и повторим наш тестовый случай, мы получим следующие инструкции SQL:
select nextval(hibernate_sequence) select nextval(hibernate_sequence) select nextval(hibernate_sequence) Query:[" insert into post (title, id) values (?, ?) "], Params:[ (High-Performance Java Persistence, Part 1, 1), (High-Performance Java Persistence, Part 2, 2), (High-Performance Java Persistence, Part 3, 3) ]
На этот раз мы не только извлекаем выгоду из пакетных вставок JDBC, но и можем использовать последовательность баз данных для создания идентификаторов таблиц. Однако, в отличие от генератора ТАБЛИЦЫ
, последовательности баз данных очень быстры и также не являются транзакционными, а это означает, что нет необходимости в отдельном подключении к базе данных.
Более того, генератор AUTO
вернется к ПОСЛЕДОВАТЕЛЬНОСТИ
из MariaDB 10.3, поэтому AUTO
больше не является плохим выбором для MariaDB 10.3 , как и для MySQL .
Круто, правда?
Если вы используете MariaDB с JPA и Hibernate, обновление до 10.3 будет действительно полезным. С нетерпением ждем, когда MySQL добавит поддержку последовательностей баз данных в будущем.