一尘不染

为byte []设置适当的休眠注释

hibernate

我有一个使用hibernate 3.1和JPA批注的应用程序。它有一些带有byte []属性的对象(大小为1k-200k)。它使用JPA
@Lob批注,并且hibernate 3.1可以在所有主要数据库上读取它们,这似乎隐藏了JDBC Blob供应商的特性(应该这样做)。

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

当我们发现hibernate3.5 破坏了(并且不会修复)
postgresql中的这个注释组合时(没有解决方法),我们不得不升级到3.5
。到目前为止,我还没有找到明确的修复程序,但是我确实注意到,如果我只是删除@Lob,它将使用postteasql类型bytea(该方法有效,但仅适用于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.

我正在寻找一种具有单个注释类(具有blob属性)的方法,该方法可跨主要数据库移植。

  • 注释byte []属性的可移植方式是什么?
  • 在某些最新的hibernate版本中已解决此问题吗?

更新:
阅读此博客后,我终于弄清楚JIRA问题中的原始解决方法是:显然,您应该删除@Lob并将其注释为:

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

但是,这 对我 不起作用-我仍然会获得OID而不是bytea。但是,它确实为JIRA问题的作者带来了帮助,他似乎想要oid。

在A. Garcia的回答之后,我然后尝试了这个组合,它实际上在postgresql上有效,但在oracle上不起作用。

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

我真正需要做的是控制@ org.hibernate.annotations.type组合(@Lob + byte
[]被映射)到(在postgresql上)。


这是MaterializedBlobType(SQL类型Blob)的3.5.5.Final版本的代码段。根据Steve的博客,postgresql希望您将流用于bytea(不要问我为什么),并将postgresql的自定义Blob类型用于oid。还请注意,在JDBC上使用setBytes()也可用于bytea(根据过去的经验)。因此,这解释了为什么使用流对它们都假定为“
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 );
 }
}

结果是:

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

更新 下一个逻辑问题是:“为什么不将表定义手动更改为bytea”并保留(@Lob + byte [])?这 确实 工作, UNTIL
你尝试存储空字节[]。postgreSQL驱动程序认为是OID类型表达式,列类型是bytea,这是因为hibernate(正确地)调用JDBC.setNull()而不是PG驱动程序期望的JDBC.setBytes(null)。

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

hibernate中的类型系统当前是一个“进行中的工作”(根据3.5.5弃用注释)。实际上,不赞成使用3.5.5的大部分代码,很难知道在对PostgreSQLDialect进行子类化时要看什么。

AFAKT,postgresql上的Types.BLOB
/’oid’应该映射到使用OID样式JDBC访问的某些自定义类型(即PostgresqlBlobType对象和NOT
MaterializedBlobType)。我从未真正将Blobs与postgresql一起成功使用,但是我确实知道bytea只是像我期望的那样工作。

我目前正在查看BatchUpdateException-驱动程序可能不支持批处理。


2004年的一句名言:“总结一下,我要说的是,在更改Hibernate之前,我们应该等待JDBC驱动程序正确执行LOB。”

参考文献:


阅读 282

收藏
2020-06-20

共1个答案

一尘不染

注释byte []属性的可移植方式是什么?

这取决于您想要什么。JPA可以保留未注释的内容byte[]。根据JPA 2.0规范:

11.1.6基本注释

Basic注释是映射到数据库列的最简单的类型。所述Basic注释可以应用于以下任何类型的持久性或实例变量:Java原始,类型,原始类型的包装,
java.lang.Stringjava.math.BigIntegerjava.math.BigDecimal
java.util.Datejava.util.Calendarjava.sql.Date
java.sql.Timejava.sql.Timestampbyte[]
Byte[]
char[]Character[],枚举,以及任何其他类型的器具Serializable。如2.8节所述,Basic对于这些类型的持久字段和属性,注释的使用是可选的。如果未为此类字段或属性指定基本注释,则将应用基本注释的默认值。

并且Hibernate会默认将它映射到PostgreSQL使用PostgreSQL处理的SQL
VARBINARY(或SQL是否LONGVARBINARY取决于Column大小?)bytea

但是,如果您希望将byte[]其存储在大对象中,则应使用@Lob。从规格:

11.1.24吊球注释

Lob注释指定持久性属性或字段应保持为一个大型对象到数据库支持的大对象类型。可移植应用程序Lob在映射到数据库Lob类型时应使用
注释。所述Lob注释可以与基本注释或与一起使用 ElementCollection的注释当元素集合值是基本类型。A
Lob可以是二进制或字符类型。Lob从持久字段或属性的类型推断出类型,并且,除了字符串和字符类型外,默认为Blob。

然后Hibernate会将其映射到BLOBPostgreSQL使用PostgreSQL处理的SQL oid

在某些最新的hibernate版本中已解决此问题吗?

好吧,问题是我不知道到底是什么问题。但是我至少可以说,自3.5.x分支中的3.5.0-Beta-2(已引入更改)以来,没有任何更改。

但是,我对HHH-4876HHH-4617以及PostgreSQL和BLOB(在的javadoc中提到
PostgreSQLDialect)等问题的理解是,您应该设置以下属性

hibernate.jdbc.use_streams_for_binary=false

如果您想使用oidie byte[]@Lob(这是我的理解,因为VARBINARY这不是您想要的Oracle)。你有尝试过吗?

作为替代方案,HHH-4876建议使用不推荐使用的方法PrimitiveByteArrayBlobType来获得旧的行为(Hibernate
3.5之前的版本)。

参考文献

  • JPA 2.0规范
    • 第2.8节“映射非关系字段或属性的默认值”
    • 第11.1.6节“基本注释”
    • 第11.1.24节“ Lob注释”

资源资源

2020-06-20