2013-07-31 15 views
9

I più recenti driver JDBC Java per postgres dichiarano di supportare gli UUID in modo nativo; lavorare contro Postgres 9.2 (mac).Postgres UUID JDBC non funzionante

In effetti, quando si utilizza un PreparedStatement, è possibile scorrere il codice del driver e persino camminare su tramite la funzione "setUuid" specializzata in AbstractJdbc3gStatement.java. Con tutte le indicazioni, dovrebbe "funzionare".

Tuttavia, non funziona. Il database getta indietro un errore che ricevo così:

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] 

Sì, in effetti, setUuid nel driver JDBC fa inviare che come bytea:

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

Che cosa dà? C'è qualche runa magica richiesta nel database reale per benedire questa conversione?

+1

Puoi pubblicare il PreparedStatement reale che si sta tentando di eseguire? – Rafael

risposta

20

(a) Mostraci il tuo codice.

(b) Vedere il post del blog UUID Values From JDBC to Postgres per un po 'di discussione e codice di esempio.

// 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."); 
} 

(c) Non sono sicuro di cosa si intende per

Gli ultimi driver Java JDBC per Postgres affermano di supportare nativamente UUID

Quale driver? Esistono almeno due driver JDBC open-source per Postgres, lo current/legacy one e una nuova riscrittura "next generation" one. E ci sono anche altri conducenti commerciali.

"nativamente"? Puoi collegare alla documentazione che hai letto? La specifica SQL non ha alcun tipo di dati per UUID (sfortunatamente ☹), pertanto lo JDBC spec non ha alcun tipo di dati per UUID. Per ovviare al problema, il driver JDBC per Postgres utilizza i metodi setObject e getObject in PreparedStatement sposta l'UUID attraverso la voragine tra Java ↔ SQL ↔ Postgres. Vedi il codice di esempio sopra.

Come PreparedStatement JDBC doc dice:

Se sono necessarie conversioni di tipo di parametro arbitrario, il metodo setObject deve essere utilizzato con un tipo di destinazione SQL.

Forse "nativamente", hai confuso il supporto nativo di Postgres per UUID come un tipo di dati con JDBC con un tipo di dati UUID. Postgres supporta infatti UUID come un tipo di dati, il che significa che il valore è memorizzato come 128 bit anziché più volte se fosse memorizzato come stringa esadecimale ASCII o Unicode. Ed essere nativi significa anche che Postgres sa come costruire un indice su una colonna di quel tipo.

Il punto del mio post sul blog di cui sopra è stato che sono rimasto piacevolmente sorpreso da quanto sia semplice colmare quella voragine tra Java ↔ SQL ↔ Postgres. Nei miei primi tentativi non istruiti, stavo lavorando troppo.


Un'altra nota su Postgres sostenere UUID ... Postgres sa come conservare, indicizzare e recuperare i valori UUID esistenti.Per generare valori UUID, è necessario abilitare l'estensione Postgres (plugin) uuid-ossp. Questa estensione include a library provided by The OSSP Project per generare una varietà di tipi di valori UUID. Vedi my blog for instructions.


A proposito ...

Se sapessi come petizione il gruppo di esperti JDBC o squadra JSR per fare JDBC consapevoli di UUID, certamente avrebbe fatto. Stanno facendo proprio questo per i nuovi tipi di data-ora definiti in JSR 310: Date and Time API.

Analogamente, se avessi saputo come presentare una petizione al comitato per gli standard SQL per aggiungere un tipo di UUID, lo farei. Ma a quanto pare il comitato è più riservato del Politburo sovietico e più lento di un ghiacciaio.

+5

> quel comitato è più riservato del Politburo sovietico e più lento di un ghiacciaio. ... Commento dell'anno !!! –

11

ho usato il seguente approccio per aggiungere UUID e altri oggetti per postgres:

PGobject toInsertUUID = new PGobject(); 
toInsertUUID.setType("uuid"); 
toInsertUUID.setValue(uuid.toString()); 
PreparedStmt stmt = conn.prepareStatement(query); 
stmt.setObject(placeHolder,toInsertUUID); 
stmt.execute(); 

In questo modo si fermeremo se stessi da fare casting di tipo. Questo pezzo di codice ha funzionato perfettamente per me in qualsiasi momento, ad esempio persino JSON.

+1

Grazie. Questo dovrebbe essere contrassegnato come una risposta. – azhidkov

0

provare

.setParameter("uuid", uuid, PostgresUUIDType.INSTANCE); 
Problemi correlati