PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Das Euro-Zeichen kann mit Hibernate/PostgreSQL nicht in der LOB-String-Eigenschaft gespeichert werden

Nachdem ich viel im Quellcode von Hibernate und dem PostgreSQL-JDBC-Treiber herumgegraben hatte, gelang es mir, die Ursache des Problems zu finden. Am Ende wird die Methode write() des BlobOutputStream (vom JDBC-Treiber bereitgestellt) aufgerufen, um den Inhalt des Clobs in die Datenbank zu schreiben. Diese Methode sieht folgendermaßen aus:

public void write(int b) throws java.io.IOException
{
    checkClosed();
    try
    {
        if (bpos >= bsize)
        {
            lo.write(buf);
            bpos = 0;
        }
        buf[bpos++] = (byte)b;
    }
    catch (SQLException se)
    {
        throw new IOException(se.toString());
    }
}

Diese Methode nimmt ein „int“ (32 Bit/4 Byte) als Argument und konvertiert es in ein „Byte“ (8 Bit/1 Byte), wodurch effektiv 3 Byte an Informationen verloren gehen. Zeichenfolgendarstellungen in Java sind UTF-16-codiert, was bedeutet, dass jedes Zeichen durch 16 Bits/2 Bytes dargestellt wird. Das Euro-Zeichen hat den Int-Wert 8364. Nach Umwandlung in Byte bleibt der Wert 172 (in Oktett-Darstellung 254).

Ich bin mir nicht sicher, was jetzt die beste Lösung für dieses Problem ist. IMHO sollte der JDBC-Treiber für die Codierung/Decodierung der Java-UTF-16-Zeichen in die von der Datenbank benötigte Codierung verantwortlich sein. Ich sehe jedoch keine Optimierungsmöglichkeiten im JDBC-Treibercode, um sein Verhalten zu ändern (und ich möchte keinen eigenen JDBC-Treibercode schreiben und pflegen).

Daher habe ich Hibernate um einen benutzerdefinierten ClobType erweitert und es geschafft, die UTF-16-Zeichen vor dem Schreiben in die Datenbank in UTF-8 zu konvertieren und umgekehrt beim Abrufen des Clobs.

Die Lösungen sind zu groß, um diese Antwort einfach einzufügen. Wenn Sie interessiert sind, schreiben Sie mir und ich schicke es Ihnen.

Tschüss, Franck