Использование разных типов пользователей Hibernate в разных ситуациях

Я использую Hibernate + JPA в качестве решения ORM.

Я использую HSQL для модульного тестирования и PostgreSQL в качестве реальной базы данных.

Я хочу иметь возможность использовать собственный тип Postgres UUID с Hibernate и используйте UUID в его строковом представлении с HSQL для модульного тестирования (поскольку HSQL не имеет типа UUID).

Я использую сохраняемый XML с различными конфигурациями для модульного тестирования Postgres и HSQL.

Вот как Hibernate «видит» мой пользовательский тип пользователя:

@Id
@Column(name="UUID", length=36)
@org.hibernate.annotations.Type(type="com.xxx.UUIDStringType")
public UUID getUUID() {
    return uuid;
}


public void setUUID(UUID uuid) {
    this.uuid = uuid;
}

и это прекрасно работает. Но что мне нужно, так это возможность заменить часть аннотации "com.xxx.UUIDStringType" в XML или из файла свойств, который можно изменить без повторной компиляции.

Любые идеи?


person mainstringargs    schedule 17.06.2009    source источник


Ответы (4)


Этот вопрос действительно старый, и на него уже давно дан ответ, но недавно я оказался в такой же ситуации и нашел хорошее решение. Для начала я обнаружил, что Hibernate имеет три разных встроенных реализации типа UUID:

  1. binary-uuid: сохраняет UUID как двоичный файл
  2. uuid-char: сохраняет UUID как последовательность символов
  3. pg-uuid : использует собственный тип UUID Postgres.

Эти типы зарегистрированы по умолчанию и могут быть указаны для данного поля с аннотацией @Type, например.

@Column
@Type(type = "pg-uuid")
private UUID myUuidField;

Существует также механизм переопределения типов по умолчанию в файле Dialect. Поэтому, если окончательное развертывание должно обращаться к базе данных Postgres, но модульные тесты используют HSQL, вы можете переопределить тип pg-uuid для чтения/записи символьных данных, написав собственный диалект следующим образом:

public class CustomHSQLDialect extends HSQLDialect {

    public CustomHSQLDialect() {
        super();

        // overrides the default implementation of "pg-uuid" to replace it
        // with varchar-based storage.
        addTypeOverride(new UUIDCharType() {
            @Override
            public String getName() {
                return "pg-uuid";
            }
        });
    }
}

Теперь просто подключите пользовательский диалект, и тип pg-uuid будет доступен в обеих средах.

person stevevls    schedule 02.07.2014
comment
Я не вижу, чтобы addTypeOverride вызывали в этом классе. Я использую Hibernate 5. - person visola; 16.08.2018

Привет, для тех, кто ищет решение в Hibernate 4 (поскольку метод Dialect#addTypeOverride больше недоступен), я нашел его, лежащий в основе этот комментарий Стива Эберсоула

Вы должны создать собственный тип пользователя, подобный этому:

public class UUIDStringCustomType extends AbstractSingleColumnStandardBasicType {

    public UUIDStringCustomType() {
        super(VarcharTypeDescriptor.INSTANCE, UUIDTypeDescriptor.INSTANCE);
    }

    @Override
    public String getName() {
        return "pg-uuid";
    }

}

И чтобы связать его с диалектом HSQLDB, вы должны создать собственный диалект, который переопределяет метод Dialect#contributeTypes следующим образом:

public class CustomHsqlDialect extends HSQLDialect {


    @Override
    public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
        super.contributeTypes(typeContributions,serviceRegistry);
        typeContributions.contributeType(new UUIDStringCustomType());
    }

}

Затем вы можете использовать @Type(type="pg-uuid") с двумя базами данных.

Надеюсь кому-нибудь поможет...

person Philippe    schedule 21.07.2015
comment
Как вы связываете HSQLDialect с JPA? - person delucasvb; 26.04.2016
comment
Вы должны определить в файле конфигурации hibernate (или любой другой реализации) свойство: hibernate.dialect . Здесь вы указываете свой новый диалект CustomHsqlDialect с его путем к классам. Надеюсь, вам все еще интересно... - person Philippe; 05.05.2016
comment
spring.jpa.properties.hibernate.dialect = com.yourpackage.etc.CustomHsqlDialect - person Timothy Mugayi; 08.10.2018

Чтобы избежать проблем между типами UUID без указания аннотации @Type (что в основном означает, что вы должны настроить все аннотации, когда хотите перейти с postgres на mysql или наоборот...), я использую package-info.java с гибернациями @TypeDef аннотация на этом пакете.

Вот пример настройки вашего приложения:
Предположим, что module/src/main/java/app.package.domain содержит ваши сущности. И ваши тесты хранятся в module/src/test/java/app.package.

Просто создайте два package-info.java в ваших domain пакетах.

Убедитесь, что файлы package-info всегда находятся в одном и том же пакете (для тестирования и производства). См. следующий пример ниже:

src/main/java
  app
    package
      domain
        package-info.java 

src/test/java
  app
    package
      domain
        package-info.java 

Содержимое вашей продукции package-info.java должно выглядеть так (Postgres):

@TypeDef(
  name = "pg-uuid",
  defaultForType = UUID.class,
  typeClass = PostgresUUIDType.class
)
package app.package.domain;

import org.hibernate.annotations.TypeDef;
import org.hibernate.type.PostgresUUIDType;

import java.util.UUID;

И вот как должна выглядеть ваша тестовая «конфигурация» (H2):

@TypeDef(
  name = "uuid-char",
  defaultForType = UUID.class,
  typeClass = UUIDCharType.class
)
package app.package.domain;

import org.hibernate.annotations.TypeDef;
import org.hibernate.type.UUIDCharType;

import java.util.UUID;

Надеюсь, поможет

person Tim    schedule 27.11.2016
comment
У меня были трудности с этим, я думаю, из-за того, как eclipse использует путь к классам. Но я смог заставить его работать, поместив мою «производственную» информацию о пакете в пространство имен более высокого уровня и поместив мою «тестовую» информацию о пакете в пространство имен более низкого уровня. - person Jeremy; 15.10.2020

Возможно, вы можете добавить в свой тип пользователя некоторые способности, чтобы делать правильные вещи в зависимости от возможностей базы данных. Сам Hibernate использует аналогичный подход со своим «родным» генератором идентификаторов, который ведет себя по-разному в зависимости от типа используемой базы данных. Подобный подход устраняет необходимость переключения отображения во время выполнения.

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

person Rob H    schedule 17.06.2009
comment
Спасибо, чувак.. ты спасаешь жизнь. Паттерн стратегии работал как по маслу. - person mainstringargs; 17.06.2009