J'ai une application utilisant Hibernate 3.1 et les annotations JPA. Elle contient quelques objets avec des attributs byte[] (taille de 1k à 200k). Elle utilise l'annotation JPA @Lob, et Hibernate 3.1 peut bien lire ces données sur toutes les bases de données principales -- il semble masquer les particularités des fournisseurs JDBC Blob (comme il se doit).
@Entity
public class ConfigAttribute {
@Lob
public byte[] getValueBuffer() {
return m_valueBuffer;
}
}
Nous avons dû passer à la version 3.5, quand nous avons découvert que Hibernate 3.5 casse (et ne répare pas) cette combinaison d'annotations dans postgresql (sans contournement). Je n'ai pas encore trouvé de solution claire jusqu'à présent, mais j'ai remarqué que si je supprime simplement le @Lob, il utilise le type postgresql bytea (qui fonctionne, mais seulement sur postgres).
annotation postgres oracle fonctionne sur
-------------------------------------------------------------
byte[] + @Lob oid blob oracle
byte[] bytea raw(255) postgresql
byte[] + @Type(PBA) oid blob oracle
byte[] + @Type(BT) bytea blob postgresql
une fois que vous utilisez @Type, @Lob semble ne plus être pertinent
note : oracle semble avoir déprécié le type "raw" depuis 8i.
Je cherche un moyen d'avoir une seule classe annotée (avec une propriété de blob) qui soit portable sur les bases de données principales.
- Quel est le moyen portable pour annoter une propriété byte[] ?
- Cela a-t-il été corrigé dans une version récente de Hibernate ?
Mise à jour : Après avoir lu ce blog, j'ai finalement compris quel était le contournement original dans l'issue JIRA : Apparemment, vous êtes censé supprimer @Lob et annoter la propriété comme suit :
@Type(type="org.hibernate.type.PrimitiveByteArrayBlobType")
byte[] getValueBuffer() {...
Cependant, cela ne fonctionne pas pour moi -- j'obtiens toujours des OID au lieu de bytea ; cependant, cela a fonctionné pour l'auteur de l'issue JIRA, qui semblait vouloir oid.
Après la réponse d'A. Garcia, j'ai donc essayé cette combinaison, qui fonctionne effectivement sur postgresql, mais pas sur oracle.
@Type(type="org.hibernate.type.BinaryType")
byte[] getValueBuffer() {...
Ce dont j'ai vraiment besoin de faire est de contrôler quel @org.hibernate.annotations.Type la combinaison (@Lob + byte[] est mappée) vers (sur postgresql).
Voici l'extrait de 3.5.5.Final de MaterializedBlobType (type sql Blob). Selon le blog de Steve, postgresql veut que vous utilisiez des flux pour bytea (ne me demandez pas pourquoi) et le type Blob personnalisé de postgresql pour les oid. Notez également que l'utilisation de setBytes() sur JDBC concerne également le bytea (d'après mon expérience passée). Cela explique pourquoi use-streams n'a aucun effet car ils supposent tous les deux '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 );
}
}
Cela donne :
ERREUR : la colonne "signature" est de type oid mais l'expression est de type bytea
Mise à jour La question logique suivante est : "pourquoi ne pas simplement changer manuellement les définitions de table en bytea" et conserver le (@Lob + byte[]) ? Cela fonctionne, JUSQU'À ce que vous essayiez de stocker un byte[] nul. Que le pilote postgreSQL considère comme une expression de type OID et que le type de colonne soit bytea -- ceci est dû au fait qu'hibernate (à juste titre) appelle JDBC.setNull() au lieu de JDBC.setBytes(null) comme attendu par le pilote PG.
ERREUR : la colonne "signature" est de type bytea mais l'expression est de type oid
Le système de types dans hibernate est actuellement un 'travail en cours' (selon le commentaire de dépréciation de 3.5.5). En fait, tellement de code de la version 3.5.5 est déprécié, qu'il est difficile de savoir à quoi il faut faire attention lors de la sous-classe de PostgreSQLDialect).
AFAKT, les types Types.BLOB/'oid' sur postgresql devraient être mappés vers un type personnalisé qui utilise un accès JDBC de style OID (c'est-à-dire un objet PostgresqlBlobType et PAS MaterializedBlobType). Je n'ai jamais réellement utilisé avec succès des Blobs avec postgresql, mais je sais que bytea fonctionne simplement comme prévu.
Je regarde actuellement l'exception BatchUpdateException -- il est possible que le pilote ne prenne pas en charge le mode batch.
Excellente citation de 2004 : "Pour résumer mes divagations, je dirais que nous devrions attendre que le pilote JDBC gère correctement les LOBs avant de modifier Hibernate."
Références :
- https://forum.hibernate.org/viewtopic.php?p=2393203
- https://forum.hibernate.org/viewtopic.php?p=2435174
- http://hibernate.atlassian.net/browse/HHH-4617
- http://postgresql.1045698.n5.nabble.com/Migration-to-Hibernate-3-5-final-td2175339.html
- https://jira.springframework.org/browse/SPR-2318
- https://forums.hibernate.org/viewtopic.php?p=2203382&sid=b526a17d9cf60a80f13d40cf8082aafd
- http://virgo47.wordpress.com/2008/06/13/jpa-postgresql-and-bytea-vs-oid-type/
0 votes
Cela semble avoir été corrigé dans 3.6, pas certain pour 3.5.6 ; la classe MaterializedBlobType a été totalement réécrite de 3.5.5 > 3.6. Le type OID fonctionne désormais depuis qu'ils ont changé l'implémentation.
0 votes
Bien ! Je me demande quel problème Jira suit cette réécriture, le cas échéant (peut-être que la réécriture est une conséquence d'un changement plus profond). Ce serait bien de rétroporter les modifications dans la version 3.5, si possible. Mauvaise nouvelle si ce n'est pas possible.
0 votes
En fait, mon test m'a donné un faux positif la première fois (je savais que j'aurais dû attendre!) - ce n'est toujours pas résolu, le bug s'est simplement déplacé vers BlobTypeDescriptor.
0 votes
Merci. @Type(type="org.hibernate.type.BinaryType") a fonctionné pour moi pour une table qui stocke des fichiers PDF. J'ai migré une base de données d'Oracle vers Postgres en utilisant Oracle-To-PostgreSQL de Intelligent Converters, et il a automatiquement converti et inséré de BLOB en BYTEA mais BlobType n'a pas fonctionné pour moi.
0 votes
Pas de plaisir pour nous qui avons besoin d'un mappage générique à utiliser pour plusieurs SGBDR... Je ne peux pas avoir un type cartographié pour SQLServer et un pour PostgrSQL