Автор оригинала: Petre Popescu.
При создании структуры базы данных важно убедиться, что каждая строка в таблице имеет уникальный идентификатор, чтобы ее можно было легко индексировать, извлекать и манипулировать ею при необходимости. Наиболее распространенными методами являются использование автоматически увеличивающегося столбца или сгенерированного UUID.
Я не буду описывать метод автоматического увеличения, так как он не создает реальных проблем и может быть сопоставлен целому числу в классе домена Java. При использовании UUID это может создать некоторые проблемы, в зависимости от конфигурации и версии MySQL. Хорошей новостью является то, что существует простой способ сопоставления столбца Java UUID с MySQL с помощью Hibernate, и никаких дополнительных библиотек не требуется.
Во-первых, давайте посмотрим на таблицу образцов. Я буду использовать упрощенную версию таблицы ПОЛЬЗОВАТЕЛЕЙ, в которой хранится информация для входа каждого зарегистрированного пользователя на сайт. Нам понадобится следующая информация:
- ИДЕНТИФИКАТОР
- Электронная почта
- Имя
- Хэш Пароля
Это упрощенная структура с минимальным количеством столбцов. Хранение несоленого хэша пароля не рекомендуется. Ознакомьтесь с рекомендациями по хранению паролей в базе данных при создании окончательной структуры.
Мы хотим, чтобы идентификатор был уникальным, поэтому мы будем использовать UUID Java в нашем объекте домена. Поскольку мы хотим, чтобы вся информация также была удобочитаемой для человека, идентификатор должен храниться в виде строки. Поскольку мы знаем формат UUID, когда он представлен в виде строки, мы знаем, что он имеет длину 36 символов, поэтому мы можем определить столбец как VARCHAR(36).
Теперь мы создаем наш доменный класс, используя аннотации Hibernate, чтобы сопоставить его с нашей существующей таблицей MySQL.
@Entity @Table(name = "users") public class UserDO { @Id @GeneratedValue(generator = "uuid2") @GenericGenerator(name = "uuid2", strategy = "uuid2") @Column(name = "id", updatable = false, nullable = false, columnDefinition = "VARCHAR(36)") private UUID id; @Column private String username; @Column private String email; @Column(name = "password_hash") private String passwordHash; }
Мы ожидаем, что все работает так, как задумывалось, и что Hibernate знает, как сопоставить UUID со столбцом VARCHAR(36), но это верно только частично. При выполнении кода и попытке выполнить вставку, java.sql. Будет создано исключение SQLException:
java.sql.SQLException: Incorrect string value: '\xE3\xAF\xF7d\x0CG…' for column 'id' at row 1 at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129) at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97) at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953) at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1092) at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1040) at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1347) at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1025) at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61) at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java) at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
Это связано с тем, что Hibernate пытается вставить его в виде двоичных данных вместо строки. На данный момент есть два варианта. Во-первых, мы можем изменить столбец идентификатора в базе данных на ДВОИЧНЫЙ тип. Это решит проблему, и вставка нового пользователя будет успешной. Однако при этом идентификатор больше не читается человеком, и в будущем может быть трудно отлаживать, анализировать журналы или вручную манипулировать записями.
Мы хотим, чтобы столбец String UUID использовался в режиме гибернации без необходимости каких-либо дальнейших манипуляций в коде. Вот где вступает в действие новая аннотация: @Type
@Entity @Table(name = "users") public class UserDO { @Id @GeneratedValue(generator = "uuid2") @GenericGenerator(name = "uuid2", strategy = "uuid2") @Column(name = "id", updatable = false, nullable = false, columnDefinition = "VARCHAR(36)") @Type(type = "uuid-char") private UUID id; @Column private String username; @Column private String email; @Column(name = "password_hash") private String passwordHash; }
Эта аннотация определяет сопоставление типов гибернации. Использование “uuid-char” предписывает Hibernate хранить UUID в виде строки, а не двоичного значения. Таким образом, он может быть записан и прочитан из столбца VARCHAR(36) без необходимости какой-либо предварительной обработки с нашей стороны.
Статья, первоначально опубликованная на моем личном веб-сайте по адресу Как использовать строковые идентификаторы UUID в режиме гибернации
Оригинал: “https://www.codementor.io/@petrepopescu/how-to-use-string-uuid-in-hibernate-with-mysql-1jrhjh6ef5”