Настройте Hibernate для использования Oracle SYS_GUID () для первичного ключа - PullRequest
7 голосов
/ 11 мая 2009

Я ищу способ получить спящий режим, чтобы использовать функцию 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;
}

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

Я использую аннотации для конфигурации, но примеры конфигурации 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)
)

UPDATE:

Мэт решил использовать "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 (?, ?, ?, ?, ?, ?)

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

Ответы [ 3 ]

5 голосов
/ 11 мая 2009

Возможно, вы сможете использовать генератор 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 должен знать, каков ID объекта. Например, рассмотрим следующий сценарий:

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

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

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

2 голосов
/ 11 сентября 2014

У меня та же задача, что и у стартера темы. Благодаря предложению @ Matt Solnit я использую такие аннотации:

@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 являются неотъемлемой частью решения.

Перед сохранением новых сущностей Hibernate выдает SQL-запрос:

select rawtohex(sys_guid()) from dual

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

Когда я пытаюсь использовать java.util.UUID в качестве типа поля идентификатора, я получаю сообщение об ошибке от Hibernate при сохранении новой сущности (при попытке установить String type в поле java.util.UUID).

Также я использую javax.xml.bind.DatatypeConverter для запросов не в Hibernate (помощники Spring JDBC), для передачи конвертирования в 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,
0 голосов
/ 11 мая 2009

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

<id column="PRODUCT_ID">
  <generator class="native"/>
</id>
...