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

Как исправить ошибки проверки схемы “обнаружен неправильный тип столбца” с помощью JPA и гибернации

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

Вступление

Сопоставление сущностей с таблицами базы данных обычно является очень простым процессом. Однако, если ваши сопоставления довольно необычны, вы можете столкнуться с некоторыми редкими проблемами, подобными той, которую я нашел на форуме Hibernate .

В этой статье я собираюсь объяснить сопоставление объектов Java с типами столбцов JDBC и базы данных и то, как вы можете устранить проблему, описанную в вышеупомянутом вопросе Hibernate.

Проблема с отображением

Учитывая, что у нас есть следующая схема базы данных SQL Server:

CREATE TABLE event (
    id NUMERIC(19,0) IDENTITY NOT NULL, 
    PRIMARY KEY (id)
)

Это сопоставление схемы довольно необычно, поскольку гораздо чаще для столбца ИДЕНТИФИКАТОРОВ используется тип ЦЕЛОЕ ЧИСЛО или BIGINT . Однако, если вы имеете дело с устаревшей схемой, вам придется иметь дело с ней на стороне Java.

И вы предоставляете следующее сопоставление сущностей:

@Entity(name = "Event")
@Table(name = "event")
public class Event {

    @Id
    @GeneratedValue(
        strategy = GenerationType.IDENTITY
    )
    private Long id;
}

Если вы разрешите Hibernate проверить сопоставление с помощью параметра проверить hbm2ddl:


Hibernate создаст следующее исключение во время начальной загрузки приложения:

Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: 
Schema-validation: wrong column type encountered in column [id] in table [event]; 
found [numeric (Types#NUMERIC)], but expecting [bigint (Types#BIGINT)]

Логика отображения длинных типов в режиме гибернации

Чтобы понять, почему проверка схемы не удалась, вы должны понять, как основные типы обрабатываются Hibernate. Например, java.lang.Длинный тип обрабатывается org.hibernate.type.LongType , диаграмма классов которого выглядит следующим образом:

SqlTypeDescriptor используется для сопоставления типа Java с типом JDBC. Цель этого класса-привязать значение к Подготовленной инструкции при выполнении инструкций INSERT, UPDATE или DELETE и извлечь значение из набора результатов после выполнения инструкции SELECT.

JavaTypeDescriptor используется для обработки сопоставления одного типа Java (например, Long ) с другим (например, Число или Строка ) и используется при преобразовании значения, считанного из SqlTypeDescriptor , в ожидаемый тип Java (например, Long в этом случае).

Тип Long использует следующий SqlTypeDescriptor и JavaTypeDescriptor :

public LongType() {
    super( 
        BigIntTypeDescriptor.INSTANCE, 
        LongTypeDescriptor.INSTANCE 
    );
}

bigintypedescriptor представляет реализацию SqlTypeDescriptor , поэтому он ожидает java.sql.Types.BIGINT на стороне JDBC. Однако в нашем сопоставлении базы данных используется тип ЧИСЛОВОЙ столбец, который обозначается java.sql.Types.ЧИСЛОВОЙ тип JDBC, отсюда и сообщение об ошибке, которое мы получили во время проверки схемы.

Устранение проблемы

Решение действительно простое. Нам просто нужно переопределить тип JDBC по умолчанию Hibernate, используя явное объявление типа:

@Id
@GeneratedValue(
    strategy = GenerationType.IDENTITY
)
@Column(
    columnDefinition = "NUMERIC(19,0)"
)
private Long id;

Теперь Hibernate знает, что следует ожидать ЧИСЛОВОЙ столбец на стороне базы данных, а не BIGINT один.

Вывод

Явные сопоставления, такие как @Таблица или @Столбец , полезны не только при создании схемы базы данных с помощью инструмента hbm2ddl. Для производственной системы управление схемой базы данных с помощью такого инструмента, как Flyway – это путь, по которому нужно идти.

Однако вам необходимо убедиться, что схема сопоставления сущностей JPA синхронизирована с схемой базы данных, и именно в этом заключается стратегия validate hbm2ddl. Хотя сопоставления по умолчанию подходят для большинства случаев использования, иногда требуется предоставить явное объявление типа, например ЧИСЛОВОЙ тип столбца для столбца ИДЕНТИФИКАТОРОВ.