Tengo una aplicación que usa hibernate 3.1 y anotaciones JPA. Tiene algunos objetos con atributos de byte [] (1k - 200k de tamaño). Utiliza la anotación JPA @Lob, e hibernate 3.1 puede leerlos perfectamente en todas las bases de datos principales; parece ocultar las peculiaridades del proveedor de JDBC Blob (como debería hacer).
@Entity
public class ConfigAttribute {
@Lob
public byte[] getValueBuffer() {
return m_valueBuffer;
}
}
Tuvimos que actualizar a 3.5, cuando descubrimos que hibernate 3.5 rompe (y no arregla) esta combinación de anotaciones en postgresql (sin solución alternativa). No he encontrado una solución clara hasta ahora, pero noté que si simplemente elimino el @Lob, usa el tipo bytea de postgresql (que funciona, pero solo en 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.
Estoy buscando una forma de tener una sola clase anotada (con una propiedad de blob) que sea portátil en las principales bases de datos.
- ¿Cuál es la forma portátil de anotar una propiedad de byte []?
- ¿Está esto arreglado en alguna versión reciente de hibernate?
Actualización: Después de leer este blog , finalmente descubrí cuál era la solución original en el problema de JIRA: Aparentemente, se supone que debes soltar @Lob y anotar la propiedad como:
@Type(type="org.hibernate.type.PrimitiveByteArrayBlobType")
byte[] getValueBuffer() {...
Sin embargo, esto no funciona para mí , todavía obtengo OID en lugar de bytea; Sin embargo, funcionó para el autor de la edición de la JIRA, que parecía querer oid.
Después de la respuesta de A. García, probé este combo, que en realidad funciona en postgresql, pero no en Oracle.
@Type(type="org.hibernate.type.BinaryType")
byte[] getValueBuffer() {...
Lo que realmente necesito hacer es controlar qué @ org.hibernate.annotations. Escriba la combinación (@Lob + byte [] se asigna) a (en postgresql).
Aquí está el fragmento de 3.5.5.Final de MaterializedBlobType (Blob de tipo SQL). Según el blog de Steve, postgresql quiere que uses Streams para bytea (no me preguntes por qué) y el tipo de blob personalizado de postgresql para oids. Tenga en cuenta también que el uso de setBytes () en JDBC también es para bytea (de experiencias pasadas). Entonces, esto explica por qué los flujos de uso no tienen ningún efecto, ambos asumen '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 );
}
}
Esto resulta en:
ERROR: column "signature" is of type oid but expression is of type bytea
Actualización La siguiente pregunta lógica es: "¿por qué no cambiar las definiciones de la tabla manualmente a bytea" y mantener el (@Lob + byte [])? Esto hace el trabajo, HASTA intenta almacenar un byte nulo []. Lo que el controlador postgreSQL cree que es una expresión de tipo OID y el tipo de columna es bytea; esto se debe a que hibernate (correctamente) llama a JDBC.setNull () en lugar de JDBC.setBytes (nulo) que espera el controlador PG.
ERROR: column "signature" is of type bytea but expression is of type oid
El sistema de tipos en hibernación es actualmente un 'trabajo en progreso' (según el comentario de desaprobación 3.5.5). De hecho, gran parte del código 3.5.5 está desaprobado, es difícil saber qué mirar al subclasificar PostgreSQLDialect).
AFAKT, Types.BLOB / 'oid' en postgresql debe asignarse a algún tipo personalizado que utilice acceso JDBC de estilo OID (es decir, objeto PostgresqlBlobType y NO MaterializedBlobType). En realidad, nunca usé Blobs con éxito con postgresql, pero sé que bytea simplemente funciona como uno / esperaría.
Actualmente estoy viendo la BatchUpdateException; es posible que el controlador no admita el procesamiento por lotes.
Gran cita de 2004: "Para resumir mis divagaciones, diría que deberíamos esperar a que el controlador JDBC realice las LOB correctamente antes de cambiar Hibernate".
Referencias:
- 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/
Respuestas:
Depende de lo que quieras. JPA puede conservar un archivo
byte[]
. De la especificación JPA 2.0:E Hibernate lo mapeará "por defecto" a un SQL
VARBINARY
(¿o un SQLLONGVARBINARY
dependiendo delColumn
tamaño?) Que PostgreSQL maneja con unbytea
.Pero si desea
byte[]
que se almacene en un objeto grande, debe usar un@Lob
. De la especificación:E Hibernate lo asignará a un SQL
BLOB
que PostgreSQL maneja con unoid
.Bueno, el problema es que no sé cuál es exactamente el problema. Pero al menos puedo decir que nada ha cambiado desde 3.5.0-Beta-2 (que es donde se introdujo un cambio) en la rama 3.5.x.
Pero mi comprensión de problemas como HHH-4876 , HHH-4617 y de PostgreSQL y BLOB (mencionados en el javadoc del
PostgreSQLDialect
) es que se supone que debe establecer la siguiente propiedadsi desea usar
oid
iebyte[]
con@Lob
(lo que tengo entendido, yaVARBINARY
que no es lo que desea con Oracle). ¿Intentaste esto?Como alternativa, HHH-4876 sugiere usar el obsoleto
PrimitiveByteArrayBlobType
para obtener el comportamiento anterior (pre Hibernate 3.5).Referencias
Recursos
fuente
hibernate.jdbc.use_streams_for_binary=false
también? (voy a comprobar lo que dijo Steve ahora).Aquí va lo que dice O'reilly Enterprise JavaBeans, 3.0
Aquí va el código fuente de PostgreSQLDialect
Entonces que puedes hacer
Anule PostgreSQLDialect de la siguiente manera
Ahora solo define tu dialecto personalizado
Y use su anotación JPA @Lob portátil
ACTUALIZAR
Aquí se ha extraído aquí
...
que se puede explicar aquí
...
Es interesante porque cuando asigna Types.BOLB como bytea (Ver CustomPostgreSQLDialect) Obtiene
al insertar o actualizar
fuente
Estoy usando Hibernate 4.2.7.SP1 con Postgres 9.3 y lo siguiente funciona para mí:
ya que Oracle no tiene problemas con eso, y para Postgres estoy usando un dialecto personalizado:
La ventaja de esta solución que considero es que puedo mantener intactos los frascos de hibernación.
Para más problemas de compatibilidad de Postgres / Oracle con Hibernate, consulte la publicación de mi blog .
fuente
Finalmente he conseguido que esto funcione. Sin embargo, amplía la solución de A. García, ya que el problema radica en el tipo de hibernación MaterializedBlob, solo mapear Blob> bytea no es suficiente, necesitamos un reemplazo para MaterializedBlobType que funciona con soporte de blob roto en hibernación. Esta implementación solo funciona con bytea, pero tal vez el tipo del problema de JIRA que quería OID podría contribuir con una implementación de OID.
Lamentablemente, reemplazar estos tipos en tiempo de ejecución es una molestia, ya que deberían ser parte del dialecto. Si solo esta mejora de JIRA llegara a 3.6, sería posible.
Gran parte de esto probablemente podría ser estático (¿getBinder () realmente necesita una nueva instancia?), Pero realmente no entiendo la hibernación interna, por lo que esto es principalmente copiar + pegar + modificar.
fuente
solucioné Mi problema agregando la anotación de @Lob que creará el byte [] en Oracle como blob, pero esta anotación creará el campo como oid que no funciona correctamente. Para hacer que el byte [] sea creado como bytea, hice el dialecto del cliente para postgres como abajo
También es necesario anular el parámetro para el dialecto
spring.jpa.properties.hibernate.dialect = com.ntg.common.DBCompatibilityHelper.PostgreSQLDialectCustom
se puede encontrar más pista en ella: https://dzone.com/articles/postgres-and-oracle
fuente
Lo conseguí al anular la anotación con el archivo XML para Postgres. La anotación se mantiene para Oracle. En mi opinión, en este caso sería mejor que anulemos el mapeo de esta enidad problemática con el mapeo xml. Podemos anular entidades únicas / múltiples con mapeo xml. Por lo tanto, usaríamos anotaciones para nuestra base de datos con soporte principal y un archivo xml para cada otra base de datos.
Nota: solo necesitamos anular una sola clase, por lo que no es un gran problema. Leer más de mi ejemplo Ejemplo para anular la anotación con XML
fuente
En Postgres @Lob se rompe para el byte [] mientras intenta guardarlo como oid, y para String también ocurre el mismo problema. El siguiente código se está rompiendo en postgres, que funciona bien en Oracle.
y
Para arreglar lo anterior en postgres, he escrito a continuación hibernate.dialect personalizado
Ahora configure el dialecto personalizado en hibernación
XYZ es el nombre del paquete.
Ahora funciona bien. NOTA- Mi versión de Hibernate - 5.2.8.Versión final de Postgres- 9.6.3
fuente
Gracias Justin, Pascal por guiarme en la dirección correcta. También me enfrentaba al mismo problema con Hibernate 3.5.3. Su investigación y sus sugerencias sobre las clases adecuadas me ayudaron a identificar el problema y solucionarlo.
Para el beneficio de aquellos que todavía están atascados con Hibernate 3.5 y usando la combinación oid + byte [] + @LoB, lo siguiente es lo que he hecho para solucionar el problema.
Creé un BlobType personalizado que extendía MaterializedBlobType y anulaba el conjunto y los métodos de obtención con el acceso al estilo oid.
Registre CustomBlobType con Hibernate. Lo siguiente es lo que hice para lograrlo.
fuente