คำอธิบายประกอบไฮเบอร์เนตที่เหมาะสมสำหรับไบต์ []


120

ฉันมีแอปพลิเคชันที่ใช้คำอธิบายประกอบไฮเบอร์เนต 3.1 และ JPA มีออบเจ็กต์สองสามรายการที่มีแอตทริบิวต์ไบต์ [] (ขนาด 1k - 200k) มันใช้คำอธิบายประกอบ JPA @Lob และ hibernate 3.1 สามารถอ่านสิ่งเหล่านี้ได้ดีในฐานข้อมูลหลักทั้งหมด - ดูเหมือนว่าจะซ่อนลักษณะเฉพาะของผู้ขาย JDBC Blob (ตามที่ควรทำ)

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

เราต้องอัปเกรดเป็น 3.5 เมื่อเราพบว่าไฮเบอร์เนต 3.5 หยุดพัก (และจะไม่แก้ไข)ชุดคำอธิบายประกอบนี้ใน postgresql (โดยไม่มีวิธีแก้ปัญหา) ฉันยังไม่พบการแก้ไขที่ชัดเจน แต่ฉันสังเกตเห็นว่าถ้าฉันเพิ่งลบ @Lob ออกมันจะใช้ไบต์ประเภท postgresql (ซึ่งใช้ได้ แต่เฉพาะใน 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.

ฉันกำลังมองหาวิธีที่จะมีคลาสคำอธิบายประกอบเดียว (ที่มีคุณสมบัติหยด) ซึ่งสามารถพกพาได้ในฐานข้อมูลหลัก ๆ

  • วิธีแบบพกพาในการใส่คำอธิบายประกอบคุณสมบัติไบต์ [] คืออะไร?
  • สิ่งนี้ได้รับการแก้ไขในโหมดไฮเบอร์เนตเวอร์ชันล่าสุดหรือไม่

อัปเดต: หลังจากอ่านบล็อกนี้ในที่สุดฉันก็พบว่าวิธีแก้ปัญหาดั้งเดิมในปัญหา JIRA คืออะไร: เห็นได้ชัดว่าคุณควรวาง @Lob และใส่คำอธิบายประกอบคุณสมบัติเป็น:

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

อย่างไรก็ตามสิ่งนี้ใช้ไม่ได้สำหรับฉัน - ฉันยังคงได้รับ OIDs แทน bytea อย่างไรก็ตามมันใช้งานได้กับผู้เขียนปัญหา JIRA ซึ่งดูเหมือนจะต้องการ oid

หลังจากคำตอบจากอ.

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

สิ่งที่ต้องทำจริงๆคือควบคุม @ org.hibernate.annotations อันไหนพิมพ์ชุดค่าผสม (@Lob + byte [] ได้รับการแมป) เป็น (บน postgresql)


นี่คือตัวอย่างจาก 3.5.5 สุดท้ายจาก MaterializedBlobType (sql type Blob) ตามบล็อกของ Steve postgresql ต้องการให้คุณใช้ Streams สำหรับ bytea (อย่าถามฉันว่าทำไม) และประเภท Blob ที่กำหนดเองของ postgresql สำหรับ oids โปรดทราบด้วยว่าการใช้ setBytes () บน JDBC นั้นใช้สำหรับ bytea (จากประสบการณ์ที่ผ่านมา) ดังนั้นสิ่งนี้จึงอธิบายได้ว่าเหตุใด use-stream จึงไม่มีผลต่อทั้งคู่ถือว่าเป็น '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 () แทน JDBC.setBytes (null) ซึ่งไดรเวอร์ PG คาดหวัง

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

ขณะนี้ระบบประเภทอยู่ในโหมดไฮเบอร์เนตเป็น "งานที่อยู่ระหว่างดำเนินการ" (ตามความคิดเห็นเกี่ยวกับการเลิกใช้งาน 3.5.5) ในความเป็นจริงแล้วโค้ด 3.5.5 จำนวนมากเลิกใช้งานแล้วจึงยากที่จะทราบว่าจะต้องดูอะไรเมื่อจัดคลาสย่อยของ PostgreSQLDialect)

