Warum es passiert
Das Problem ist, dass PostgreSQL bei Umwandlungen zwischen Text- und Nicht-Text-Datentypen zu streng ist. Es erlaubt keine implizite Umwandlung (eine ohne CAST
oder ::
im SQL) von einem Texttyp wie text
oder varchar
(character varying
) in einen textähnlichen Nicht-Texttyp wie json
, xml
usw.
Der PgJDBC-Treiber gibt den Datentyp von varchar
an wenn Sie setString
aufrufen einen Parameter zuweisen. Wenn der Datenbanktyp der Spalte, des Funktionsarguments usw. nicht wirklich varchar
ist oder text
, aber statt eines anderen Typs erhalten Sie einen Typfehler. Dies gilt auch für viele andere Treiber und ORMs.
PgJDBC:stringtype=unspecified
Die beste Option bei der Verwendung von PgJDBC ist im Allgemeinen die Übergabe des Parameters stringtype=unspecified
. Dies überschreibt das Standardverhalten der Übergabe von setString
Werte als varchar
und überlässt es stattdessen der Datenbank, ihren Datentyp zu "erraten". In fast allen Fällen macht dies genau das, was Sie wollen, und übergibt den String an den Eingabe-Validierer für den Typ, den Sie speichern möchten.
Alle:CREATE CAST ... WITH FUNCTION ...
Sie können stattdessen CREATE CAST
eine datentypspezifische Umwandlung zu definieren, um dies Typ für Typ zu ermöglichen, aber dies kann an anderer Stelle Nebenwirkungen haben. Wenn Sie dies tun, tun Sie es nicht Verwenden Sie WITHOUT FUNCTION
Umwandlungen umgehen, umgehen sie die Typvalidierung und führen zu Fehlern. Sie müssen die Eingabe-/Validierungsfunktion für den Datentyp verwenden. Mit CREATE CAST
eignet sich für Benutzer anderer Datenbanktreiber, die keine Möglichkeit haben, den Treiber anzuhalten, der den Typ für Zeichenfolgen-/Textparameter angibt.
z. B.
CREATE OR REPLACE FUNCTION json_intext(text) RETURNS json AS $$
SELECT json_in($1::cstring);
$$ LANGUAGE SQL IMMUTABLE;
CREATE CAST (text AS json)
WITH FUNCTION json_intext(text) AS IMPLICIT;
Alle:Handler für benutzerdefinierte Typen
Wenn Ihr ORM dies zulässt, können Sie einen benutzerdefinierten Typhandler für den Datentyp und dieses spezifische ORM implementieren. Dies ist vor allem dann nützlich, wenn Sie einen nativen Java-Typ verwenden, der gut auf den PostgreSQL-Typ abgebildet wird, anstatt String
zu verwenden , obwohl es auch funktionieren kann, wenn Ihr ORM die Angabe von Typhandlern mithilfe von Anmerkungen usw. zulässt.
Methoden zum Implementieren benutzerdefinierter Typhandler sind treiber-, sprach- und ORM-spezifisch. Hier ist ein Beispiel für Java und Hibernate für json
.
PgJDBC:Typ-Handler mit PGObject
Wenn Sie einen nativen Java-Typ in Java verwenden, können Sie PGObject
erweitern um eine PgJDBC-Typzuordnung für Ihren Typ bereitzustellen. Sie müssen wahrscheinlich auch einen ORM-spezifischen Typ-Handler implementieren, um Ihr PGObject
zu verwenden , da die meisten ORMs einfach toString
aufrufen auf Typen, die sie nicht erkennen. Dies ist der bevorzugte Weg, um komplexe Typen zwischen Java und PostgreSQL abzubilden, aber auch der komplexeste.
PgJDBC:Typ-Handler mit setObject(int, Object)
Wenn Sie String
verwenden Um den Wert in Java anstelle eines spezifischeren Typs zu speichern, können Sie die JDBC-Methode setObject(integer, Object)
aufrufen zum Speichern der Zeichenfolge ohne Angabe eines bestimmten Datentyps. Der JDBC-Treiber sendet die Zeichenfolgendarstellung, und die Datenbank leitet den Typ vom Zielspaltentyp oder Funktionsargumenttyp ab.
Siehe auch
Fragen:
- PostgreSQL-JSON-Spalte dem Hibernate-Werttyp zuordnen
- Sind JPA (EclipseLink) benutzerdefinierte Typen möglich?
Extern:
- http://www.postgresql.org/message-id/[email protected]
- https://github.com/pgjdbc/pgjdbc/issues/265
- http://www.pateldenish.com/2013/05/inserting-json-data-into-postgres-using-jdbc-driver.html