corretto sospensione di annotazione per byte[]

Ho un’applicazione che utilizza 3.1 hibernate e JPA annotazioni. Ha fatto un paio di oggetti con il byte[] attributi (1k – 200k dimensioni). Utilizza l’APP @Lob di annotazioni, e di sospensione 3.1 grado di leggere questi bene su tutti i principali database-sembra che per nascondere la JDBC Blob fornitore peculiarità (come dovrebbe fare).

@Entity
public class ConfigAttribute {
  @Lob
  public byte[] getValueBuffer() {
    return m_valueBuffer;
  }
}

Abbiamo dovuto aggiornamento alla 3.5, quando abbiamo scoperto che hibernate 3.5 si rompe (e non risolvere) questa annotazione combinazione di postgresql (senza soluzione). Non ho trovato una chiara fix finora, ma ho notato che se mi limito a rimuovere @Lob, utilizza il postgresql tipo bytea (che funziona, ma solo su postgres).

annotation                   postgres     oracle      works on
-------------------------------------------------------------
byte[] + @Lob                oid          blob        oracle
byte[]                       bytea        raw(255)    postgresql
byte[] + @Type(PBA)          oid          blob        oracle
byte[] + @Type(BT)           bytea        blob        postgresql

once you use @Type, @Lob seems to not be relevant
note: oracle seems to have deprecated the "raw" type since 8i.

Sto cercando un modo per avere una singola classe annotata (con un blob di proprietà) che è portabile su tutti i principali database.

  • Quale è il portatile di modo di annotare un byte[] proprietà?
  • È fisso, in qualche versione recente di sospensione?

Aggiornamento:
Dopo la lettura di questo blog ho finalmente capito che l’originale soluzione JIRA problema è: a quanto Pare si sono tenuti a cadere @Lob e annotare la proprietà come:

