Настройте Hibernate на использование Oracle SYS_GUID() в качестве первичного ключа

StackOverflow https://stackoverflow.com/questions/846786

Вопрос

Я ищу способ заставить hibernate использовать oracle SYS_GUID() функция при вставке новых строк.В настоящее время мои таблицы БД имеют SYS_GUID() по умолчанию, поэтому, если hibernate просто сгенерировал SQL, в котором было опущено значение, оно должно работать.

У меня все работает, но в настоящее время он генерирует UUID / GUID в коде с использованием генератора system-uuid:

@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
@Column(name = "PRODUCT_ID", unique = true, nullable = false)
public String getId() {
    return this.productId;
}

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

Я использую аннотации для настройки, но примеры конфигурации xml также являются потрясающими.

Вот пример определения таблицы (на случай, если это имеет значение):

CREATE TABLE SCHEMA_NAME.PRODUCT
(
    PRODUCT_ID RAW(16) DEFAULT SYS_GUID() NOT NULL,
    PRODUCT_CODE VARCHAR2(10 CHAR) NOT NULL,
    PRODUCT_NAME VARCHAR2(30 CHAR) NOT NULL,
    PRODUCT_DESC VARCHAR2(512 CHAR)
)

Обновить:

Решение Mat по использованию "guid" сработало, вот сгенерированный sql:

Hibernate: 
    select rawtohex(sys_guid()) 
    from dual
Hibernate: 
    insert into PRODUCT
    (PRODUCT_CODE, PRODUCT_DESC, LOB_ID, PRODUCT_NAME, PROVIDER_ID, PRODUCT_ID) 
    values (?, ?, ?, ?, ?, ?)

Похоже, что использование значения columns по умолчанию при вставке невозможно, поэтому приходится выбирать между сгенерированным приложением идентификатором guid и обходом базы данных туда и обратно.

Это было полезно?

Решение

Возможно, вы сможете использовать генератор "guid".Видишь этот пост с форума Hibernate.Похоже, что они добавили поддержку Oracle, используя SYS_GUID() некоторое время назад, но Документация все еще говорит, что они поддерживают только SQL Server и MySQL.

Я еще не работал с аннотациями JPA, но вот пример использования конфигурации XML:

<id name="PRODUCT_ID">
  <generator class="guid" />
</id>

Редактировать: Что касается вашего второго вопроса, я думаю, вы спрашиваете, почему Hibernate не может сделать что-то подобное:

INSERT INTO PRODUCT (PRODUCT_ID, /* etc */)
SELECT SYSGUID(), /* etc */

Причина в том, что Hibernate должен знать, каков идентификатор объекта.Например, рассмотрим следующий сценарий:

  1. Вы создаете новый объект Product и сохраняете его.Oracle присваивает идентификатор.
  2. Вы отсоединяете Продукт от сеанса Гибернации.
  3. Позже вы снова прикрепите его и внесете некоторые изменения.
  4. Теперь вы хотите сохранить эти изменения.

Не зная идентификатора, Hibernate не может этого сделать.Ему нужен идентификатор для того, чтобы выдать инструкцию UPDATE.Таким образом, реализация org.hibernate.id.GUIDGenerator должен заранее сгенерировать идентификатор, а затем позже повторно использовать его в инструкции INSERT.

Это та же самая причина, по которой Hibernate не может сделать любая дозировка если вы используете идентификатор, сгенерированный базой данных (включая автоматическое увеличение в базах данных, которые его поддерживают).Использование одного из генераторов hilo или какого-либо другого механизма идентификации, генерируемого в режиме гибернации, - это единственный способ получить хорошую производительность при одновременной вставке большого количества объектов.

Другие советы

У меня та же задача, что и в начале темы.С благодарностью к @Мэтт Солнит предложение Я использую такие аннотации:

@Id
@NotNull
@Column(name = "UUID")
@GenericGenerator(name = "db-uuid", strategy = "guid")
@GeneratedValue(generator = "db-uuid")
private String uuid;
public String getUuid() { return uuid; }
public void setUuid(String uuid) { this.uuid = uuid; }

strategy = "guid" и String тип - это важнейшая часть решения.

Перед сохранением новых объектов в режиме гибернации выполните SQL-запрос:

select rawtohex(sys_guid()) from dual

Моя установка:Oracle 11, Гибернация 4.3.4.Окончательная, Весна 3.2.x.И поле - это raw(16) в таблице для эффективного хранения и меньшего размера индекса, то, если вы используете char(32).

Когда я пытаюсь использовать java.util.UUID в качестве типа поля ID я получаю сообщение об ошибке из спящего режима при сохранении нового объекта (он пытается установить String введите в java.util.UUID поле).

Также я использую javax.xml.bind.DatatypeConverter для запросов, не находящихся в режиме гибернации (помощники Spring JDBC), для передачи convert в byte[]:

String query = "insert into TBL (UUID, COMPANY) values (:UUID, :COMPANY)";
MapSqlParameterSource parameters = new MapSqlParameterSource()
    .addValue("COMPANY", repo.getCompany())
    .addValue("UUID", DatatypeConverter.parseHexBinary(signal.getUuid()));
namedJdbcTemplate.update(query, parameters);

для извлечения:

ResultSet rs;
sig.id = DatatypeConverter.printHexBinary(rs.getBytes("UUID"));

Все веб-контроллеры получают такие коды, как:

025131763FB19522E050010A106D11E9

без {, -, } символы (обычное представление UUID является {a-b-c-d-x-y} если вы помните).Это представление уже содержит кодировку URL, чистую и безопасную.Вам не нужно внедрять PropertyEditor или Convertor для String Тип:

@RequestMapping(value = {"/signal/edit/{id}.htm"}, method = RequestMethod.POST)
public String handleEditRequest(
        @PathVariable("id") String id,

Сравните с неудачной попыткой использовать jaa.util.UUID, где мне нужно написать:

@Component
public static class UUIDPropertyEditor extends PropertyEditorSupport {
    @Override
    public void setAsText(final String str) {
        if (str == null || str.isEmpty()) {
            setValue(null);
            return;
        }
        setValue(UUID.fromString(str));
    }
}
private @Autowired UUIDPropertyEditor juuidPE;

@InitBinder
public void initBinder(WebDataBinder binder) {
    binder.registerCustomEditor(UUIDPropertyEditor.class, juuidPE);
}

для того, чтобы использовать:

@PathVariable("id") UUID id,

Я думаю, вы можете сделать это, установив генератор на native.Я не совсем уверен, как это сделать в Hibernate, но в NHibernate вы бы сделали что-то подобное в XML:

<id column="PRODUCT_ID">
  <generator class="native"/>
</id>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top