AFAKT, types.BLOB / 'oid' บน postgresql ควรแมปกับประเภทที่กำหนดเองบางประเภทซึ่งใช้การเข้าถึง JDBC สไตล์ OID (เช่นวัตถุ PostgresqlBlobType และไม่ใช่ MaterializedBlobType) ฉันไม่เคยใช้ Blobs กับ postgresql ได้สำเร็จเลย แต่ฉันรู้ว่า bytea ใช้งานได้ตามที่ฉันคาดหวัง

ขณะนี้ฉันกำลังดู BatchUpdateException - อาจเป็นไปได้ว่าไดรเวอร์ไม่รองรับการทำแบตช์


คำพูดที่ยอดเยี่ยมจากปี 2004: "เพื่อสรุปความวุ่นวายของฉันฉันบอกว่าพวกเขาควรรอให้ไดรเวอร์ JDBC ทำการ LOB อย่างถูกต้องก่อนที่จะเปลี่ยน Hibernate"

อ้างอิง:


ดูเหมือนว่าจะได้รับการแก้ไขใน 3.6 ไม่แน่ใจเกี่ยวกับ 3.5.6; คลาส MaterializedBlobType ถูกเขียนใหม่ทั้งหมดจาก 3.5.5> 3.6 ขณะนี้ประเภท OID ใช้งานได้ตั้งแต่เปลี่ยนการใช้งาน
จัสติน

ดี! ฉันสงสัยว่า Jira มีปัญหาอะไรในการติดตามการเขียนซ้ำนี้ถ้ามี (การเขียนซ้ำอาจเป็นผลมาจากการเปลี่ยนแปลงที่ลึกกว่า) จะเป็นการดีที่จะย้อนกลับการเปลี่ยนแปลงใน 3.5 ถ้าเป็นไปได้ ข่าวร้ายหากไม่สามารถทำได้
Pascal Thivent

อันที่จริงการทดสอบของฉันให้ผลบวกที่ผิดพลาดเป็นครั้งแรก (รู้ว่าฉันควรรอ!) - ยังไม่ได้รับการแก้ไขข้อบกพร่องเพิ่งย้ายไปที่ BlobTypeDescriptor
จัสติน

ขอบคุณ @Type (type = "org.hibernate.type.BinaryType") ทำงานให้ฉันสำหรับตารางที่จัดเก็บไฟล์ PDF ฉันย้ายฐานข้อมูลจาก Oracle ไปยัง Postgres โดยใช้ Oracle-To-PostgreSQL จาก Intelligent Converters และมันจะแปลงและแทรกโดยอัตโนมัติจาก BLOB เป็น BYTEA แต่ BlobType ไม่ได้ผลสำหรับฉัน
jmoran

คำตอบ:


68

วิธีแบบพกพาในการใส่คำอธิบายประกอบคุณสมบัติไบต์ [] คืออะไร?

มันขึ้นอยู่กับสิ่งที่คุณต้องการ 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[], enums และประเภทอื่น ๆ ที่ดำเนินการSerializable. ตามที่อธิบายไว้ในส่วนที่ 2.8 การใช้Basicคำอธิบายประกอบเป็นทางเลือกสำหรับฟิลด์และคุณสมบัติถาวรของประเภทเหล่านี้ หากไม่ได้ระบุคำอธิบายประกอบพื้นฐานสำหรับฟิลด์หรือคุณสมบัติดังกล่าวจะใช้ค่าเริ่มต้นของคำอธิบายประกอบพื้นฐาน

และ Hibernate จะแมป "โดยค่าเริ่มต้น" กับ SQL VARBINARY(หรือ SQL LONGVARBINARYขึ้นอยู่กับColumnขนาด?) ที่ PostgreSQL จัดการกับไฟล์bytea.

แต่ถ้าคุณต้องการbyte[]เก็บไว้ใน Large Object คุณควรใช้ไฟล์@Lob. จากข้อมูลจำเพาะ:

11.1.24 Lob Annotation

