Postgres UUID JDBC не работает
Последние драйверы Java JDBC для postgres утверждают, что изначально поддерживают UUID; работает против Postgres 9.2 (Mac).
Действительно, когда используется PreparedStatement, я могу пошагово просмотреть код драйвера и даже пройти через специальную функцию setUuid в AbstractJdbc3gStatement.java. Судя по всему, он должен "просто работать".
Однако это не работает. База данных возвращает ошибку, которую я получаю таким образом:
Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: uuid = bytea
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Position: 139
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2157) ~[postgresql-9.2-1002.jdbc4.jar:na]
Да, действительно, setUuid в драйвере JDBC отправляет это как байту:
private void setUuid(int parameterIndex, UUID uuid) throws SQLException {
if (connection.binaryTransferSend(Oid.UUID)) {
byte[] val = new byte[16];
ByteConverter.int8(val, 0, uuid.getMostSignificantBits());
ByteConverter.int8(val, 8, uuid.getLeastSignificantBits());
bindBytes(parameterIndex, val, Oid.UUID);
} else {
bindLiteral(parameterIndex, uuid.toString(), Oid.UUID);
}
}
Что дает? Есть ли какая-то волшебная руна, необходимая в реальной базе данных, чтобы благословить это преобразование?
3 ответа
ТЛ; др
myPreparedStatement.setObject(
… ,
java.util.UUID.randomUUID()
)
подробности
(а) Покажите нам свой код.
PreparedStatement::setObject
работает при прохождении java.util.UUID
, Вероятно, у вас есть другая проблема в вашем коде.
(б) См. мой пост в блоге Значения UUID от JDBC до Postgres для небольшого обсуждения и примера кода.
// Generate or obtain data to store in database.
java.util.UUID uuid = java.util.UUID.randomUUID(); // Generate a random UUID.
String foodName = "Croissant";
// JDBC Prepared Statement.
PreparedStatement preparedStatement = conn.prepareStatement( "INSERT INTO food_ (pkey_, food_name_ ) VALUES (?,?)" );
int nthPlaceholder = 1; // 1-based counting (not an index).
preparedStatement.setObject( nthPlaceholder++, uuid );
preparedStatement.setString( nthPlaceholder++, foodName );
// Execute SQL.
if ( !( preparedStatement.executeUpdate() == 1 ) ) {
// If the SQL reports other than one row inserted…
this.logger.error( "Failed to insert row into database." );
}
(с) Я не уверен, что вы подразумеваете под
Последние драйверы Java JDBC для postgres утверждают, что изначально поддерживают UUID
Какой водитель? Существует как минимум два драйвера JDBC с открытым исходным кодом для Postgres: текущий / устаревший и новый переписанный "следующего поколения". Есть и другие коммерческие драйверы.
"Родной"? Можете ли вы дать ссылку на документацию, которую вы прочитали? В спецификации SQL нет типа данных для UUID (к сожалению, ☹), поэтому в спецификации JDBC нет типа данных для UUID. В качестве обходного пути драйвер JDBC для Postgres использует setObject
а также getObject
методы в PreparedStatement перемещают UUID через пропасть между Java, SQL, Postgres. Смотрите пример кода выше.
Как сказано в документе PreparedStatement JDBC:
Если требуются произвольные преобразования типов параметров, следует использовать метод setObject с целевым типом SQL.
Возможно, "изначально" вы перепутали собственную поддержку Postgres для UUID как типа данных с JDBC, имеющим тип данных UUID. Postgres действительно поддерживает UUID как тип данных, что означает, что значение сохраняется как 128-битное, а не многократно, если оно было сохранено как шестнадцатеричная строка ASCII или Unicode. Быть нативным также означает, что Postgres знает, как построить индекс для столбца этого типа.
Суть моего поста, упомянутого выше, заключалась в том, что я был приятно удивлен тем, насколько просто преодолеть эту пропасть между Java ↔ SQL ↔ Postgres
, В моих первых необразованных попытках я работал слишком усердно.
Еще одно замечание о том, что Postgres поддерживает UUID... Postgres знает, как хранить, индексировать и извлекать существующие значения UUID. Чтобы сгенерировать значения UUID, необходимо включить расширение Postgres (плагин) uuid-ossp
, Это расширение включает библиотеку, предоставляемую проектом OSSP, для генерации различных типов значений UUID. Смотрите мой блог для получения инструкций.
Кстати…
Если бы я знал, как подать прошение в экспертную группу JDBC или команду JSR, чтобы JDBC знал о UUID, я бы, конечно, знал. Они делают это только для новых типов даты и времени, определенных в JSR 310: API даты и времени.
Точно так же, если бы я знал, как обратиться к комитету по стандартам SQL с просьбой добавить тип данных UUID, я бы сделал это. Но, видимо, этот комитет более скрытный, чем советское Политбюро, и медленнее, чем ледник.
Я использовал следующий подход для добавления UUID и других объектов в postgres:
PGobject toInsertUUID = new PGobject();
toInsertUUID.setType("uuid");
toInsertUUID.setValue(uuid.toString());
PreparedStmt stmt = conn.prepareStatement(query);
stmt.setObject(placeHolder,toInsertUUID);
stmt.execute();
Таким образом, вы будете мешать себе делать приведение типов. Этот кусок кода работал отлично для меня в любое время, например, даже JSON.
Это сработало для меня, используя org.postgresql.postgresql 42.2.5
myPreparedStatement.setObject(4, UUID.randomUUID(),java.sql.Types.OTHER)
Без java.sql.Types.OTHER я получил ошибку
Пытаться
.setParameter("uuid", uuid, PostgresUUIDType.INSTANCE);