我的应用程序使用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;
}
}
我们发现在postgresql中使用这个注解组合时,hibernate 3.5 会破坏(且不会修复),因此我们不得不升级到3.5版本。目前我还没有找到明确的解决方案,但我注意到如果我只是删除@Lob注解,它会使用postgresql类型bytea(在postgresql上可以工作,但在其他数据库上可能有问题)。
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类型处理oids。请注意,在JDBC上使用setBytes()也适用于bytea(来自以往的经验)。因此,这就解释了为什么使用use-streams没有影响,它们都假定“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[])?”这确实可以工作,直到您尝试存储null byte[]。这时postgreSQL驱动程序会认为这是OID类型表达式,而列类型是bytea--这是因为Hibernate(正确地)调用JDBC.setNull()而不是JDBC.setBytes(null),这是PG驱动程序期望的。
ERROR: column "signature" is of type bytea but expression is of type oid
据3.5.5版本的弃用注释,Hibernate中的类型系统目前仍处于“正在进行中”的状态。实际上,3.5.5代码中有很多已过时的内容,因此在子类化PostgreSQLDialect时很难知道该看哪些内容。
根据我的了解,postgresql上的Types.BLOB/'oid'应该映射到某个自定义类型,该类型使用OID样式的JDBC访问(即PostgresqlBlobType对象而不是MaterializedBlobType对象)。我从未真正成功地使用过postgresql上的Blobs,但我确实知道bytea可以像一个Blobs一样简单地工作/产生预期的效果。
我目前正在研究BatchUpdateException——可能是驱动程序不支持批处理。
2004年的一句重要引述:
“总结我的废话,我想说,在Hibernate进行更改之前,我们应该等待JDBC驱动程序正确处理LOBS。”
参考资料:
- 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/