Lobคำอธิบายประกอบระบุว่าทรัพย์สินถาวรหรือสาขาที่ควรได้รับการยืนยันว่าเป็นวัตถุขนาดใหญ่ไปยังฐานข้อมูลสนับสนุนประเภทวัตถุขนาดใหญ่ แอปพลิเคชันแบบพกพาควรใช้ Lobคำอธิบายประกอบเมื่อแมปกับLobประเภทฐานข้อมูล Lobคำอธิบายประกอบอาจถูกนำมาใช้ร่วมกับคำอธิบายประกอบพื้นฐานหรือมี ElementCollectionคำอธิบายประกอบเมื่อค่าคอลเลกชันองค์ประกอบเป็นประเภทพื้นฐาน A Lobอาจเป็นประเภทไบนารีหรืออักขระก็ได้ Lobประเภทอนุมานจากชนิดของข้อมูลแบบถาวรหรือทรัพย์สินและยกเว้นสำหรับสตริงและตัวอักษรชนิดเริ่มต้นที่หยด

และ Hibernate จะแมปกับ SQL BLOBที่ PostgreSQL จัดการด้วยไฟล์oid .

สิ่งนี้ได้รับการแก้ไขในโหมดไฮเบอร์เนตเวอร์ชันล่าสุดหรือไม่

ปัญหาคือฉันไม่รู้ว่าปัญหาคืออะไรกันแน่ แต่อย่างน้อยฉันสามารถพูดได้ว่าไม่มีอะไรเปลี่ยนแปลงตั้งแต่ 3.5.0-Beta-2 (ซึ่งเป็นจุดที่มีการเปลี่ยนแปลง) ในสาขา 3.5.x

แต่ความเข้าใจของฉันเกี่ยวกับปัญหาเช่นHHH-4876 , HHH-4617และของPostgreSQL และ BLOBs (กล่าวถึงใน javadoc ของ PostgreSQLDialect) คือคุณควรตั้งค่าคุณสมบัติต่อไปนี้

hibernate.jdbc.use_streams_for_binary=false

หากคุณต้องการใช้oidie byte[]กับ@Lob(ซึ่งเป็นความเข้าใจของฉันเนื่องจากVARBINARYไม่ใช่สิ่งที่คุณต้องการกับ Oracle) ลองทำดูไหม

อีกทางเลือกหนึ่งคือHHH-4876แนะนำให้ใช้การเลิกใช้PrimitiveByteArrayBlobTypeเพื่อให้ได้พฤติกรรมเก่า (ก่อนไฮเบอร์เนต 3.5)

อ้างอิง

  • ข้อกำหนด JPA 2.0
    • ส่วนที่ 2.8 "ค่าเริ่มต้นการแม็ปสำหรับฟิลด์หรือคุณสมบัติที่ไม่เกี่ยวข้อง"
    • ส่วน 11.1.6 "คำอธิบายประกอบพื้นฐาน"
    • ส่วน 11.1.24 "Lob Annotation"

ทรัพยากร


OMG ฉันรู้ว่าคำถามนี้เปลี่ยนไปมากตั้งแต่ฉันเริ่มตอบ จะอ่านการเปลี่ยนแปลงทั้งหมดในภายหลังและอัปเดตคำตอบของฉันหลังจากย่อยการเปลี่ยนแปลงหากจำเป็น
Pascal Thivent

เป็นการดีที่จะเห็นข้อมูลจำเพาะดังนั้นการไฮเบอร์เนตจึงถูกต้องโดยสิ้นเชิงในการแมป (@Lob + byte []) กับประเภทวัตถุขนาดใหญ่ที่รองรับ ใน Postgresql มี 2 (bytea หรือ oid) อย่างไรก็ตามในขณะที่ไฮเบอร์เนต 3.5 แม็พเป็น oid (โดยค่าเริ่มต้น) จะอ่านโดยใช้ JDBC getBytes () ซึ่งไดรเวอร์ PGSQL จะส่งคืน oid 6 ไบต์แทนข้อมูล โปรดทราบว่าผู้เขียนบล็อกได้ตอบคำถามอย่างเป็นประโยชน์มากที่สุด (ในบล็อกของเขา) นับตั้งแต่มีการตั้งคำถาม
จัสติน

@ จัสตินอย่างไรก็ตามในขณะที่ไฮเบอร์เนต 3.5 แมปเป็น oid (โดยค่าเริ่มต้น) จะอ่านโดยใช้ JDBC getBytes () ซึ่งไดรเวอร์ PGSQL ส่งคืน 6 ไบต์ oid แทนข้อมูล - สิ่งนี้เกิดขึ้นเมื่อใช้hibernate.jdbc.use_streams_for_binary=falseด้วยหรือไม่? (ไปตรวจสอบสิ่งที่สตีฟพูดตอนนี้)
Pascal Thivent

