Проблема с проверкой гибернации для типа blob sql

Я получаю следующую ошибку:

Caused by: org.hibernate.HibernateException: Wrong column type in PUBLIC.PUBLIC.ALL_TYPES_ENTITIES for column blob1. Found: varbinary, expected: blob(255)
    at org.hibernate.mapping.Table.validateColumns(Table.java:383)

Я создаю таблицу с помощью liquibase:

        <column name="blob1" type="BLOB">
            <constraints nullable="true"/>
        </column>

Объект Java имеет поле:

private byte[] blob1;
...
@Basic(fetch = FetchType.LAZY)
@Lob
@Column(name = "blob1")
public byte[] getBlob1() {
    return blob1;
}

Я использую hsqldb 2.2.9 в качестве базы данных и Hibernate 3.5.0-Final в качестве поставщика JPA. Диалект Hibernate для hsqldb:

<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>

Когда liquibase создает таблицу, liquibase HsqlTypeConverter должен использовать VARBINARY в качестве типа sql. КОГДА схема проверки Hibernate думает, что это тип blob(255), сравнивает его с VARBINARY и выдает исключение.

Вот код, который проверяет таблицу:

public void validateColumns(Dialect dialect, Mapping mapping, TableMetadata tableInfo) {
    Iterator iter = getColumnIterator();
    while ( iter.hasNext() ) {
        Column col = (Column) iter.next();

        ColumnMetadata columnInfo = tableInfo.getColumnMetadata( col.getName() );

        if ( columnInfo == null ) {
            throw new HibernateException( "Missing column: " + col.getName() + " in " + Table.qualify( tableInfo.getCatalog(), tableInfo.getSchema(), tableInfo.getName()));
        }
        else {
            final boolean typesMatch = col.getSqlType( dialect, mapping ).toLowerCase()
                    .startsWith( columnInfo.getTypeName().toLowerCase() )
                    || columnInfo.getTypeCode() == col.getSqlTypeCode( mapping );
            if ( !typesMatch ) {
                throw new HibernateException(
...

В отладчике я вижу, когда возникает исключение, что col.sqlType = blob(255), columnInfo.typeName = VARBINARY. По какой-то причине, когда col.getSqlType( dialect, mapping ) вызывается для инициализации col.sqlType, он получает blob (255). Я полагаю, что мне следует обновить диалект hsqldb в конфигурации спящего режима. Но не уверен. Не знаю, что мне делать, чтобы решить проблему.


person Alexandr    schedule 03.06.2013    source источник


Ответы (2)


Liquibase не использует тип sql BLOB для больших двоичных объектов, которые стали доступны в hsqldb, начиная с версии 2.0. В hsqldb 1.8.X для больших двоичных объектов использовался тип sql: varbinary. Чтобы решить эту проблему, я обновил диалект hsqldb, используемый в спящем режиме:

public class HSQL_1_8_X_Dialect extends HSQLDialect {

    public HSQL_1_8_X_Dialect() {
        super();

        registerColumnType(Types.BLOB, "varbinary");
        registerColumnType(Types.CLOB, "varchar");
    }
}

<property name="hibernate.dialect" value="com.savdev.datasource.dialect.HSQL_1_8_X_Dialect"/>

Это решило проблему. Кроме того, я полагаю, что liquibase должна либо обновить текущую HsqlTypeConverter, либо добавить новую, которая поддерживает версию hsqldb 2.X.

person Alexandr    schedule 04.06.2013

Вы получаете 255 в своем запросе проверки, потому что это значение по умолчанию для свойства length аннотации @Column.

Поскольку HSQLDB поддерживает как VARBINARY, так и BLOB типы SQL, по-видимому, Hibernate использует BLOB в качестве сопоставления SQL по умолчанию для byte[] столбцов.

Вы можете явно указать Hibernate использовать VARBINARY, указав свойство columnDefinition для @Column:

@Basic(fetch = FetchType.LAZY)
@Lob
@Column(name = "blob1", columnDefinition = "VARBINARY")
public byte[] getBlob1() {
    return blob1;
}

Обратите внимание, что определения столбца могут быть изменены явным указанием его длины, как это описано здесь, но обычно это связано с String столбцами.

person n1ckolas    schedule 03.06.2013
comment
но если я позже изменю hsqldb, например, на сервер ms sql, который поддерживает blob как VARBINARY (MAX), мне придется изменить атрибут столбца. Могу ли я что-нибудь сделать с этой проблемой? Я не думаю, что обновление модели - лучший вариант при смене сервера базы данных. - person Alexandr; 03.06.2013
comment
Дело в том, что вы создаете БД с помощью liquibase, но проверяете с помощью Hibernate. В этом случае нужно либо убедиться, что liquibase создает тип, который ожидает Hibernate, либо наоборот - убедиться, что Hibernates ожидает тип, который создан liquibase. Для создания всего, независимого от платформы БД, я бы позволил Hibernate создавать все таблицы/поля самостоятельно (т.е. hbm2ddl=update). - person n1ckolas; 03.06.2013
comment
тогда, может быть, вы можете сказать мне, как создать таблицу Liquibase, чтобы она была проверена Hibernate? Независимо от платформы БД. как только я устанавливаю columnDefinition, я вообще удаляю независимость от платформы БД. - person Alexandr; 03.06.2013
comment
Я не уверен, но, возможно, вам следует попробовать интеграцию Hibernate для Liquibase. Если не поможет, то наверное можно считать это багом Liquibase-Hibernate. - person n1ckolas; 03.06.2013