@Type(type="org.hibernate.type.PrimitiveByteArrayBlobType") 
byte[] getValueBuffer() {...

Tuttavia, questo non funziona per me — ho ancora Oid invece di bytea; essa ha, tuttavia, il lavoro per l’autore del JIRA problema, che sembrava voler oid.

Dopo la risposta da parte di A. Garcia, poi ho provato questa combinazione, che effettivamente funziona su postgresql, ma non su oracle.

@Type(type="org.hibernate.type.BinaryType") 
byte[] getValueBuffer() {...

Che cosa ho veramente bisogno di fare è controllare che @org.di sospensione.le annotazioni.Tipo di combinazione (@Lob + byte[] viene ” mappata) (postgresql).


Qui è il frammento di 3.5.5.Finale da MaterializedBlobType (sql di tipo Blob). Secondo il blog di Steve, postgresql vuole di utilizzare Flussi per bytea (non chiedetemi perché) e di postgresql personalizzato di tipo Blob per oid. Si noti inoltre che con setBytes() su JDBC è anche per bytea (rispetto al passato). Quindi, questo spiega perché l’uso di streaming non interessa che sia scontato il ‘bytea’.

public void set(PreparedStatement st, Object value, int index) {
 byte[] internalValue = toInternalFormat( value );
 if ( Environment.useStreamsForBinary() ) {
  //use streams = true
   st.setBinaryStream( index, 
    new ByteArrayInputStream( internalValue ), internalValue.length );
 }
 else {
  //use streams = false
  st.setBytes( index, internalValue );
 }
}

Questo si traduce in:

ERROR: column "signature" is of type oid but expression is of type bytea

Aggiornamento
La prossima domanda logica è: “perché non basta cambiare le definizioni di tabella manualmente a bytea” e mantenere l’ (@Lob + byte[])? Questo non lavoro, FINO si tenta di memorizzare un valore null byte[]. Che postgreSQL driver pensa che è un OID tipo di espressione e il tipo di colonna è bytea — questo è causa di sospensione (giustamente) le chiamate JDBC.setNull() invece di JDBC.setBytes(null) PG driver si aspetta.

ERROR: column "signature" is of type bytea but expression is of type oid

Il tipo di sistema in modalità di ibernazione è attualmente un ‘work in progress’ (secondo 3.5.5 un periodo di ammortamento di commento). Infatti, tanto 3.5.5 codice è obsoleto, è difficile sapere cosa guardare quando sottoclassi la PostgreSQLDialect).

AFAKT, Tipi.BLOB/’oid’ su postgresql deve essere mappato a qualche tipo personalizzato che utilizza OID stile JDBC accesso (ossia PostgresqlBlobType oggetto e NON MaterializedBlobType). Non ho mai effettivamente utilizzato con successo di Blob con postgresql, ma so che bytea semplicemente funziona come uno /mi sarei aspettato.

Attualmente sto guardando il BatchUpdateException — possibile che il driver non supporta batch.


Grande citazione dal 2004:
“Per riassumere le mie divagazioni, direi che ci si dovrebbe attendere che il driver JDBC per fare Lob correttamente prima di cambiare di Sospensione.”

Riferimenti:

Questo sembra essere stato risolto in 3.6, non è certo 3.5.6; il MaterializedBlobType classe è stato totalmente riscritto da 3.5.5 > 3.6. L’OID tipo ora funziona dato che hanno cambiato l’attuazione.
Bello! Mi chiedo cosa Jira problema è traccia di questa riscrittura, se del caso (forse la riscrittura è una conseguenza di un profondo cambiamento). Sarebbe bello portare le modifiche in 3.5, se possibile. Cattive notizie, se possibile.
In realtà il mio test mi ha dato un falso positivo la prima volta (sapevo che avrei dovuto aspettare!) — ancora non risolto, il problema è solo spostato BlobTypeDescriptor.

OriginaleL’autore | 

8 Replies
  1. 57

    Qual è il portatile di modo di annotare un byte[] proprietà?

    Dipende da ciò che si desidera. JPA possono persistere non annotati byte[]. Dal JPA 2.0 spec:

    11.1.6 Annotazione Di Base

    Il Basic annotazione è il più semplice
    tipo di mapping a una colonna del database.
    Il Basic annotazione può essere applicato
    di una persistente di proprietà o di istanza
    variabile di uno dei seguenti
    tipi primitivi di Java, tipi, wrapper
    i tipi primitivi,
    java.lang.String,
    java.math.BigInteger,
    java.math.BigDecimal,
    java.util.Date,
    java.util.Calendar, java.sql.Date,
    java.sql.Time, java.sql.Timestamp,
    byte[], Byte[], char[], Character[], le enumerazioni, e qualsiasi altro
    tipo che implementa Serializable.
    Come descritto nella Sezione 2.8, l’uso
    del Basic annotazione è facoltativa
    per persistente i campi e le proprietà
    di questi tipi. Se la Base
    l’annotazione non è specificato per tale
    campo o una proprietà, i valori di default
    l’annotazione di Base.

    Sospensione e la mappa di un “default” di SQL VARBINARY (o SQL LONGVARBINARY a seconda del Column dimensioni?) che PostgreSQL maniglie con bytea.

    Ma se si desidera che il byte[] essere memorizzati in un Oggetto di Grandi dimensioni, è consigliabile utilizzare un @Lob. Dalle specifiche tecniche:

    11.1.24 Lob Annotazione

    Un Lob annotazione specifica che un
    di proprietà persistenti o il campo deve essere
    persistente come un oggetto di grandi dimensioni per un
    supportato da database di grandi dimensioni tipo di oggetto.
    Portatile, le applicazioni devono utilizzare il
    Lob annotazione quando il mapping a un
    database Lob tipo. Il Lob annotazione
    può essere utilizzato in combinazione con il
    Annotazione di base o con il
    ElementCollection annotazione quando il
    insieme di elementi di valore è di base
    tipo. Un Lob può essere sia un binario o
    tipo di carattere. Il Lob tipo è
    dedotto dal tipo di
    persistente campo o una proprietà e,
    tranne che per le stringhe e i tipi di carattere,
    impostazioni predefinite di Blob.

    Sospensione e la mappa per SQL BLOB che PostgreSQL maniglie con oid
    .

    È fisso, in qualche versione recente di sospensione?

    Bene, il problema è che non so qual è il problema esattamente. Ma posso almeno dire che nulla è cambiato dal 3.5.0-Beta-2 (che è cambiata è stato introdotto)in 3.5.x ramo.

    Ma la mia comprensione di problemi come HHH-4876, HHH-4617 e di PostgreSQL e Blob (menzionato nel javadoc del PostgreSQLDialect) è che si suppone di impostare le seguenti proprietà

    hibernate.jdbc.use_streams_for_binary=false

    se si desidera utilizzare oid cioè byte[] con @Lob (che è la mia comprensione, poiché VARBINARY non è ciò che si desidera con Oracle). Hai provato questo?

    Come alternativa, HHH-4876 suggerisce di utilizzare il deprecato PrimitiveByteArrayBlobType per ottenere il comportamento (pre Sospensione 3.5).

    Riferimenti

    • JPA 2.0
      • Sezione 2.8 “Mappatura dei valori di Default per i Non-Campi di Relazione o di Proprietà”
      • Sezione 11.1.6 “Annotazione Di Base”
      • Sezione 11.1.24 “Lob Annotazione”

    Risorse

    OMG, mi rendo conto che questa domanda è molto cambiato da quando ho iniziato a rispondere. Leggere tutte le modifiche e aggiornare in seguito il mio answes dopo aver appreso le modifiche, se necessario.
    La sua buona per vedere la spec, quindi hibernate è totalmente corretto mappa (@Lob + byte[]) per un oggetto di grandi dimensioni di tipo supportato. In Postgresql ci sono 2 (bytea o oid). Tuttavia, mentre la sospensione 3.5 mappe oid (per impostazione predefinita) legge utilizzando JDBC getBytes() che PGSQL driver restituisce il 6 byte oid al posto dei dati. Nota anche che l’autore del blog ha risposto più utilmente (sul suo blog) dato che la domanda è stata posta.
    mentre sospensione 3.5 mappe oid (per impostazione predefinita) legge utilizzando JDBC getBytes() che PGSQL driver restituisce il 6 byte oid invece dei dati – questo si verifica quando si utilizza hibernate.jdbc.use_streams_for_binary=false troppo? (andando a controllare quello che Steve ha detto ora).
    Ho intenzione di provare a specificare nel file delle proprietà, tuttavia PostgreSQLDialect ha useInputStreamToInsertBlob() restituisce false, quindi suppongo che io sono, perché io non sono esplicitamente l’impostazione di questa proprietà.
    Dopo l’impostazione di questa proprietà (true o false), ottengo un’eccezione di runtime: ERRORE: la colonna “firma” è di tipo bytea ma l’espressione è di tipo oid”. Devo dire che sto usando hibernate 3.5.5.Finale + PG 8.2 driver.

    OriginaleL’autore Pascal Thivent

  2. 9

    Qui va che O’reilly Enterprise JavaBeans, 3.0 dice

    JDBC ha particolari tipi di questi oggetti molto grandi. Java.sql.Tipo Blob rappresenta i dati binari, e java.sql.Clob rappresenta i dati di carattere.

    Qui va PostgreSQLDialect codice sorgente

    public PostgreSQLDialect() {
        super();
        ...
        registerColumnType(Types.VARBINARY, "bytea");
        /**
          * Notice it maps java.sql.Types.BLOB as oid
          */
        registerColumnType(Types.BLOB, "oid");
    }

    Così che cosa si può fare

    Ignorare PostgreSQLDialect come segue

    public class CustomPostgreSQLDialect extends PostgreSQLDialect {
    
        public CustomPostgreSQLDialect() {
            super();
    
            registerColumnType(Types.BLOB, "bytea");
        }
    }

    Ora basta definire il proprio personalizzato dialetto

    <property name="hibernate.dialect" value="br.com.ar.dialect.CustomPostgreSQLDialect"/>

    E usare il vostro portatile JPA @Lob annotazione

    @Lob
    public byte[] getValueBuffer() {

    AGGIORNAMENTO

    Qui è stato estratto qui

    Ho un’applicazione in esecuzione in sospensione 3.3.2 e le applicazioni funziona bene, con tutti i campi blob utilizzando oid (byte[] in java)

    Migrazione a sospensione 3.5 tutti i campi blob non funziona più, e il server di log mostra: ERRORE org.di sospensione.util.JDBCExceptionReporter – ERRORE: colonna è di tipo oid ma l’espressione è di tipo bytea

    che può essere spiegato qui

    Questo genere non è bug dei PG JDBC, ma il cambiamento di implementazione predefinita di Sospensione nella versione 3.5. Nella mia situazione impostazione compatibile proprietà di connessione
    non ha aiutato
    .

    Molto di più questo quello che ho visto in 3.5 – beta 2, e non so se questo problema è stato risolto è Hibernate – senza @annotazione di Tipo – auto-creare una colonna di tipo oid, ma prova a leggere questo come bytea

    Interessante perché, quando egli mappe Tipi.BOLB come bytea (Vedi CustomPostgreSQLDialect) Ha la possibilità di avere

    Non può eseguire JDBC aggiornamento batch

    durante l’inserimento o l’aggiornamento

    Questa soluzione appare glorioso, sto provando ora.
    Questo genera il corretto DDL, ma non riesce a runtime: ho un java.sql.BatchUpdateException quando cercando di un oggetto con un blob di proprietà.
    Provare un simile scenario, l’utilizzo di Oracle invece di PostgreSQL e vedere cosa si ottiene. BatchUpdateException ha a che fare con gli errori che si verifica durante un batch operazione di aggiornamento.
    In realtà, quello che voglio non è la per la mappa BLOB “bytea” ma, invece, mappa (byte[] + @Lob) annotazione combinazione di Tipi.VARBINARY!
    Vedere download-llnw.oracle.com/javase/1.5.0/docs/api/java/sql/…

    OriginaleL’autore Arthur Ronald

  3. 6

    Finalmente ho ottenuto questo lavoro. Si espande sulla soluzione da A. Garcia, tuttavia, dal momento che il problema sta nel tipo hibernate MaterializedBlob tipo semplice mappatura di Blob > bytea non è sufficiente, abbiamo bisogno di un ricambio per MaterializedBlobType che funziona con sospensione rotto il supporto blob. Questa implementazione funziona solo con bytea, ma forse il ragazzo dal JIRA problema che ha voluto OID potrebbe contribuire un OID attuazione.

    Purtroppo la sostituzione di questi tipi di runtime è un dolore, in quanto dovrebbero essere parte del Dialetto.
    Se solo questo JIRA enhanement entra in 3.6 sarebbe possibile.

    public class PostgresqlMateralizedBlobType extends AbstractSingleColumnStandardBasicType<byte[]> {
     public static final PostgresqlMateralizedBlobType INSTANCE = new PostgresqlMateralizedBlobType();
    
     public PostgresqlMateralizedBlobType() {
      super( PostgresqlBlobTypeDescriptor.INSTANCE, PrimitiveByteArrayTypeDescriptor.INSTANCE );
     }
    
      public String getName() {
       return "materialized_blob";
      }
    }

    Molto di questo, probabilmente, potrebbe essere statico (non getBinder() veramente bisogno di una nuova istanza?), ma io non capisco la sospensione interno in modo che questo è in gran parte copia + incolla + modifica.

    public class PostgresqlBlobTypeDescriptor extends BlobTypeDescriptor implements SqlTypeDescriptor {
      public static final BlobTypeDescriptor INSTANCE = new PostgresqlBlobTypeDescriptor();
    
      public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
       return new PostgresqlBlobBinder<X>(javaTypeDescriptor, this);
      }
      public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
       return new BasicExtractor<X>( javaTypeDescriptor, this ) {
        protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { 
          return (X)rs.getBytes(name);
        }
       };
      }
    }
    
    public class PostgresqlBlobBinder<J> implements ValueBinder<J> {
     private final JavaTypeDescriptor<J> javaDescriptor;
     private final SqlTypeDescriptor sqlDescriptor;
    
     public PostgresqlBlobBinder(JavaTypeDescriptor<J> javaDescriptor, SqlTypeDescriptor sqlDescriptor) { 
      this.javaDescriptor = javaDescriptor; this.sqlDescriptor = sqlDescriptor;
     }  
     ...
     public final void bind(PreparedStatement st, J value, int index, WrapperOptions options) 
     throws SQLException {
      st.setBytes(index, (byte[])value);
     }
    }
    +1 per la vostra ricerca. Complimenti. Solo un consiglio: Preferite la modifica della propria domanda/risposta fino a 8 volte. In caso contrario, la tua domanda/risposta diventerà comunità wiki e non guadagno reputazione e voto non sarà più calcolata
    Vivere e imparare suppongo, ho avuto così tante modifiche, mi sono dimenticato di fare una cosa o di altri con il mio ambiente di test.
    Stesso qui, +1 per la ricerca e la soluzione per la vostra situazione.
    ogni possibilità di soluzione con 4.2.x Sospensione di versione? Interno di Hibernate hanno cambiato un po ‘ (ho commentato problema descritto: hibernate.atlassian.net/browse/HHH-5584).

    OriginaleL’autore Justin

  4. 4

    Sto usando Hibernate 4.2.7.SP1 con Postgres, 9.3 e in seguito lavora per me:

    @Entity
    public class ConfigAttribute {
      @Lob
      public byte[] getValueBuffer() {
        return m_valueBuffer;
      }
    }

    come Oracle non ha problemi con quella, e per Postgres sto usando personalizzato dialetto:

    public class PostgreSQLDialectCustom extends PostgreSQL82Dialect {
    
        @Override
        public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
        if (sqlTypeDescriptor.getSqlType() == java.sql.Types.BLOB) {
          return BinaryTypeDescriptor.INSTANCE;
        }
        return super.remapSqlTypeDescriptor(sqlTypeDescriptor);
      }
    }

    il vantaggio di questa soluzione che prendo in considerazione, che posso tenere sospensione vasi intatti.

    Per ulteriori Postgres/Oracle problemi di compatibilità con Hibernate, vedere il mio post del blog.

    Per me ha funzionato, utilizzando Hibernate 4.3.6 e Postgresql 9.3 con l’estensione Postgresql9Dialect. Grazie!

    OriginaleL’autore

  5. 1

    ho risolto il Mio problema aggiungendo l’annotazione @Lob che creerà il byte[] in oracle come blob , ma questa annotazione si crea il campo come oid che non funziona correttamente , fare byte[] creato come bytea ho fatto il cliente Dialetto per postgres, come di seguito

    Public class PostgreSQLDialectCustom extends PostgreSQL82Dialect {
        public PostgreSQLDialectCustom() {
            System.out.println("Init PostgreSQLDialectCustom");
            registerColumnType( Types.BLOB, "bytea" );
    
          }
    
        @Override
        public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
        if (sqlTypeDescriptor.getSqlType() == java.sql.Types.BLOB) {
          return BinaryTypeDescriptor.INSTANCE;
        }
        return super.remapSqlTypeDescriptor(sqlTypeDescriptor);
      }
     }

    Necessario eseguire l’override di parametro per il Dialetto

    spring.jpa.properties.hibernate.dialect=com.ntg.common.DBCompatibilityHelper.PostgreSQLDialectCustom

    più suggerimento può essere trovato lei : https://dzone.com/articles/postgres-and-oracle

    OriginaleL’autore

  6. 0

    Ho preso il lavoro con l’override di annotazione con i file XML per Postgres. L’annotazione viene mantenuto per Oracle. A mio parere, In questo caso sarebbe meglio ignorare la mappatura di questo problema-alcuni enity con xml di mapping. Siamo in grado di eseguire l’override singola /multipla entità xml di mapping. Quindi ci sarebbe l’uso di annotazione per i nostri pricipalmente-database supportato, e un file xml per ogni altro database.

    Nota: abbiamo solo bisogno di eseguire l’override di una singola classe , quindi non è un grosso problema.
    Leggi di più dal mio esempio
    Esempio per eseguire l’override di annotazione XML

    OriginaleL’autore

  7. 0

    Su Postgres @Lob è di rottura per byte[] come si cerca di salvarlo come oid, e la Corda che anche lo stesso problema si verifica. Di seguito codice di interruzione di postgres che sta lavorando bene su oracle.

    @Lob
    private String stringField;

    e

    @Lob
    private byte[]   someByteStream;

    Per fissare sopra a postgres hanno scritto sotto personalizzato di sospensione.dialetto

    public class PostgreSQLDialectCustom extends PostgreSQL82Dialect{
    
    public PostgreSQLDialectCustom()
    {
        super();
        registerColumnType(Types.BLOB, "bytea");
    }
    
     @Override
     public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
        if (Types.CLOB == sqlTypeDescriptor.getSqlType()) {
          return LongVarcharTypeDescriptor.INSTANCE;
        }
        return super.remapSqlTypeDescriptor(sqlTypeDescriptor);
      }
    }

    Ora configurare personalizzato dialetto in sospensione

    hibernate.dialect=X.Y.Z.PostgreSQLDialectCustom   

    X. Y. Z è il nome del pacchetto.

    Ora funziona bene.
    NOTA – la Mia Sospensione di versione – 5.2.8.Finale
    Postgres versione – 9.6.3

    OriginaleL’autore

  8. 0

    Grazie Justin, Pascal per me guidare verso la giusta direzione. Mi è stato anche affrontando lo stesso problema con la Sospensione 3.5.3. La vostra ricerca e puntatori a destra classi mi aveva aiutato a identificare il problema e fare una correzione.

    Per il beneficio per coloro che sono ancora bloccato con Sospensione 3.5 e l’utilizzo di oid + byte[] + @LoB combinazione di seguito è quello che ho fatto per risolvere il problema.

    1. Ho creato un custom BlobType estendere MaterializedBlobType e sovrascrivere il set e i metodi get con l’oid stile di accesso.

      public class CustomBlobType extends MaterializedBlobType {
      
      private static final String POSTGRESQL_DIALECT = PostgreSQLDialect.class.getName();
      
      /**
       * Currently set dialect.
       */
      private String dialect = hibernateConfiguration.getProperty(Environment.DIALECT);
      
      /*
       * (non-Javadoc)
       * @see org.hibernate.type.AbstractBynaryType#set(java.sql.PreparedStatement, java.lang.Object, int)
       */
      @Override
      public void set(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
          byte[] internalValue = toInternalFormat(value);
      
          if (POSTGRESQL_DIALECT.equals(dialect)) {
              try {
      
      //I had access to sessionFactory through a custom sessionFactory wrapper.
      st.setBlob(index, Hibernate.createBlob(internalValue, sessionFactory.getCurrentSession()));
                  } catch (SystemException e) {
                      throw new HibernateException(e);
                  }
              } else {
                  st.setBytes(index, internalValue);
              }
          }
      
      /*
       * (non-Javadoc)
       * @see org.hibernate.type.AbstractBynaryType#get(java.sql.ResultSet, java.lang.String)
       */
      @Override
      public Object get(ResultSet rs, String name) throws HibernateException, SQLException {
          Blob blob = rs.getBlob(name);
          if (rs.wasNull()) {
              return null;
          }
          int length = (int) blob.length();
          return toExternalFormat(blob.getBytes(1, length));
        }
      }
      1. Registrare il CustomBlobType con Hibernate. Di seguito è quello che ho fatto per raggiungere questo obiettivo.

        hibernateConfiguration= new AnnotationConfiguration();
        Mappings mappings = hibernateConfiguration.createMappings();
        mappings.addTypeDef("materialized_blob", "x.y.z.BlobType", null);

    OriginaleL’autore

Lascia un commento