ฉันจะลองระบุในไฟล์คุณสมบัติ แต่ PostgreSQLDialect มี useInputStreamToInsertBlob () ส่งคืนเท็จดังนั้นฉันจึงถือว่าฉันเป็น - เนื่องจากฉันไม่ได้ตั้งค่าคุณสมบัตินี้อย่างชัดเจน
จัสติน

หลังจากตั้งค่าคุณสมบัตินี้ (เป็นจริงหรือเท็จ) ฉันได้รับข้อยกเว้นรันไทม์: ข้อผิดพลาด: คอลัมน์ "ลายเซ็น" เป็นประเภทไบต์ แต่นิพจน์เป็นประเภท oid "ฉันควรระบุว่าฉันใช้ไฮเบอร์เนต 3.5.5.Final + PG ไดรเวอร์ 8.2
จัสติน

10

นี่คือสิ่งที่ O’illy 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

ที่นี่ได้รับการสกัดที่นี่

ฉันมีแอปพลิเคชันที่ทำงานในโหมดไฮเบอร์เนต 3.3.2 และแอปพลิเคชันทำงานได้ดีโดยมีฟิลด์หยดทั้งหมดที่ใช้ oid (byte [] ใน java)

...

การโอนย้ายไปยังไฮเบอร์เนต 3.5 ช่อง Blob ทั้งหมดไม่ทำงานอีกต่อไปและบันทึกของเซิร์ฟเวอร์จะแสดง: ERROR org.hibernate.util.JDBCExceptionReporter - ข้อผิดพลาด: คอลัมน์เป็นประเภท oid แต่นิพจน์เป็นประเภท bytea

ซึ่งสามารถอธิบายได้ ที่นี่

generaly นี้ไม่ได้เป็นปัญหาใน PG JDBC , แต่การเปลี่ยนแปลงของการดำเนินการเริ่มต้นของ Hibernate ในรุ่น ในสถานการณ์ของฉันตั้งค่าคุณสมบัติที่รองรับการเชื่อมต่อไม่ได้ช่วย

...

สิ่งที่ฉันเห็นใน 3.5 - เบต้า 2 อีกมากมายและฉันไม่รู้ว่าสิ่งนี้ได้รับการแก้ไขแล้วหรือไม่ Hibernate - โดยไม่มีคำอธิบายประกอบ @Type - จะสร้างคอลัมน์ประเภท oid โดยอัตโนมัติ แต่จะพยายามอ่านสิ่งนี้เป็น bytea

ที่น่าสนใจคือเมื่อเขาแมป types.BOLB เป็น bytea (ดู CustomPostgreSQLDialect) เขาได้รับ

ไม่สามารถดำเนินการอัพเดตแบตช์ JDBC

เมื่อใส่หรืออัปเดต


โซลูชันนี้ดูดีฉันกำลังลองใช้อยู่
จัสติน

สิ่งนี้สร้าง DDL ที่ถูกต้อง แต่ล้มเหลวเมื่อรันไทม์: ฉันได้รับ java.sql.BatchUpdateException เมื่อพยายามที่จะวัตถุที่มีคุณสมบัติหยด
จัสติน

@ จัสตินลองใช้สถานการณ์ที่คล้ายกันโดยใช้ Oracle แทน PostgreSQL และดูว่าคุณจะได้อะไร BatchUpdateException เกี่ยวข้องกับข้อผิดพลาดที่เกิดขึ้นระหว่างการดำเนินการอัพเดตแบตช์
Arthur Ronald

จริงๆแล้วสิ่งที่ฉันต้องการจริงๆไม่ใช่การแมป BLOB กับ "bytea" แต่แทนที่จะแมป (byte [] + @Lob) รวมกันเป็น types.VARBINARY!
จัสติน


7

ฉันใช้ 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);
  }
}

ข้อดีของโซลูชันนี้ที่ฉันพิจารณาคือฉันสามารถเก็บขวดไฮเบอร์เนตไว้ได้โดยไม่ถูกแตะต้อง

สำหรับข้อมูลเพิ่มเติมปัญหาความเข้ากัน Postgres / ออราเคิลกับ Hibernate ดูของฉันโพสต์บล็อก


