适当的休眠注释byte [] [英] proper hibernate annotation for byte[]

查看:206
本文介绍了适当的休眠注释byte []的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用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;
}
}



我们不得不升级到3.5,当我们发现hibernate 3.5 打破(并且不会修复) postgresql中的此注释组合(没有解决方法) )。我还没有找到一个明确的修复,到目前为止,但我没有注意到,如果我只是删除@Lob,它使用postgresql类型bytea(它的工作原理,但只在postgres)。

 注释postgres oracle在
上工作---------------------------- ---------------------------------
byte [] + @Lob oid blob oracle
byte [] bytea raw(255)postgresql
byte [] + @Type(PBA)oid blob oracle
byte [] + @Type(BT)bytea blob postgresql

once你使用@Type,@ Lob似乎不相关
note:oracle似乎已经弃用了自8i以来的raw类型。

我正在寻找一种方法来获得一个单一的注释类




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




更新:
阅读这个博客我终于弄清楚了JIRA问题的原始解决方法是:显然你应该删除@Lob并将属性注释为:

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

> for me - 我仍然得到OID而不是bytea;



在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想要你使用Streams为bytea(不要问我为什么)和postgresql的自定义Blob类型为oids。还要注意,在JDBC上使用setBytes()也是bytea(从过去的经验)。所以这解释了为什么使用流不影响他们都假设'bytea'。

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

这会导致:

 错误:列签名的类型为oid,但表达式为bytea 

更新
下一个逻辑问题是:为什么不手动将表定义更改为bytea,并保留(@Lob +字节[])?这 有效, UNTIL 您尝试存储一个空字节[]。其中postgreSQL驱动程序认为是一个OID类型表达式,列类型是bytea - 这是因为hibernate(右)调用JDBC.setNull()而不是JDBC驱动程序期望的JDBC.setBytes(null)。

 错误:列签名类型为bytea,但表达式为oid类型

hibernate中的类型系统当前是一个正在进行中(根据3.5.5 deprecation注释)。事实上,这么多的3.5.5代码已经过时了,很难知道在对PostgreSQLDialect进行子类化时应该注意什么)。 postgresql上的AFAKT,Types.BLOB /'oid'应映射到一些使用OID样式JDBC访问(即PostgresqlBlobType对象和NOT MaterializedBlobType)的自定义类型。我从来没有成功地使用Blobs与postgresql,但我知道bytea只是简单地工作作为一个/我期望。



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






2004年的报价:
为了总结我的漫游,我会说他们应该等待对于JDBC驱动程序在更改Hibernate之前正确地执行LOB。



参考:




方案


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


这取决于你想要什么。 JPA可以持久保存非注释的 byte [] 。从JPA 2.0规格:


11.1.6基本注解



code>基本注释是映射到数据库列的最简单的
类型。
Basic 注释可以应用
到以下任何
类型的持久性属性或实例
变量:Java原始类型,
,原始类型,类型,包装器
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 [] ,枚举和任何其他实现 Serializable
类型。
如第2.8节所述, Basic 注释的
的使用是可选的
用于持久字段和属性
类型。如果没有为这样的
字段或属性指定Basic
注释,则将应用Basic注释的默认值


而Hibernate会将它默认映射到SQL VARBINARY (或SQL LONGVARBINARY 取决于 Column size?)PostgreSQL处理与 bytea



但是如果你想把 byte [] 存储在一个Large Object中,你应该使用 @Lob 。根据规范:


11.1.24 Lob注释



A Lob 注释指定
持久性属性或字段应为
作为大对象持久保存到
数据库支持的大对象类型。
当映射到
数据库时,便携式应用程序应使用
Lob 注释 Lob 类型。 Lob 注释
可以与
基本注释结合使用,或与
ElementCollection 注释,当
元素集合值是基本的
类型。 Lob 可以是二进制或
字符类型。 Lob 类型是根据
持久性字段或属性的类型推断的
,以及除字符串和字符类型之外的
类型
默认为Blob。


而Hibernate会将其映射到SQL BLOB PostgreSQL处理与 oid


在一些最近的版本的hibernate?


好吧,问题是我不知道什么问题是什么。但我至少可以说,自从3.5.x分支中3.5.0-Beta-2(这是已经改变了的地方)以来没有什么改变。



但是,我对 HHH-4876 HHH-4617 PostgreSQL和BLOBs (在 PostgreSQLDialect 的javadoc中提到)是你应该设置以下属性

  hibernate.jdbc.use_streams_for_binary = false 


code> byte <$ <$> $ <$> <$> $ b <$> @Lob (这是我的理解,因为 VARBINARY 不是你想要的与Oracle)。您尝试过吗?



另一种方法是, HHH-4876 建议使用弃用的 PrimitiveByteArrayBlobType 获取旧的行为(Hibernate 3.5之前)。



参考




  • JPA 2.0规格


    • 第2.8节映射非关系字段或属性的默认值

    • 第11.1.6节基本注释





资源




