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 プロパティ付き) を作成する方法を探しています。
- byte[] プロパティに注釈を付けるポータブルな方法は何ですか?
- これは最近のバージョンの Hibernate で修正されていますか?
アップデート:読んだあとこのブログようやく、JIRA の問題における元の回避策が何であったかがわかりました。どうやら、@Lob を削除して、プロパティに次のように注釈を付けることになっているようです。
@Type(type="org.hibernate.type.PrimitiveByteArrayBlobType")
byte[] getValueBuffer() {...
しかし、これはうまくいかない私にとって-- 私はまだ bytea ではなく OID を取得します。ただし、JIRA の問題の作成者にとっては機能しました。作成者は oid を望んでいたようです。
A. Garcia からの回答の後、私はこの組み合わせを試してみましたが、これは実際には postgresql では機能しますが、oracle では機能しません。
@Type(type="org.hibernate.type.BinaryType")
byte[] getValueBuffer() {...
本当に必要なのは、組み合わせ (@Lob + byte[]) がどの @org.hibernate.annotations.Type にマップされるかを制御することです (postgresql の場合)。
以下は、MaterializedBlobType (SQL 型 Blob) の 3.5.5.Final からの抜粋です。Steve のブログによると、postgresql では bytea に Streams を使用し (理由は聞かないでください)、oid に postgresql のカスタム Blob 型を使用するように求められています。また、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 です。これは、PG ドライバが期待する JDBC.setBytes(null) ではなく、hibernate が (正しく) JDBC.setNull() を呼び出すためです。
ERROR: column "signature" is of type bytea but expression is of type oid
Hibernate の型システムは現在「進行中」です (3.5.5 の非推奨コメントによると)。実際、3.5.5 のコードの多くは非推奨になっているため、PostgreSQLDialect をサブクラス化するときに何を確認すればよいかがわかりにくいです。
私の知る限り、postgresql の Types.BLOB/'oid' は、OID スタイルの JDBC アクセスを使用するカスタム タイプ (つまり、PostgresqlBlobType オブジェクトであり、MaterializedBlobType ではありません) にマップされる必要があります。私は実際に postgresql で Blob をうまく使用したことはありませんが、bytea が単純に Blob として機能し、期待どおりに機能することは知っています。
現在、BatchUpdateException を確認中です。ドライバーがバッチ処理をサポートしていない可能性があります。
2004 年の素晴らしい引用: 「私の長々とした意見をまとめると、Hibernate を変更する前に、JDBC ドライバーが LOB を適切に実行できるようになるまで待つべきだということです。」
参考文献:
- 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
- 参考文献
- http://virgo47.wordpress.com/2008/06/13/jpa-postgresql-and-bytea-vs-oid-type/
ベストアンサー1
byte[] プロパティに注釈を付けるポータブルな方法は何ですか?
それはあなたが何を望んでいるかによります。JPA は注釈のない を永続化できますbyte[]
。JPA 2.0 仕様から:
11.1.6 基本的な注釈
アノテーションは、
Basic
データベース列へのマッピングの最も単純なタイプです。アノテーションは、Javaプリミティブ、型、プリミティブ型のラッパー、、、、、、、、、、のいずれかの型の永続プロパティまたはインスタンス変数にBasic
適用できます。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[]
、、列挙型、および を実装するその他の型。セクション 2.8 で説明したように、これらの型char[]
の永続フィールドとプロパティでは、アノテーションの使用はオプションです。このようなフィールドまたはプロパティに Basic アノテーションが指定されていない場合は、Basic アノテーションのデフォルト値が適用されます。Character[]
Serializable
Basic
そして、Hibernate はそれを「デフォルトで」PostgreSQL が で処理する SQL (またはサイズによってはVARBINARY
SQL ?) にマップします。LONGVARBINARY
Column
bytea
しかし、 をbyte[]
ラージ オブジェクトに格納したい場合は、 を使用する必要があります@Lob
。仕様から引用します。
11.1.24 ロブ注釈
注釈
Lob
は、永続的なプロパティまたはフィールドを、データベースでサポートされているラージ オブジェクト タイプにラージ オブジェクトとして永続化することを指定します。ポータブル アプリケーションでは、Lob
データベースLob
タイプにマッピングするときに注釈を使用する必要があります。Lob
注釈は、Basic 注釈と組み合わせて使用することも、ElementCollection
要素コレクション値が基本タイプである場合に注釈と組み合わせて使用することもできます。注釈は、Lob
バイナリ タイプまたは文字タイプのいずれかですLob
。タイプは永続的なフィールドまたはプロパティのタイプから推論され、文字列タイプと文字タイプを除き、デフォルトで Blob になります。
BLOB
そして、Hibernate はそれをPostgreSQL が で処理するSQL にマッピングしますoid
。
これは最近のバージョンの Hibernate で修正されていますか?
まあ、問題は、問題が正確に何なのか私には分からないということです。しかし、少なくとも、3.5.x ブランチでは、3.5.0-Beta-2 (変更が導入された場所) 以降何も変わっていないと言えます。
しかし、私の理解では、HHH-4876、HHH-4617そしてのPostgreSQL と BLOB(のjavadocに記載されているPostgreSQLDialect
)次のプロパティを設定する必要があります。
hibernate.jdbc.use_streams_for_binary=false
oid
iebyte[]
を使用したい場合(これはOracle で必要なことではない@Lob
と理解しています)。これを試しましたか?VARBINARY
代わりに、HHH-4876PrimitiveByteArrayBlobType
古い動作 (Hibernate 3.5 より前) を取得するには、非推奨の使用をお勧めします。
参考文献
- JPA 2.0 仕様
- セクション 2.8「非リレーションシップ フィールドまたはプロパティのマッピングのデフォルト」
- セクション 11.1.6「基本的な注釈」
- セクション 11.1.24「Lob 注釈」