Jus*_*tin 110 java database postgresql hibernate blob
我有一个使用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).
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属性).
更新: 阅读此博客后,我终于弄明白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希望你使用Streams for 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 [])?这确实有效,直到您尝试存储空字节[].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进行子类化时应该注意什么.
postgresql上的AFAKT,Types.BLOB /'oid'应该映射到一些使用OID样式JDBC访问的自定义类型(即PostgresqlBlobType对象和NOT MaterializedBlobType).我从来没有真正成功地将blob用于postgresql,但我确实知道bytea只是简单地用作/我期望的那个.
我目前正在查看BatchUpdateException - 它可能是驱动程序不支持批处理.
2004年的精彩语句:"总结一下我的ramblings,我会说他们在更改Hibernate之前应该等待JDBC驱动程序正确地执行LOB."
参考文献:
Pas*_*ent 63
注释byte []属性的可移植方式是什么?
这取决于你想要什么.JPA可以持久保存未注释的内容byte[].从JPA 2.0规范:
11.1.6基本注释
的
Basic注释是映射到数据库列的最简单的类型.所述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对于持久字段和这些类型的属性,注释的使用是可选的.如果未为此类字段或属性指定基本注释,则将应用基本注释的默认值.
Hibernate会将它"默认"映射到PostgreSQL处理的SQL VARBINARY(或SQL,LONGVARBINARY具体取决于Column大小?)bytea.
但是如果你想将byte[]它存储在一个大对象中,你应该使用一个@Lob.从规格:
11.1.24 Lob注释
甲
Lob注释指定持久性属性或字段应保持为一个大型对象到数据库支持的大对象类型.Lob在映射到数据库Lob类型时,便携式应用程序应使用 注释.所述Lob注释可以结合使用与所述基本注释或与ElementCollection当所述元素集合值是基本类型的注释.ALob可以是二进制或字符类型.Lob类型是从持久字段或属性的类型推断出来的,除字符串和字符类型外,默认为Blob.
Hibernate会将它映射到BLOBPostgreSQL处理的SQL oid
.
这是在最近的一些hibernate版本中修复的吗?
好吧,问题是我不知道究竟是什么问题.但我至少可以说在3.5.x分支中3.5.0-Beta-2(这是已经引入更改的地方)之后没有任何变化.
但是我对HHH-4876,HHH-4617以及PostgreSQL和BLOBs(在javadoc中提到   PostgreSQLDialect)等问题的理解是你应该设置以下属性
hibernate.jdbc.use_streams_for_binary=false
如果你想使用oid即byte[]用@Lob(这是我的理解,因为VARBINARY不是你想要与甲骨文的).你试过这个吗?
作为替代方案,HHH-4876建议使用弃用PrimitiveByteArrayBlobType来获得旧行为(在Hibernate 3.5之前).
这就是O'reilly Enterprise JavaBeans,3.0所说的
JDBC对这些非常大的对象有特殊类型.java.sql.Blob类型表示二进制数据,java.sql.Clob表示字符数据.
这里是PostgreSQLDialect源代码
public PostgreSQLDialect() {
    super();
    ...
    registerColumnType(Types.VARBINARY, "bytea");
    /**
      * Notice it maps java.sql.Types.BLOB as oid
      */
    registerColumnType(Types.BLOB, "oid");
}
那么你可以做什么
重写PostgreSQLDialect如下
public class CustomPostgreSQLDialect extends PostgreSQLDialect {
    public CustomPostgreSQLDialect() {
        super();
        registerColumnType(Types.BLOB, "bytea");
    }
}
现在只需定义您的自定义方言
<property name="hibernate.dialect" value="br.com.ar.dialect.CustomPostgreSQLDialect"/>
并使用便携式JPA @Lob注释
@Lob
public byte[] getValueBuffer() {
UPDATE
这里已经提到了这里
我有一个在hibernate 3.3.2中运行的应用程序,应用程序工作正常,所有blob字段都使用oid(java中的byte [])
...
迁移到hibernate 3.5所有blob字段都不再起作用,服务器日志显示:ERROR org.hibernate.util.JDBCExceptionReporter - ERROR:列的类型为oid,但表达式的类型为bytea
这可以在 这里解释
这通常不是PG JDBC中的错误,而是改变了3.5版本中Hibernate的默认实现.在我的情况下设置连接上的兼容属性没有帮助.
...
更多我在3.5 - beta 2中看到的,我不知道这是否已修复是Hibernate - 没有@Type注释 - 将自动创建类型为oid的列,但会尝试将其读作bytea
有趣的是因为当他将Types.BOLB映射为bytea(参见CustomPostgreSQLDialect)时,他得到了
无法执行JDBC批量更新
插入或更新时
我正在将Hibernate 4.2.7.SP1与Postgres 9.3配合使用,并且对我有用:
@Entity
public class ConfigAttribute {
  @Lob
  public byte[] getValueBuffer() {
    return m_valueBuffer;
  }
}
因为Oracle对此没有问题,对于Postgres,我使用的是自定义方言:
public class PostgreSQLDialectCustom extends PostgreSQL82Dialect {
    @Override
    public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
    if (sqlTypeDescriptor.getSqlType() == java.sql.Types.BLOB) {
      return BinaryTypeDescriptor.INSTANCE;
    }
    return super.remapSqlTypeDescriptor(sqlTypeDescriptor);
  }
}
我认为这种解决方案的优势在于,可以保持休眠状态。
有关Hibernate与Postgres / Oracle的更多兼容性问题,请参阅我的博客文章。
我终于有了这个工作.它扩展了A. Garcia的解决方案,但是,由于问题在于hibernate类型MaterializedBlob类型只是映射Blob> bytea是不够的,我们需要替换MaterializedBlobType,它适用于hibernates破碎的blob支持.这个实现只适用于bytea,但是想要OID的JIRA问题的人可能会提供OID实现.
遗憾的是,在运行时替换这些类型是一件痛苦的事,因为它们应该是Dialect的一部分.如果只有这个JIRA enhanement进入3.6就有可能.
public class PostgresqlMateralizedBlobType extends AbstractSingleColumnStandardBasicType<byte[]> {
 public static final PostgresqlMateralizedBlobType INSTANCE = new PostgresqlMateralizedBlobType();
 public PostgresqlMateralizedBlobType() {
  super( PostgresqlBlobTypeDescriptor.INSTANCE, PrimitiveByteArrayTypeDescriptor.INSTANCE );
 }
  public String getName() {
   return "materialized_blob";
  }
}
其中大部分都可能是静态的(getBinder()确实需要一个新实例吗?),但我并不真正理解hibernate内部所以这主要是复制+粘贴+修改.
public class PostgresqlBlobTypeDescriptor extends BlobTypeDescriptor implements SqlTypeDescriptor {
  public static final BlobTypeDescriptor INSTANCE = new PostgresqlBlobTypeDescriptor();
  public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
   return new PostgresqlBlobBinder<X>(javaTypeDescriptor, this);
  }
  public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
   return new BasicExtractor<X>( javaTypeDescriptor, this ) {
    protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { 
      return (X)rs.getBytes(name);
    }
   };
  }
}
public class PostgresqlBlobBinder<J> implements ValueBinder<J> {
 private final JavaTypeDescriptor<J> javaDescriptor;
 private final SqlTypeDescriptor sqlDescriptor;
 public PostgresqlBlobBinder(JavaTypeDescriptor<J> javaDescriptor, SqlTypeDescriptor sqlDescriptor) { 
  this.javaDescriptor = javaDescriptor; this.sqlDescriptor = sqlDescriptor;
 }  
 ...
 public final void bind(PreparedStatement st, J value, int index, WrapperOptions options) 
 throws SQLException {
  st.setBytes(index, (byte[])value);
 }
}
小智 5
我通过添加 @Lob 的注释来解决我的问题,该注释将在 oracle 中创建 byte[] 为 blob,但此注释会将字段创建为 oid 无法正常工作,为了使 byte[] 创建为 bytea,我创建了客户方言postgres 如下
Public class PostgreSQLDialectCustom extends PostgreSQL82Dialect {
    public PostgreSQLDialectCustom() {
        System.out.println("Init PostgreSQLDialectCustom");
        registerColumnType( Types.BLOB, "bytea" );
      }
    @Override
    public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
    if (sqlTypeDescriptor.getSqlType() == java.sql.Types.BLOB) {
      return BinaryTypeDescriptor.INSTANCE;
    }
    return super.remapSqlTypeDescriptor(sqlTypeDescriptor);
  }
 }
还需要覆盖方言的参数
spring.jpa.properties.hibernate.dialect=com.ntg.common.DBCompatibilityHelper.PostgreSQLDialectCustom
更多提示可以找到她:https : //dzone.com/articles/postgres-and-oracle
| 归档时间: | 
 | 
| 查看次数: | 93400 次 | 
| 最近记录: |