I have an application using hibernate 3.1 and JPA annotations. It has a few objects with byte[] attributes (1k - 200k in size). It uses the JPA @Lob annotation, and hibernate 3.1 can read these just fine on all major databases -- it seems to hide the JDBC Blob vendor peculiarities (as it should do).

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

We had to upgrade to 3.5, when we discovered that hibernate 3.5 breaks (and won't fix) this annotation combination in postgresql (with no workaround). I have not found a clear fix so far, but I did notice that if I just remove the @Lob, it uses the postgresql type bytea (which works, but only on 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.

I am looking for a way to have a single annotated class (with a blob property) which is portable across major databases.

  • What is the portable way to annotate a byte[] property?
  • Is this fixed in some recent version of hibernate?

Update: After reading this blog I have finally figured out what the original workaround in the JIRA issue was: Apparently you are supposed to drop @Lob and annotate the property as:

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

However, this does not work for me -- I still get OIDs instead of bytea; it did however work for the author of the JIRA issue, who seemed to want oid.

After the answer from A. Garcia, I then tried this combo, which actually does work on postgresql, but not on oracle.

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

What I really need to do is control which @org.hibernate.annotations.Type the combination (@Lob + byte[] gets mapped) to (on postgresql).


Here is the snippet from 3.5.5.Final from MaterializedBlobType (sql type Blob). According to Steve's blog, postgresql wants you to use Streams for bytea (don't ask me why) and postgresql's custom Blob type for oids. Note also that using setBytes() on JDBC is also for bytea (from past experience). So this explains why use-streams has no affect they both assume '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 );
 }
}

This results in:

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

Update The next logical question is: "why not just change the table definitions manually to bytea" and keep the (@Lob + byte[])? This does work, UNTIL you try to store a null byte[]. Which the postgreSQL driver thinks is an OID type expression and the column type is bytea -- this is because hibernate (rightly) calls JDBC.setNull() instead of JDBC.setBytes(null) which PG driver expects.

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

The type system in hibernate is currently a 'work in progress' (according to 3.5.5 deprecation comment). In fact so much of the 3.5.5 code is deprecated, it is hard to know what to look at when sub-classing the PostgreSQLDialect).

AFAKT, Types.BLOB/'oid' on postgresql should be mapped to some custom type which uses OID style JDBC access (i.e. PostgresqlBlobType object and NOT MaterializedBlobType). I've never actually successfully used Blobs with postgresql, but I do know that bytea just simply works as one / I would expect.

I am currently looking at the BatchUpdateException -- its possible that the driver doesn't support batching.


Great quote from 2004: "To sum up my ramblings, I'd say they we should wait for the JDBC driver to do LOBs properly before changing Hibernate."

References:

解决方案

What is the portable way to annotate a byte[] property?

It depends on what you want. JPA can persist a non annotated byte[]. From the JPA 2.0 spec:

11.1.6 Basic Annotation

The Basic annotation is the simplest type of mapping to a database column. The Basic annotation can be applied to a persistent property or instance variable of any of the following types: Java primitive, types, wrappers of the primitive types, 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[], enums, and any other type that implements Serializable. As described in Section 2.8, the use of the Basic annotation is optional for persistent fields and properties of these types. If the Basic annotation is not specified for such a field or property, the default values of the Basic annotation will apply.

And Hibernate will map a it "by default" to a SQL VARBINARY (or a SQL LONGVARBINARY depending on the Column size?) that PostgreSQL handles with a bytea.

But if you want the byte[] to be stored in a Large Object, you should use a @Lob. From the spec:

11.1.24 Lob Annotation

A Lob annotation specifies that a persistent property or field should be persisted as a large object to a database-supported large object type. Portable applications should use the Lob annotation when mapping to a database Lob type. The Lob annotation may be used in conjunction with the Basic annotation or with the ElementCollection annotation when the element collection value is of basic type. A Lob may be either a binary or character type. The Lob type is inferred from the type of the persistent field or property and, except for string and character types, defaults to Blob.

And Hibernate will map it to a SQL BLOB that PostgreSQL handles with a oid .

Is this fixed in some recent version of hibernate?

Well, the problem is that I don't know what the problem is exactly. But I can at least say that nothing has changed since 3.5.0-Beta-2 (which is where a changed has been introduced)in the 3.5.x branch.

But my understanding of issues like HHH-4876, HHH-4617 and of PostgreSQL and BLOBs (mentioned in the javadoc of the PostgreSQLDialect) is that you are supposed to set the following property

hibernate.jdbc.use_streams_for_binary=false

if you want to use oid i.e. byte[] with @Lob (which is my understanding since VARBINARY is not what you want with Oracle). Did you try this?

As an alternative, HHH-4876 suggests using the deprecated PrimitiveByteArrayBlobType to get the old behavior (pre Hibernate 3.5).

References

  • JPA 2.0 Specification
    • Section 2.8 "Mapping Defaults for Non-Relationship Fields or Properties"
    • Section 11.1.6 "Basic Annotation"
    • Section 11.1.24 "Lob Annotation"

Resources

这篇关于适当的休眠注释byte []的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