Рубрики
Без рубрики

Как заменить генератор идентификаторов ТАБЛИЦ на ПОСЛЕДОВАТЕЛЬНОСТЬ или ИДЕНТИФИКАТОР переносимым способом

Автор оригинала: Vlad Mihalcea.

Как объяснялось ранее, генератор идентификаторов ТАБЛИЦ не масштабируется , поэтому вам следует избегать идентификаторов. Однако некоторым корпоративным приложениям может потребоваться запуск как на MySQL (который не поддерживает последовательности баз данных), так и на Oracle, PostgreSQL и SQL Server 2012.

В этой статье будет объяснено, как легко вы можете достичь этой цели, используя переопределение сопоставления JPA.

Последовательности баз данных являются лучшим выбором генератора идентификаторов при использовании JPA и Hibernate. Это связано с тем, что, в отличие от ИДЕНТИФИКАТОРА генератора, вы можете воспользоваться пакетными обновлениями JDBC . Поэтому вы всегда должны использовать последовательность баз данных, если базовая база данных поддерживает эту функцию.

@Entity(name = "Post")
@Table(name = "post")
public class Post {

    @Id
    @GeneratedValue(
        generator = "sequence", 
        strategy = GenerationType.SEQUENCE
    )
    @SequenceGenerator(
        name = "sequence", 
        allocationSize = 10
    )
    private Long id;

    private String title;

    //Getters and setters omitted for brevity sake
}

При сохранении 5 Post сущностей в PostgreSQL:

doInJPA(entityManager -> {
    for (int i = 0; i < 5; i++) {
        Post post = new Post();
        post.setTitle(
            String.format("Post nr %d", i + 1)
        );
        entityManager.persist(post);
    }
});

Hibernate генерирует следующие инструкции SQL:

SELECT nextval ('hibernate_sequence')
SELECT nextval ('hibernate_sequence')

INSERT INTO post (title, id) VALUES ('Post nr 1', 1)
INSERT INTO post (title, id) VALUES ('Post nr 2', 2)
INSERT INTO post (title, id) VALUES ('Post nr 3', 3)
INSERT INTO post (title, id) VALUES ('Post nr 4', 4)
INSERT INTO post (title, id) VALUES ('Post nr 5', 5)

Как вы можете видеть, существует только 2 вызова последовательности, которые определяют минимальную и максимальную границы объединенного оптимизатора .

Для MySQL, поскольку мы не хотим использовать генератор TABLE , мы обязаны использовать стратегию IDENTITY identifier. Однако мы хотим повторно использовать предыдущее сопоставление сущностей, поэтому все, что нам нужно,-это предоставить XML-сопоставление JPA, которое переопределяет сопоставление аннотаций на основе Java:




    com.vladmihalcea.book.hpjp.hibernate.identifier.global
    
        
            
                
            
        
    

Все это возможно, потому что спецификация JPA определяет следующее поведение:

Метаданные XML могут использоваться в качестве альтернативы этим аннотациям, а также для переопределения или дополнения аннотации

— Спецификация JPA 2.1, 11.1 Аннотации для объектно-реляционного отображения

Теперь, поскольку я загружаю JPA без persistence.xml файл , мой PersistenceUnitInfo выглядит так:

PersistenceUnitInfoImpl persistenceUnitInfo = 
    new PersistenceUnitInfoImpl(
        name, entityClassNames(), properties()
);

String[] resources = resources();
if (resources != null) {
    persistenceUnitInfo
        .getMappingFileNames()
        .addAll(Arrays.asList(resources));
}

Итак, для MySQL сопоставление на основе Java выполняется следующим образом:

@Override
protected Class[] entities() {
    return new Class[] {
        Post.class,
    };
}

@Override
protected String[] resources() {
    return new String[] {
        "mappings/identifier/global/mysql-orm.xml"
    };
}

Итак, когда я запускаю предыдущий тестовый случай на MySQL, Hibernate генерирует следующие инструкции SQL:

INSERT INTO post (title) VALUES ('Post nr 1')
INSERT INTO post (title) VALUES ('Post nr 2')
INSERT INTO post (title) VALUES ('Post nr 3')
INSERT INTO post (title) VALUES ('Post nr 4')
INSERT INTO post (title) VALUES ('Post nr 5')

Как вы можете видеть, сопоставление XML переопределило сопоставление аннотаций только для атрибута идентификатора. Это здорово, так как мы можем повторно использовать все, что мы определили в аннотациях Java, все еще решая проблему переносимости идентификаторов базы данных.

Скорее всего, вы собираетесь использовать persistence.xml в вашем корпоративном приложении, поэтому конфигурация выглядит следующим образом:



    

        
            org.hibernate.jpa.HibernatePersistenceProvider
        

        
            mappings/identifier/global/mysql-orm.xml
        

        
            com.vladmihalcea.book.hpjp.hibernate.identifier.global.Post
        

    

Вы даже можете использовать файлы сопоставления, расположенные за пределами файла JAR так что среда MySQL просто предоставляет соответствующие orm.xml файл конфигурации в указанном внешнем каталоге конфигурации.

Вот и все!

Тип поколения. AUTO не является хорошим выбором для MySQL, так как из режима гибернации 5 он возвращается к ТАБЛИЦЕ генератору, что плохо сказывается на производительности.

Нет необходимости использовать генератор ТАБЛИЦ идентификаторов. Если переносимость является вашей основной заботой, вы можете просто использовать ПОСЛЕДОВАТЕЛЬНОСТЬ по умолчанию и переопределить это стратегией IDENTITY для MySQL. Просто убедитесь, что среда MySQL поставляется с orm.xml файл конфигурации, который переопределяет сопоставление ПОСЛЕДОВАТЕЛЬНОСТИ идентификаторов.