Настройте Hibernate на использование Oracle SYS_GUID() в качестве первичного ключа
Вопрос
Я ищу способ заставить 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 должен знать, каков идентификатор объекта.Например, рассмотрим следующий сценарий:
- Вы создаете новый объект Product и сохраняете его.Oracle присваивает идентификатор.
- Вы отсоединяете Продукт от сеанса Гибернации.
- Позже вы снова прикрепите его и внесете некоторые изменения.
- Теперь вы хотите сохранить эти изменения.
Не зная идентификатора, 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>