Reputation: 909
I have the RAW(16) PK column in Oracle, and trying to insert into it using JDBC:
PreparedStatement stmt = connection.prepareStatement("insert into COUNTRY (id, state, version, code, name, nationality, issuing_entity, country) values (?, ?, ?, ?, ?, ?, ?, ?)");
UUID id = UUID.randomUUID();
stmt.setObject(1, id, Types.BINARY);
However, I am getting an exception:
java.sql.SQLException: Invalid column type
at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:8494)
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:7995)
at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:8559)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:225)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.setObject(HikariProxyPreparedStatement.java)
at rw.gov.dgie.framework.test.AbstractTestCaseWithDB.tryToInsertCountry(AbstractTestCaseWithDB.java:78)
at rw.gov.dgie.framework.test.AbstractTestCaseWithDB.dbSetup(AbstractTestCaseWithDB.java:62)
at test.rw.gov.dgie.bms.terr.service.TestCountryService.init(TestCountryService.java:37)
I am getting the same exception when trying to use DbSetup for inserting test data.
Is there a way to make JDBC insert UUIDs into RAW(16) column?
I am using Oracle JDBC 12.2.0.1.0.
Upvotes: 15
Views: 14372
Reputation: 53381
JdbcTemplate
provides different methods for performing a DML operations like insert. Please, consider for instance update
.
@MarmiteBomber provides in his/her answer all the necessary information for performing what you need, please, only wrap the code appropriately in the different artifacts defined by Spring.
For example, you can use PreparedStatementCreator
, something like:
jdbcTemplate.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
PreparedStatement ps = con.prepareStatement("insert into TAB_UUID (id, uuid) values (?,?)");
ps.setInt(1,1);
UUID uuid = UUID.randomUUID();
ps.setBytes(2,asBytes(uuid));
return ps;
}
});
The code can be simplified using lambdas to:
jdbcTemplate.update(con -> {
PreparedStatement ps = con.prepareStatement("insert into TAB_UUID (id, uuid) values (?,?)");
ps.setInt(1,1);
UUID uuid = UUID.randomUUID();
ps.setBytes(2,asBytes(uuid));
return ps;
});
If you prefer, you can use PreparedStatementSetter
instead:
jdbcTemplate.update("insert into TAB_UUID (id, uuid) values (?,?)", new PreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps) throws SQLException {
ps.setInt(1,1);
UUID uuid = UUID.randomUUID();
ps.setBytes(2, asBytes(uuid));
}
});
Again, the code can be simplified with lambdas:
jdbcTemplate.update("insert into TAB_UUID (id, uuid) values (?,?)", ps -> {
ps.setInt(1,1);
UUID uuid = UUID.randomUUID();
ps.setBytes(2, asBytes(uuid));
});
In both examples you explicitly invoke setBytes
in the underlying prepared statement and use the asBytes
method from the Marmite answer.
Upvotes: 2
Reputation: 2634
getJdbcTemplate().update("INSERT INTO abc(abc_id, abc_uuid, "
+ "VALUES (?, ?)",
abcId, uuidToBytes(abcUuid))
Here's a helper method to converet UUID type to bytes.
private byte[] uuidToBytes(final UUID uuid) {
if (Objects.isNull(uuid)) {
return null;
}
final byte[] uuidAsBytes = new byte[16];
ByteBuffer.wrap(uuidAsBytes)
.order(ByteOrder.BIG_ENDIAN)
.putLong(uuid.getMostSignificantBits())
.putLong(uuid.getLeastSignificantBits());
return uuidAsBytes;
}
Upvotes: 2
Reputation: 21063
You must convert the UUID to a byte array. See the method asBytes how to do it.
After it the binding is a s simple as using setBytes
.
Example
def stmt = con.prepareStatement("insert into TAB_UUID (id, uuid) values (?,?)")
// bind
stmt.setInt(1,1)
def uuid = UUID.randomUUID()
stmt.setBytes(2,asBytes(uuid))
def rowCount = stmt.executeUpdate()
Here just for case the link doesn't work the conversion method UUID to byte array
public static byte[] asBytes(UUID uuid) {
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return bb.array();
}
Upvotes: 11
Reputation:
Oracle has no real UUID datatype and dealing with RAW(16)
is really a PITA.
What we do, is to pass the UUID as a string to a SQL statement that uses hextoraw()
:
String sql = "insert into foo (id) values (hextoraw(?))";
PreparedStatement pstmt = connection.prepareStatement(sql);
UUID uid = UUID.randomUUID();
pstmt.setString(1, uid.toString().replaceAll("-", ""));
Upvotes: 5