Comprenons d'abord ce qu'est le type XMLTYPE.
XMLTYPE est un type de données unique pour Oracle depuis 9i. C'est une existence puissante qui hérite du blob. Il peut être utilisé pour stocker XML et fournit de nombreuses fonctions de fonctionnement. En théorie, il peut économiser des données 2G.
Alors, comment insérez-vous les données XMLTYPE via Java? Le projet utilise MyBatis, et il y a toujours des exceptions inexplicables. Je ne peux pas comprendre s'il s'agit du problème de MyBatis ou JDBC lui-même, donc je prévois de le faire étape par étape, résolvez d'abord JDBC, puis résolvez MyBatis.
JDBC
Après une longue période de lutte, j'ai constaté qu'il existe trois méthodes principales pour le fonctionnement de JDBC:
1. Utilisez XMLTYPE comme une chaîne de chaîne en Java, et la tâche spécifique de la création de XMLType est complètement remise à la base de données:
String sql = "Insérer dans XMLTable (xml) valeurs (sys.xmltype.createExml (?))"; String xmldata = "<Bellow> Ceci est un fragment XML </cablown>"; ps.SetString (1, xmldata); ps.ExecuteUpdate ();
Cette méthode rendra trop la contrainte de la base de données, car cette méthode est simple et ne nécessite pas de dépendances supplémentaires. Cette méthode a été utilisée au début, mais lors d'une utilisation réelle, il a été constaté que lorsque la longueur du contenu dépasse environ 4000, elle lancera: ORA-01461: peut lier une valeur longue uniquement pour l'insertion dans une longue exception de colonne. Au début, je pensais que la raison de l'utilisation de MyBatis était toujours la même lors de l'utilisation du test JDBC, et il n'y avait pas de solution lors de l'utilisation de nombreuses méthodes. Il est impossible d'enregistrer des données avec une longueur inférieure à 4000 lors de l'utilisation de ce grand champ dans le projet. De cette façon, l'utilisation de VARCHAR2 est suffisante, donc cette méthode est éliminée.
2. Utilisez le type COB pour fonctionner. XMLTYPE hérite de l'existence de CLOB, donc il peut être utilisé via CLOB. La méthode consiste à créer des données CLOB sur le client et à la transmettre dans la base de données pour construire la valeur XMLType via la fonction XMLTYPE () d'Oracle:
String sql = "Insérer dans XMLTable (XML) VALEURS (XMLTYPE (?))"; String xmldata = "<Bellow> Ceci est un fragment XML </cablown>"; // Créer CloBclob TempClob = CloB.CreateEmporary (Connection, False, CloB.Duration_Session); // Ouvrir CloBTempClob.Open (Clob.Mode_readwrite); // Get writterwriter clobwriter = tempclob.SetcharAtteTream (100); // write data Clobwriter.write (xmldata); // Fresh Clobwriter.flush (); // close writeCloBwriter.close (); // close clobTempclob.close (); pst.setObject (1, tempclob);
Cette méthode client et base de données sont responsables de la création de XMLType en même temps, donc la pression est relativement moyenne et il n'y a aucun problème à dépasser la longueur. Cependant, lors de l'utilisation réelle, il a été constaté que l'en-tête de contenu du XML ne peut pas contenir les informations suivantes:
<? xml version = "1.0" Encoding = "utf-8"?>
Sinon, une exception sera lancée:
Les noms Pi commençant par XML sont réservés
Ne parlons pas de savoir si vous rencontrerez des problèmes de code brouillé lors du traitement du contenu de l'inclusion XML en chinois à l'avenir. Le simple fait de le regarder rend les gens mal à l'aise, et les exigences nécessitent également une économie. Il n'y a aucun moyen, et cette méthode ne fonctionnera pas.
3. Utilisez la classe Oracle.xdb.xmlType fournie par Oracle. Une fois que le client a créé XMLTYPE, l'objet est directement transmis à la base de données:
Connexion conn = ...; // obtenir la connexion préparée Ps = ... String xmldata = "<Bellow> Ceci est un fragment XML </cablown>"; // Créer un objet XMLTYPE XMLTYPE XMLTYPE = XMLTYPE.CREATEXML (CONN, XMLDATA); Ps.SetObject (1, xmlType); ps.ExecuteUpdate ();
Cette méthode remet complètement la tâche de créer XMLType au client, de sorte que le client est sous une grande pression et la base de données est sous basse pression. Pendant le test réel, deux packages en pot doivent être ajoutés, sinon la classe ne peut être trouvée Erreur:
xdb.jarxmlParserv2.jar
Il est nécessaire de noter que ce package JAR n'a pas d'annotation de version, il est donc facile de faire des erreurs. Au début, j'ai téléchargé un xdb.jar, mais peu importe comment je l'ai fait, il a été invité à ne pas trouver une certaine classe. Après vérification, j'ai constaté qu'il appartient à une version antérieure d'Oracle. Après avoir à nouveau téléchargé un xdb.jar, c'est normal.
Les trois méthodes ci-dessus ont été comparées en insérant 200 000 éléments de données:
La première méthode: le temps le plus court et la consommation de processeur du serveur est le plus important;
La deuxième méthode: le plus de temps est utilisé et la consommation de processeur du serveur est centrée;
La troisième méthode: longue et centrée, la consommation de processeur du serveur est minime.
À ce stade, JDBC a finalement fait quelques petites choses dans le fonctionnement des données de type XMLTYPE. Inutile de dire que la troisième solution est adoptée, mais le projet n'utilise essentiellement pas directement JDBC pour fonctionner. Par exemple, dans le projet actuel, MyBatis est utilisé. Ce qui précède a également mentionné qu'il y a toujours des exceptions lors de l'utilisation de MyBatis. Après avoir vérifié MyBatis, il n'y a pas de mise en œuvre de XMLType. Il semble qu'il y ait encore des problèmes, mais JDBC a été fait, donc l'idée est claire, non?
Mybatis
En utilisant MyBatis pour faire fonctionner XMLTYPE, nous mappes également en type de chaîne du côté Java. Lorsque l'opération directe ne fait aucun traitement, comme JDBC, tout est normal lorsque le contenu transmis est inférieur à 4000. Lorsque le contenu transmis est supérieur à 4000, une exception est également lancée:
ORA-01461: ne peut lier une longue valeur que pour l'insert dans une longue colonne
On peut voir que le fonctionnement de MyBatis est en fait le même que JDBC, sauf qu'il résume une couche en dehors de JDBC, afin que nous puissions utiliser des fichiers de configuration et d'autres méthodes de mappage pour accéder plus commodément à la base de données. Ce que nous devons faire est d'insérer des données de type XMLType basées sur la commodité d'origine MyBatis. Dans ce cas, la mise en œuvre d'un processeur de type personnalisé de type XMLTYPE est le meilleur choix.
Ici, nous utilisons toujours la solution trois mentionnée ci-dessus. Naturellement, les deux packages JAR: xdb.jar et xmlparserv2.jar doivent également être ajoutés.
Ajoutez un XMLTypetypeHandler pour implémenter l'interface TypeHandler. Étant donné que l'insertion de données utilise principalement la méthode SetParameter, seule cette méthode est répertoriée ici. L'autre code de méthode est omis:
/ ** * Oracle Sys.xmlType Type Processeur personnalisé * / public class XmlTypeTyPyTyPhandler implémente TypeHandler <string> {@Override public void SetParameter (préparé PS, int I, String Paramètre, JDBCTYPE JDBCTYPE) lance Sqlexception {} ...}Cette méthode SetParameter est utilisée par MyBatis pour définir des paramètres lors de l'insertion de données dans la base de données. Quant aux paramètres de cette méthode, je crois que vous avez déjà compris le code. Nous insérerons ici le code suivant selon la méthode d'implémentation JDBC précédente:
public void setParameter (préparé PS, int i, paramètre de chaîne, jdbcType jdbcType) lève sqlexception {xmltype xmlType = xmlType.CreateExml (ps.getConnection (), paramètre); Ps.SetObject (i, xmlType);}Et enregistrer le convertisseur dans Mappe-Config.xml, car dans l'énumération définie par Mybatis org.apache.ibatis.type.jdbcType, il n'y a pas de type xmltype dont nous avons besoin, nous le définissons ici comme non défini:
<FIFIGRAGE> <TypeHandlers> <TypeHandler javatype = "String" jdbcType = "Undefined" handler = "com.tyyd.dw.context.xmltypetypeHandler" /> </ typeHandlers> </ Configuration>
Dans les paramètres de fichier de configuration, utilisez notre convertisseur défini afin que MyBatis puisse le trouver:
# {xmlfile, jdbcType = undefined},Bien sûr, vous pouvez également être plus standardisé et écrire son type et le convertisseur que vous utilisez de manière complète:
# {xmlfile, javatype = string, jdbcType = undefined, typeHandler = com.tyyd.dw.context.xmltypetypehandler}
Complétez les étapes ci-dessus et logiquement tout est fait, exécutons-le.
Le résultat est lancé: java.lang.ClassCastException: org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to oracle.jdbc.OracleConnection
Il ne peut pas être converti en Oracle d'objet d'Oracle OracleConnection. Après vérification, nous avons constaté que notre source de données utilise le DBCP d'Apache, qui devrait être incompatible avec les deux. J'ai vérifié en ligne et un gars a dit qu'il avait donné une solution parfaite, qui est de charger une classe de pilote Oracle dans la méthode SetParameter pour créer une connexion, comme suit:
Class.forname ("oracle.jdbc.oracledriver"); connexion connexion = driverManager.getConnection (url, nom d'utilisateur, mot de passe);Cela peut en effet résoudre le problème que l'objet Connexion ne peut pas être converti à 100%, mais en termes de mise en œuvre, haha, je ne commenterai toujours pas. Il y a aussi des gens qui traversent Internet, disant qu'ils peuvent être convertis en un objet PoolableConnection, puis utiliser la méthode GetDelegate pour obtenir le lien proxy d'origine. Cela semble possible, essayons:
PoolableConnection Connection = (PoolableConnection) ps.GetConnection (); xmlType xmlType = xmlType.CreateExml (Connection.getDelegate (), paramètre); ps.SetObject (i, xmlType);
En conséquence, une autre exception a été lancée:
org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to org.apache.commons.dbcp.PoolableConnection , ne peut pas être converti.
Il n'y a aucun moyen, il semble que les articles circulant en ligne ne soient pas fiables, il n'y a donc pas de raccourci, vous devez donc vérifier le code source vous-même.
En regardant le code source, nous avons constaté que PoolableConnection hérite de la classe de connexion de délégation et que la classe DelegatingConnection implémente l'interface de connexion. Convertissons-le en une connexion déléguée pour essayer:
DelégationConnection Connection = (DelegatingConnection) ps.GetConnection (); xmlType xmlType = xmlType.CreateExml (Connection.getDelegate (), paramètre); Ps.SetObject (i, xmlType);
En conséquence, une exception a été lancée: incapable de construire des descripteurs: arguments non valides; L'exception imbriquée est java.sql.sqlexception: Impossible de construire des descripteurs: arguments non valides, par le débogage de points d'arrêt, j'ai constaté que l'objet de connexion est en fait nul. Comment pourrait-il être nul? Les gens sur Internet l'utilisent bien, mais cela ne fonctionnera pas avec moi. C'est vraiment une douleur. Ce n'est pas insoluble. Devez-vous vraiment charger un cours de pilote seul comme le gars ci-dessus l'a dit? Il n'y a aucun moyen, étudions à nouveau.
Enfin, j'ai constaté que la connexion proxy d'origine peut être obtenue via la méthode Getmetadata. Il est si brillant et le test est si clair. C'est enfin normal et pas facile. Le code final est le suivant:
@OverRIDEPUBLIC void SetParameter (préparéStatement PS, int i, paramètre de chaîne, jdbcType jdbcType) lève SqException {DelegatingConnection Connection = (DelegatingConnection) ps.getConnection (). GetMetAdata () .getConnection (); XmlType xmlType = xmlType.CreateExml (connexion.getDelegate (), paramètre); Ps.SetObject (i, xmlType);}À ce stade, l'utilisation de MyBatis pour faire fonctionner les types XMLType a finalement été effectuée, et le processus est plein de rebondissements. Bien sûr, il doit y avoir des questions lorsque les données sont insérées. Ensuite, nous devons implémenter les opérations de requête de type XMLTYPE.