2
ทำงานให้ฉันโดยใช้ Hibernate 4.3.6 และ Postgresql 9.3 พร้อมการขยาย Postgresql9Dialect ขอบคุณ!
Andrés Oviedo

ทำงานร่วมกับ Hibernate 5.3.7 Final และ Postgres95Dialect Thx
Bernhard Kern

6

ในที่สุดฉันก็ทำงานนี้ได้ มันขยายการแก้ปัญหาจาก A.Garcia อย่างไรก็ตามเนื่องจากปัญหาอยู่ในประเภท MaterializedBlob ประเภท hibernate เพียงแค่การแมป Blob> bytea นั้นไม่เพียงพอเราจึงจำเป็นต้องเปลี่ยน MaterializedBlobType ซึ่งทำงานร่วมกับ hibernates ที่รองรับ blob เสีย การใช้งานนี้ใช้ได้กับ bytea เท่านั้น แต่บางทีคนที่มาจากปัญหา JIRA ที่ต้องการ OID อาจมีส่วนร่วมในการติดตั้ง OID

น่าเศร้าที่การแทนที่ประเภทเหล่านี้ในรันไทม์เป็นความเจ็บปวดเนื่องจากควรเป็นส่วนหนึ่งของภาษาถิ่น หากมีเพียงการปรับปรุง JIRA นี้เป็น 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 () ต้องการอินสแตนซ์ใหม่จริง ๆ หรือไม่) แต่ฉันไม่ค่อยเข้าใจไฮเบอร์เนตภายในดังนั้นส่วนใหญ่จึงเป็นการคัดลอก + วาง + แก้ไข

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);
 }
}

+1 สำหรับการวิจัยของคุณ ขอแสดงความยินดี เพียงคำแนะนำ: ต้องการแก้ไขคำถาม / คำตอบของคุณเองมากถึง 8 ครั้ง มิฉะนั้นคำถาม / คำตอบของคุณจะกลายเป็นวิกิชุมชนและคุณจะไม่ได้รับชื่อเสียงและคะแนนโหวตจะไม่ถูกคำนวณอีกต่อไป
Arthur Ronald

ใช้ชีวิตและเรียนรู้ฉันคิดว่าฉันมีการแก้ไขมากมายในขณะที่ฉันลืมที่จะทำอย่างใดอย่างหนึ่งกับสภาพแวดล้อมการทดสอบของฉัน
จัสติน

เดียวกันที่นี่, +1 สำหรับการวิจัยและโซลูชั่นสำหรับสถานการณ์ของคุณ
Pascal Thivent

มีโอกาสแก้ปัญหาด้วยเวอร์ชัน 4.2.x Hibernate หรือไม่ ภายใน Hibernate มีการเปลี่ยนแปลงเล็กน้อย (ฉันแสดงความคิดเห็นเกี่ยวกับปัญหาที่ตอบ: hibernate.atlassian.net/browse/HHH-5584 )
Peter Butkovic

2

ฉันแก้ไขปัญหาของฉันโดยการเพิ่มคำอธิบายประกอบของ @Lob ซึ่งจะสร้างไบต์ [] ใน oracle เป็นหยด แต่คำอธิบายประกอบนี้จะสร้างฟิลด์เป็น oid ซึ่งทำงานไม่ถูกต้องในการสร้างไบต์ [] ที่สร้างเป็นไบต์ฉันทำให้ภาษาลูกค้าสำหรับ 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


0

ฉันได้ผลโดยการแทนที่คำอธิบายประกอบด้วยไฟล์ XML สำหรับ Postgres คำอธิบายประกอบจะถูกเก็บไว้สำหรับ Oracle ในความคิดของฉันในกรณีนี้มันจะเป็นการดีที่สุดที่เราจะแทนที่การแมปของปัญหานี้ - ความสัมพันธ์บางอย่างด้วยการแมป xml เราสามารถแทนที่เอนทิตีเดียว / หลายรายการด้วยการแมป xml ดังนั้นเราจะใช้คำอธิบายประกอบสำหรับฐานข้อมูลที่สนับสนุนส่วนใหญ่และไฟล์ xml สำหรับฐานข้อมูลอื่น ๆ

หมายเหตุ: เราต้องลบล้างคลาสเดียวเท่านั้นจึงไม่ใช่เรื่องใหญ่ อ่านเพิ่มเติมจากตัวอย่างตัวอย่างของฉัน เพื่อแทนที่คำอธิบายประกอบด้วย XML


