Oracle JDBC: как вставить UUID в столбец RAW (16)

У меня есть столбец RAW (16) PK в Oracle, и я пытаюсь вставить в него с помощью 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);

Однако я получаю исключение:

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)

Я получаю такое же исключение при попытке использовать DbSetup для вставки тестовых данных.

Есть ли способ заставить JDBC вставлять UUID в столбец RAW (16)?

Я использую Oracle JDBC 12.2.0.1.0.

Вы не можете спасти id.toString()?

user7294900 25.06.2018 14:52

imho вам нужно передать что-то вроде byte [] драйверу JDBC, чтобы разрешить хранение типа данных RAW.

ibre5041 25.06.2018 14:58

id.toString ()? В RAW (16)? Но как?

Serge Iroshnikov 25.06.2018 14:59

@ ibre5041, я могу записать это в байтах, но мне нужно, чтобы DbSetup работал. Hibernate отлично работает

Serge Iroshnikov 25.06.2018 15:04

как насчет использования setBytes () вместо setObject ()?

ibre5041 25.06.2018 15:10

setBytes () работает, но не для DbSetup

Serge Iroshnikov 25.06.2018 15:12
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
9
6
6 406
3

Ответы 3

Oracle не имеет реального типа данных UUID, и работа с RAW(16) на самом деле является PITA.

Что мы делаем, так это передаем UUID в виде строки в инструкцию SQL, которая использует hextoraw():

String sql = "insert into foo (id) values (hextoraw(?))";
PreparedStatement pstmt = connection.prepareStatement(sql);
UUID uid = UUID.randomUUID();
pstmt.setString(1, uid.toString().replaceAll("-", ""));

Вы должны преобразовать UUID в байтовый массив. Смотрите метод asBytes, как это сделать.

После этого привязка осуществляется очень просто, как с помощью setBytes.

Пример

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()

Вот на всякий случай ссылка не работает метод преобразования UUID в байтовый массив

  public static byte[] asBytes(UUID uuid) {
    ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
    bb.putLong(uuid.getMostSignificantBits());
    bb.putLong(uuid.getLeastSignificantBits());
    return bb.array();
  }

@Serge, пожалуйста; в любом случае, исходя из моего опыта, я бы использовал / разрешил использовать хэш-коды в качестве PK, только если есть две веские причины: почему sequence нельзя использовать, и этот хеш-код дает реальное преимущество перед числовым PK. Удачи!

Marmite Bomber 25.06.2018 17:32

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

Serge Iroshnikov 26.06.2018 15:29
getJdbcTemplate().update("INSERT INTO abc(abc_id, abc_uuid, "
                                       + "VALUES (?, ?)",
                                          abcId, uuidToBytes(abcUuid))

Вот вспомогательный метод для преобразования типа UUID в байты.

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;
    }

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