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

Как использовать автоматически сгенерированный идентификатор UUID JVM или базы данных с JPA и гибернацией

Узнайте, как использовать автоматически сгенерированный идентификатор сущности UUID с помощью JPA и гибернации. UUID может быть сгенерирован либо в JVM, либо в базе данных.

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

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

Наш Пост объект выглядит следующим образом:

Объект Post имеет идентификатор UUID и заголовок. Теперь давайте посмотрим, как мы можем отобразить Опубликуйте сущность, чтобы идентификатор UUID был автоматически сгенерирован для нас.

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

Однако мало кто может знать, что Тип поколения. AUTO также может использоваться для идентификаторов UUID:

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

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private UUID id;

    private String title;

    //Getters and setters omitted for brevity
}

Теперь, когда сохраняется Сообщение сущность:

Post post = new Post();
post.setTitle("High-Performance Java Persistence");

entityManager.persist(post);

Hibernate создает следующую инструкцию SQL INSERT:

INSERT INTO post (
    title, 
    id
) 
VALUES (
    'High-Performance Java Persistence', 
    'b5607d38-8fc1-43ef-b44e-34967083c80a'
)

Даже дозирование работает так, как ожидалось:

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

Спящий режим, генерирующий одну инструкцию SQL INSERT с 3 наборами значений параметров привязки:

Query:[
    "insert into post (title, id) values (?, ?)"
], 
Params:[
    (High-Performance Java Persistence, Part 1, 7176589b-a3ca-472f-bf00-c253c351ddcc), 
    (High-Performance Java Persistence, Part 2, a4269fb4-07c9-447a-9d65-f443c074de20), 
    (High-Performance Java Persistence, Part 3, e33962a0-d841-48b1-8f43-caf98116f3ee)
]

Теперь, если мы не хотим, чтобы UUID создавался JVM, и хотим использовать функции, зависящие от базы данных, нам нужно предоставить реализацию org.hibernate.id. uuidgenerationстратегия интерфейс:

public class PostgreSQLUUIDGenerationStrategy 
    implements UUIDGenerationStrategy {

    @Override
    public int getGeneratedVersion() {
        return 4;
    }

    @Override
    public UUID generateUUID(
            SharedSessionContractImplementor session) {
        return ((Session) session).doReturningWork(connection -> {
            try(
                Statement statement = connection.createStatement();
                ResultSet resultSet = statement.executeQuery(
                    "select uuid_generate_v4()" 
                )
            ) {
                while (resultSet.next()) {
                    return (UUID) resultSet.getObject(1);
                }
            }
            throw new IllegalArgumentException("Can't fetch a new UUID");
        });
    }
}

Метод getGeneratedVersion определяет, какой тип UUID мы генерируем, в соответствии со стандартом IETF RFC 4122. В нашем случае, 4 расшифровывается как вариант 4 (случайная) стратегия генератора.

Поскольку мы используем PostgreSQL, нам также необходимо создать расширение uuid-ossp перед использованием функций, специфичных для UUID:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

Теперь мы можем вызвать функцию uuid_generate_v4 , чтобы получить UUID варианта 4 на основе спецификации IETF RFC 4122.

Чтобы предоставить PostgreSQL Стратегию генерации UUID для нашей Post сущности, мы должны использовать специфичный для гибернации @GenericGenerator :

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

    @Id
    @GeneratedValue(
        strategy = GenerationType.AUTO, 
        generator = "pg-uuid"
    )
    @GenericGenerator(
        name = "pg-uuid", 
        strategy = "uuid2",
        parameters = @Parameter(
            name = "uuid_gen_strategy_class",
            value = "com.vladmihalcea.book.hpjp.hibernate.identifier.uuid.PostgreSQLUUIDGenerationStrategy"
        )
    )
    private UUID id;

    private String title;

    //Getters and setters omitted for brevity
}

Стратегия uuid2 означает org.hibernate.id. Генератор UUID который мы хотим использовать вместо устаревшего org.hibernate.id. UUIDHexGenerator это зарегистрировано под именем uuid в режиме гибернации.

Атрибут @Parameter используется для настройки UUIDgenerationstrategy с помощью uuid_gen_strategy_class значение параметра, которое принимает полное имя класса org.hibernate.id. Uuidgenerationстратегия реализация интерфейса.

И, вот оно что!

Теперь при сохранении 3 Post сущностей Hibernate генерирует следующие инструкции SQL:

select uuid_generate_v4()
select uuid_generate_v4()
select uuid_generate_v4()

Query:[
    "insert into post (title, id) values (?, ?)"
], 
Params:[
    (High-Performance Java Persistence, Part 1, 9eb52a9b-fb81-4930-b0cd-079a447ed2ba), 
    (High-Performance Java Persistence, Part 2, 2a69ec7d-a147-4c71-8a20-9ba760de0149), 
    (High-Performance Java Persistence, Part 3, e7616832-bb4e-470a-8df4-0534ab56d960)
]

Обратите внимание на вызовы функции uuid_generate_v4 PostgreSQL, которая используется для присвоения значений идентификаторов UUID.

Поэтому автоматическое создание идентификатора UUID при использовании Hibernate довольно просто.

Вы можете либо разрешить Hibernate использовать стратегию генерации UUID на основе Java, либо делегировать эту задачу базе данных. Последний вариант требует обеспечения реализации org.hibernate.id. Uuidgenerationстратегия , которая довольно проста.