I am looking for a way to get hibernate to use oracle's SYS_GUID()
function when inserting new rows. Currently my DB tables have SYS_GUID()
as the default so if hibernate simply generated SQL that omited the value it should work.
I have everything working, but it is currently generating the UUID/GUID in code using the system-uuid generator:
@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;
}
This is fine, but I would prefer that the guids were generated by the database so they will be sequential and potentially have better performance. Plus I would just like to know how to configure this.
I am using annotations for configuration, but xml configuration examples are awesome as well.
Here is a sample table definition (in case it matters):
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's sollution of using "guid" worked, here is the sql generated:
Hibernate:
select rawtohex(sys_guid())
from dual
Hibernate:
insert into PRODUCT
(PRODUCT_CODE, PRODUCT_DESC, LOB_ID, PRODUCT_NAME, PROVIDER_ID, PRODUCT_ID)
values (?, ?, ?, ?, ?, ?)
It seems that using the columns default value in an insert is not possible, so the choice is between an application generated guid and a database round trip.
You might be able to use the "guid" generator. See this post from the Hibernate forum. It looks like they added support for Oracle using SYS_GUID()
a while back, but the documentation still says they only support SQL Server and MySQL.
I haven't worked with JPA annotations yet, but here is an example using XML configuration:
<id name="PRODUCT_ID">
<generator class="guid" />
</id>
EDIT: In regards to your second question, I think you are asking why Hibernate can't do something like this:
INSERT INTO PRODUCT (PRODUCT_ID, /* etc */)
SELECT SYSGUID(), /* etc */
The reason is that Hibernate must know what the object's ID is. For example, consider the following scenario:
Without knowing the ID, Hibernate can't do this. It needs the ID in order to issue the UPDATE statement. So the implementation of org.hibernate.id.GUIDGenerator
has to generate the ID beforehand, and then later on re-use it in the INSERT statement.
This is the same reason why Hibernate cannot do any batching if you use a database-generated ID (including auto-increment on databases that support it). Using one of the hilo generators, or some other Hibernate-generated ID mechanism, is the only way to get good performance when inserting lots of objects at once.
I have same task that topic starter. With thanks to @Matt Solnit suggestion I use such annotations:
@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"
and String
type are essential parts of solution.
Before persisting new entities Hibernate issue SQL query:
select rawtohex(sys_guid()) from dual
My setup: Oracle 11, Hibernate 4.3.4.Final, Spring 3.2.x. And field is raw(16)
in table for efficient storage and lesser index size then if you use char(32)
.
When I try to use java.util.UUID
as ID field type I get error from Hibernate on persisting new entity (it try to set String
type to java.util.UUID
field).
Also I use javax.xml.bind.DatatypeConverter
for non-Hibernate queries (Spring JDBC helpers), for passing convert to 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);
for extracting:
ResultSet rs;
sig.id = DatatypeConverter.printHexBinary(rs.getBytes("UUID"));
All web controllers get codes like:
025131763FB19522E050010A106D11E9
without {
, -
, }
chars (usual representation of UUID is {a-b-c-d-x-y}
if you remember). This representation already URL encoding clean and safe. You don't need to implement PropertyEditor
or Convertor
for String
type:
@RequestMapping(value = {"/signal/edit/{id}.htm"}, method = RequestMethod.POST)
public String handleEditRequest(
@PathVariable("id") String id,
Compare with failed attempt to use jaa.util.UUID
, where I need to write:
@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);
}
in order to use:
@PathVariable("id") UUID id,
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With