Derby/JavaDB byte[] in Datenbank speichern [JPA]

T_O_B_E_E

Mitglied
Hallo zusammen,

ich habe ein byte[] Array welches ich mit JPA/Hibernate in eine Derby DB speichern möchte.
Java:
@Transient
private Double[][] testMatrix = new Double[10][10]; // Direktes speichern geht mit JPA nicht :-(

private byte[] testMatrixSaver; // Hier soll testMatrix rein und über dieses Feld gespeichert werden

@Basic(fetch=FetchType.LAZY) @Lob
public byte[] getTestMatrixSaver() {
 for (int i = 0; i < testMatrix.length; i++) { // Fill testMatrix with dummy values
 Arrays.fill(testMatrix[i], new Double(9.3));
 }
 ByteArrayOutputStream baos = new ByteArrayOutputStream(); // Convert testMatrix into a byte array
 try {
   ObjectOutputStream oos = new ObjectOutputStream(baos);
   oos.writeObject(testMatrix);
 } catch (IOException iOException) {
 }
 testMatrixSaver = baos.toByteArray();
 return testMatrixSaver;
}
Beim Schreiben in die DB gibts dann folgende Fehlermeldung: "Bei dem Versuch, VARCHAR () FOR BIT DATA '(Bin√§rer Datenwert wird nicht angezeigt.)' auf die Länge 255 zu kürzen, ist ein Abschneidefehler aufgetreten."
Hat jemand eine Idee woran das liegen könnte? Ich habe die Methode ja mit @Lob annotiert, so dass dieser Fehler doch eigentlich nicht mehr auftreten sollte!?
 
Der Fehler liegt am Hibernate Derby Dialect siehe auch [#HHH-2614] Blob Length Set to 255 By Default With Derby DB


Workaround wäre den Derby Dialect zu erweitern:

Java:
import java.sql.Types;

/**
 * Hibernate Dialect for Derby.
 * This implementation fixes [#HHH-2614] Blob Length Set to 255 By Default With Derby DB
 */
public class DerbyDialect extends org.hibernate.dialect.DerbyDialect {

    public DerbyDialect() {
        super();
        registerColumnType(Types.BLOB, "blob");
        registerColumnType(Types.CLOB, "clob");
    }
}
 
Kontrolliere bitte die persistence.xml. Dort muß für die persitence-unit ein zusätzlicher value "hibernate.dialect" eingetragen sein, der den Klassennamen des neuen Dialects beeinhaltet. Sonst verwendet Hibernate nicht den überschriebenen Dialect.
 
Kontrolliere bitte die persistence.xml. Dort muß für die persitence-unit ein zusätzlicher value "hibernate.dialect" eingetragen sein, der den Klassennamen des neuen Dialects beeinhaltet. Sonst verwendet Hibernate nicht den überschriebenen Dialect.

In der persistence.xml habe ich nur die zu persistierenden Klassen. Den EntityManager erstelle ich per Property Map:
Java:
public class EntityManagerProvider {

    private static Map<String, Object> configs = new HashMap<String, Object>() {
        {
            put("hibernate.connection.driver_class", "org.apache.derby.jdbc.ClientDriver");
            put("hibernate.connection.url", "jdbc:derby://127.0.0.1:1527/Test");
            put("hibernate.connection.username", "test");
            put("hibernate.connection.password", "testpw");
            put("hibernate.hbm2ddl.auto", "update");
            put("hibernate.show_sql", "true");
            put("hibernate.dialect", "org.mytest.DerbyDialect");
        }
    };

    public static final EntityManager getEntityManager(String persistenceUnit) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnit, configs);
        EntityManager em = emf.createEntityManager();
        return em;
    }
}
Durch Umbennen der Dialect Klasse konnte ich prüfen, dass die Klasse genommen wird.

persistence.xml:
[XML]
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="MyTestUnit">
<class>org.mytest.MyTest</class>
</persistence-unit>
</persistence>
[/XML]
 
Die entsprechende Tabelle wird jedesmal neu angelegt ?
Wenn nicht, dann wurde die Tabellenspalte als blob(255) angelegt. In dem Fall wird ein ALTER TABLE nötig.

Das mit dem Dialect hilft ja nur die Tabelle z.B. per hbm:ddl jetzt richtig anzulegen.
 
Die entsprechende Tabelle wird jedesmal neu angelegt ?
Wenn nicht, dann wurde die Tabellenspalte als blob(255) angelegt. In dem Fall wird ein ALTER TABLE nötig.

Das mit dem Dialect hilft ja nur die Tabelle z.B. per hbm:ddl jetzt richtig anzulegen.

Ich habe die Tabelle noch einmal gelöscht und neu anlegen lassen. Leider klappt das immer noch nicht mit byte[]. Als Workaround erstelle ich jetzt mit dem byte Array einen SerialBlob. Diesen kann ich problemlos in die DB speichern.
Java:
@Transient
private Double[][] testMatrix = new Double[1000][1000];    
private Blob testMatrixSaver;

@Lob
public Blob getTestMatrixSaver() throws SerialException, SQLException {
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 try {
   ObjectOutputStream oos = new ObjectOutputStream(baos);
   oos.writeObject(testMatrix);
  } catch (IOException iOException) { }
 testMatrixSaver = new SerialBlob(baos.toByteArray());
 return testMatrixSaver;
}
 
Jetzt klappts auch mit byte[]. Der Code sieht folgendermassen aus:

Java:
    @Transient
    private byte[] testMatrixSaverArray;
    
    @Transient
    private Double[][] testMatrix = new Double[100][1000]; // !!! Geht nicht !!!
    
    @Lob
    @Access(AccessType.PROPERTY)
    public byte[] getTestMatrixSaverArray() {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(testMatrix);
        } catch (IOException iOException) {
        }
        testMatrixSaverArray = baos.toByteArray();
        return testMatrixSaverArray;
    }
    
    public void setTestMatrixSaverArray(byte[] testMatrixSaverArray) throws IOException, ClassNotFoundException {
        this.testMatrixSaverArray = testMatrixSaverArray;
        ByteArrayInputStream bais = new ByteArrayInputStream(testMatrixSaverArray);
        testMatrix = (Double[][]) new ObjectInputStream(bais).readObject();
    }
Danke für die Hilfe! :toll:
 

Zurück
Oben