Lassen Sie uns zunächst verstehen, was XMLTYPE -Typ ist.
XMLTYPE ist seit 9i ein eindeutiger Datentyp für Oracle. Es ist eine kraftvolle Existenz, die den Blob erbt. Es kann zum Speichern von XML verwendet werden und bietet viele Betriebsfunktionen. Theoretisch kann es 2G -Daten speichern.
Wie können Sie XMLTYPE -Daten über Java einfügen? Das Projekt verwendet MyBatis, und es gibt immer unerklärliche Ausnahmen. Ich kann nicht herausfinden, ob es MyBatis 'Problem oder JDBC selbst ist. Daher habe ich vor, es Schritt für Schritt zu machen, JDBC zuerst zu lösen und dann MyBatis zu lösen.
JDBC
Nach langer Zeit des Kampfes stellte ich fest, dass es drei Hauptmethoden für den JDBC -Betrieb gibt:
1. Verwenden Sie XMLTYPE als String -Zeichenfolge in Java, und die spezifische Aufgabe zum Erstellen von XMLTYPE wird vollständig an die Datenbank übergeben:
String SQL = "In XMLTable (xml) -Werte einfügen (sys.xmlType.Createxml (?))"; String xmldata = "<label> Dies ist ein XML -Fragment </label>"; ps.setstring (1, xmldata); ps.executeUpdate ();
Diese Methode macht die Datenbankspannung zu stark, da diese Methode einfach ist und keine zusätzlichen Abhängigkeiten erfordert. Diese Methode wurde zu Beginn verwendet, aber während der tatsächlichen Verwendung wurde festgestellt, dass die Länge des Inhalts etwa 4000 überschreitet, sie: ORA-01461: Kann einen langen Wert nur für die Einfügung in eine lange Spaltenausnahme binden. Zuerst dachte ich, dass der Grund für die Verwendung von MyBatis bei Verwendung des JDBC -Tests immer noch der gleiche war, und es gab keine Lösung, wenn viele Methoden verwendet wurden. Es ist unmöglich, Daten mit einer Länge von weniger als 4000 zu speichern, wenn dieses große Feld im Projekt verwendet wird. Auf diese Weise reicht die Verwendung von varchar2 aus, so dass diese Methode beseitigt wird.
2. Verwenden Sie den CLOB -Typ zum Betrieb. XmlType erbt die Existenz von CLOB, sodass sie durch CLOB betrieben werden kann. Die Methode besteht darin, CLOB -Daten im Client zu erstellen und sie in die Datenbank zu übergeben, um den XMLTYPE -Wert über die Funktion von Oracle XMLTYPE () zu konstruieren:
String SQL = "In XMLTable (XML) -Werte (xmlType (?))") "; String xmldata = "<label> Dies ist ein XML -Fragment </label>"; // CLOBCLOB TEMPCOB = CLOB.CreateTemporary (Verbindung, Falsch, clob.duration_Session); // Clobtempclob.open (CloB.Mode_readwrite) öffnen; // writerWriter clobwriter = tempclob.setcharacterstream (100); // Daten clobwriter.write (xmldata); // frisch clobwriter.flush (); // WriterClobwriter.Close (); // Clotztempclob.Close (); pst.setObject (1, tempclob);
Diese Methode -Client und Datenbank sind für das gleichzeitige Erstellen von XMLTYPE verantwortlich, sodass der Druck relativ durchschnittlich ist und es kein Problem gibt, die Länge zu überschreiten. Während des tatsächlichen Gebrauchs wurde jedoch festgestellt, dass der Inhaltsüberschuss des XML die folgenden Informationen nicht enthalten kann:
<? xml Version = "1.0" coding = "utf-8"?>
Andernfalls wird eine Ausnahme ausgelöst:
PI -Namen beginnend mit XML sind reserviert
Lassen Sie uns nicht darüber sprechen, ob Sie bei der Verarbeitung des Inhalts der XML -Einbeziehung in Chinesisch in der Zukunft belastete Codeprobleme stoßen. Wenn Sie es nur betrachten, fühlen sich die Menschen unwohl, und die Anforderungen erfordern auch ein Speichern. Es gibt keinen Weg, und diese Methode funktioniert nicht.
3. Verwenden Sie die von Oracle bereitgestellte Oracle.xdb.xmlType -Klasse. Nachdem der Client XMLTYPE erstellt hat, wird das Objekt direkt an die Datenbank übergeben:
Verbindung conn = ...; // Verbindungsvorbereitete statement ps = ...; // Vorbereitungsanschläge sql = "In XMLTable (xml) -Werte (?)" Einfügen; String xmldata = "<label> Dies ist ein XML -Fragment </label>"; // Erstellen Sie ein XMLTYPE -Objekt xmlType xmlType = xmlType.CreatexMl (conn, xmldata); ps.SetObject (1, xmlType); ps.executeUpdate ();
Diese Methode befasst sich vollständig mit der Erstellung von XMLTYPE an den Client, sodass der Client unter großem Druck steht und die Datenbank unter niedrigem Druck steht. Während des tatsächlichen Tests müssen zwei JAR -Pakete hinzugefügt werden, andernfalls kann die Klasse kein Fehler gefunden werden:
xdb.jarxmlparserv2.jar
Es ist zu beachten, dass dieses JAR -Paket keine Versionsannotation hat, daher ist es einfach, Fehler zu machen. Am Anfang habe ich einen XDB.Jar heruntergeladen, aber egal wie ich es tat, es wurde veranlasst, dass ich keine bestimmte Klasse finden konnte. Nachdem ich nachgesehen hatte, stellte ich fest, dass es zu einer früheren Version von Oracle gehört. Nach dem Wiederladen eines xdb.jar ist es normal.
Die obigen drei Methoden wurden durch Einfügen von 200.000 Datenstücke verglichen:
Die erste Methode: Die kürzeste Zeit und der Server -CPU -Verbrauch sind die größten;
Die zweite Methode: Die längste Zeit wird verwendet und der Server -CPU -Verbrauch wird zentriert.
Die dritte Methode: zeitaufwändig und zentriert, der Server-CPU-Verbrauch ist minimal.
Zu diesem Zeitpunkt hat JDBC endlich einige kleine Dinge im Betrieb von XMLTYPE -Daten -Daten gemacht. Unnötig zu erwähnen, dass die dritte Lösung übernommen wird, aber das Projekt verwendet im Grunde nicht direkt JDBC, um zu operieren. Zum Beispiel wird im aktuellen Projekt MyBatis verwendet. In dem obigen erwähnte auch, dass es bei der Verwendung von MyBatis immer Ausnahmen gibt. Nach der Überprüfung von MyBatis gibt es keine Implementierung von XMLTYPE. Es scheint, dass es immer noch einige Probleme gibt, aber JDBC wurde gemacht, also ist die Idee klar, oder?
Mybatis
Mit MyBatis zum Betrieb von XMLTYPE kartieren wir auch dem String -Typ auf der Java -Seite. Wenn der direkte Betrieb wie JDBC keine Verarbeitung durchführt, ist alles normal, wenn der übertragene Inhalt weniger als 4000 beträgt. Wenn der übertragene Inhalt mehr als 4000 beträgt, wird auch eine Ausnahme ausgelöst:
ORA-01461: Kann einen langen Wert nur für den Einsatz in eine lange Spalte binden
Es ist ersichtlich, dass MyBatis 'Betrieb tatsächlich mit JDBC übereinstimmt, außer dass er eine Ebene außerhalb von JDBC zusammenfasst, damit wir Konfigurationsdateien und andere Zuordnungsmethoden verwenden können, um bequemer auf die Datenbank zuzugreifen. Wir müssen XMLTYPE -Daten anhand der ursprünglichen MyBatis -Bequemlichkeit einfügen. In diesem Fall ist die Implementierung eines benutzerdefinierten TypsHandler -Prozessors vom Typ XMLTYPE die beste Wahl.
Hier verwenden wir immer noch die oben erwähnte Lösung. Natürlich müssen die beiden JAR -Pakete: XDB.Jar und XmlParServ2.jar hinzugefügt werden.
Fügen Sie einen xmltypetypeHandler hinzu, um die Typhandler -Schnittstelle zu implementieren. Da das Einfügen von Daten hauptsächlich die SetParameter -Methode verwendet, wird hier nur diese Methode aufgeführt. Der andere Methodcode wird weggelassen:
/*** Oracle sys.xmlType Typen Benutzerdefinierter Prozessor*/public class xmltyPetypeHandler implements TypeHandler <string> {@Override public void setParameter (prepedStatement ps, int i, String -Parameter, jdbctype jdbctype) löst SQLEXception {{} ...} ...} ...} ...} ...} ...} ...} ...} ...} ...} ...} ...} ...} ...} ...} ...} ...} ...} ...Diese SetParameter -Methode wird von MyBatis verwendet, um Parameter beim Einfügen von Daten in die Datenbank festzulegen. Was die Parameter dieser Methode betrifft, glaube ich, dass Sie den Code bereits verstanden haben. Wir werden den folgenden Code hier gemäß der vorherigen JDBC -Implementierungsmethode einfügen:
public void setParameter (prepedStatement ps, int i, String -Parameter, jdbctype jdbcType) löscht sqlexception {xmlType xmlType = xmlType.Createxml (ps.getConnection (), Parameter); ps.SetObject (i, xmlType);}Und registrieren Sie den Konverter in Mapper-config.xml, da in der von mybatis org.apache.ibatis.type.jdbcType definierten Aufzählung keinen XMLTYPE-Typ benötigen, den wir benötigen.
<configuration> <typeHandlers> <typeHandler javatype = "string" jdbctype = "undefined" Handler = "com.tyyd.dw.context.xmltypetypeHandler"/> </typeHandlers> </configuration>
Verwenden Sie in den Parametern der Konfigurationsdatei unseren definierten Konverter, damit MyBatis ihn finden kann:
#{xmlfile, jdbctype = undefiniert},Natürlich können Sie auch standardisierter sein und seinen Typ und den Konverter auf eine vollständige Weise ausschreiben:
#{xmlfile, javatype = string, jdbctype = undefined, typeHandler = com.tyyd.dw.context.xmltypetypeHandler},
Führen Sie die oben genannten Schritte aus und logischerweise ist alles fertig. Lassen Sie uns sie ausführen.
Das Ergebnis wird geworfen: java.lang.ClassCastException: org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to oracle.jdbc.OracleConnection
Es kann nicht in Oraces Verbindungsobjekt Oracleconnection konvertiert werden. Nach der Überprüfung stellten wir fest, dass unsere Datenquelle das DBCP von Apache verwendet, was mit den beiden nicht kompatibel sein sollte. Ich habe online überprüft und ein Mann sagte, dass er eine perfekte Lösung gegeben habe, nämlich eine Oracle -Treiberklasse in der SetParameter -Methode zu laden, um eine Verbindung zu erstellen, wie folgt:
Class.forname ("oracle.jdbc.oracledriver"); Connection Connection = DriverManager.getConnection (URL, Benutzername, Passwort);Dies kann in der Tat das Problem lösen, dass das Verbindungsobjekt nicht 100%konvertiert werden kann, aber in Bezug auf die Implementierung werde ich immer noch nicht kommentieren. Es gibt auch Leute, die das Internet herumgeben und sagen, dass sie in ein PoolableConnection -Objekt umgewandelt werden können, und dann die GetDelegate -Methode verwenden, um den ursprünglichen Proxy -Link zu erhalten. Dies scheint machbar, versuchen wir:
PoolableConnection Connection = (PoolableConnection) ps.getConnection (); xmlType xmlType = xmlType.creeRexml (connection.getDelegate (), Parameter); ps.setObject (i, xmlType);
Infolgedessen wurde eine weitere Ausnahme ausgelöst:
org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to org.apache.commons.dbcp.PoolableConnection , kann nicht konvertiert werden.
Es gibt keine Möglichkeit, dass die Artikel, die online verbreitet werden, nicht zuverlässig sind. Es gibt also keine Verknüpfung, sodass Sie den Quellcode selbst überprüfen sollten.
Durch die Betrachtung des Quellcodes haben wir festgestellt, dass die PoolableConnection die DelegatingConnection -Klasse erbt, und die DelegatingConnection -Klasse implementiert die Verbindungsschnittstelle. Lassen Sie es uns in eine DelegatingConnection umwandeln, um es zu versuchen:
DelegatingConnection Connection = (DelegatingConnection) ps.getConnection (); xmlType xmlType = xmlType.creeRexml (connection.getDelegate (), Parameter); ps.setObject (i, xmltype);
Infolgedessen wurde eine Ausnahme ausgelöst: Deskriptoren nicht konstruieren: ungültige Argumente; Eine verschachtelte Ausnahme ist java.sql.sqlexception: Deskriptoren können nicht konstruieren: Ungültige Argumente. Durch Breakpoint -Debugging fand ich, dass das Verbindungsobjekt tatsächlich null ist. Wie könnte es null sein? Die Leute im Internet nutzen es gut, aber es wird nicht mit mir funktionieren. Es ist wirklich ein Schmerz. Dies ist nicht unlösbar. Müssen Sie wirklich eine Fahrerklasse alleine laden, wie der oben erwähnte Typ sagte? Es gibt keinen Weg, lasst es uns noch einmal studieren.
Schließlich stellte ich fest, dass die ursprüngliche Proxy -Verbindung über die GetMetadata -Methode erhalten werden kann. Es ist so hell und der Test ist so klar. Es ist endlich normal und nicht einfach. Der endgültige Code lautet wie folgt:
@Overridepublic void setParameter (prepedStatement ps, int i, String -Parameter, jdbcType jdbctype) löst SQLEXception {delegatingConnection Connection = (DelegatingConnection) ps.getConnection (). XmlType xmlType = xmlType.CreatexMl (connection.getDelegate (), Parameter); ps.SetObject (i, xmlType);}Zu diesem Zeitpunkt wurde endlich MyBatis zum Betrieb von XMLTYPE -Typen durchgeführt, und der Prozess ist voller Wendungen. Natürlich müssen Abfragen angegeben werden, wenn Daten eingefügt werden. Als nächstes müssen wir XMLTYPE -Abfragebetriebe implementieren.