0

ใน Postgres @Lob กำลังทำลายสำหรับ byte [] เนื่องจากพยายามบันทึกเป็น oid และสำหรับ String ก็เกิดปัญหาเช่นเดียวกัน โค้ดด้านล่างทำลาย postgres ซึ่งทำงานได้ดีบน oracle

@Lob
private String stringField;

และ

@Lob
private byte[]   someByteStream;

ในการแก้ไขด้านบนใน postgres ได้เขียนไว้ด้านล่าง hibernate.dialect ที่กำหนดเอง

public class PostgreSQLDialectCustom extends PostgreSQL82Dialect{

public PostgreSQLDialectCustom()
{
    super();
    registerColumnType(Types.BLOB, "bytea");
}

 @Override
 public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
    if (Types.CLOB == sqlTypeDescriptor.getSqlType()) {
      return LongVarcharTypeDescriptor.INSTANCE;
    }
    return super.remapSqlTypeDescriptor(sqlTypeDescriptor);
  }
}

ตอนนี้กำหนดค่าภาษาถิ่นที่กำหนดเองในโหมดไฮเบอร์เนต

hibernate.dialect=X.Y.Z.PostgreSQLDialectCustom   

XYZ คือชื่อแพ็คเกจ

ตอนนี้ทำงานได้ดี หมายเหตุ - เวอร์ชันไฮเบอร์เนตของฉัน - 5.2.8 เวอร์ชันสุดท้ายของ Postgres - 9.6.3


0

ขอบคุณจัสตินปาสคาลที่ชี้แนะแนวทางที่ถูกต้อง ฉันก็ประสบปัญหาเดียวกันกับ Hibernate 3.5.3 การวิจัยและคำแนะนำของคุณไปยังชั้นเรียนที่เหมาะสมช่วยให้ฉันระบุปัญหาและทำการแก้ไขได้

เพื่อประโยชน์สำหรับผู้ที่ยังติดอยู่กับ Hibernate 3.5 และใช้ชุดค่าผสม oid + byte [] + @LoB ต่อไปนี้คือสิ่งที่ฉันได้ทำเพื่อแก้ไขปัญหา

  1. ฉันสร้าง BlobType แบบกำหนดเองที่ขยาย MaterializedBlobType และแทนที่ชุดและเมธอด get ด้วยการเข้าถึงสไตล์ oid

    public class CustomBlobType extends MaterializedBlobType {
    
    private static final String POSTGRESQL_DIALECT = PostgreSQLDialect.class.getName();
    
    /**
     * Currently set dialect.
     */
    private String dialect = hibernateConfiguration.getProperty(Environment.DIALECT);
    
    /*
     * (non-Javadoc)
     * @see org.hibernate.type.AbstractBynaryType#set(java.sql.PreparedStatement, java.lang.Object, int)
     */
    @Override
    public void set(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
        byte[] internalValue = toInternalFormat(value);
    
        if (POSTGRESQL_DIALECT.equals(dialect)) {
            try {
    
    //I had access to sessionFactory through a custom sessionFactory wrapper.
    st.setBlob(index, Hibernate.createBlob(internalValue, sessionFactory.getCurrentSession()));
                } catch (SystemException e) {
                    throw new HibernateException(e);
                }
            } else {
                st.setBytes(index, internalValue);
            }
        }
    
    /*
     * (non-Javadoc)
     * @see org.hibernate.type.AbstractBynaryType#get(java.sql.ResultSet, java.lang.String)
     */
    @Override
    public Object get(ResultSet rs, String name) throws HibernateException, SQLException {
        Blob blob = rs.getBlob(name);
        if (rs.wasNull()) {
            return null;
        }
        int length = (int) blob.length();
        return toExternalFormat(blob.getBytes(1, length));
      }
    }
    1. ลงทะเบียน CustomBlobType ด้วย Hibernate ต่อไปนี้คือสิ่งที่ฉันทำเพื่อให้บรรลุเป้าหมายนั้น

      hibernateConfiguration= new AnnotationConfiguration();
      Mappings mappings = hibernateConfiguration.createMappings();
      mappings.addTypeDef("materialized_blob", "x.y.z.BlobType", null);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.