Vamos primeiro entender o que é o tipo XMLType.
O XMLTYPE é um tipo de dados exclusivo para o Oracle desde 9i. É uma existência poderosa que herda a bolha. Ele pode ser usado para armazenar XML e fornece muitas funções de operação. Em teoria, ele pode salvar dados 2G.
Então, como você insira dados XMLType através do Java? O projeto usa Mybatis e sempre há exceções inexplicáveis. Não consigo descobrir se é o problema do Mybatis ou o próprio JDBC, então pretendo fazê -lo passo a passo, primeiro resolva o JDBC e depois resolva Mybatis.
JDBC
Depois de um longo tempo de luta, descobri que existem três métodos principais para a operação JDBC:
1. Use XMLType como uma string string em java, e a tarefa específica de criar XMLType é completamente entregue ao banco de dados:
String sql = "inserir nos valores xmltable (xml) (sys.xmltype.createxml (?))"; String xmldata = "<brety> Este é um fragmento XML </celt>"; ps.SetString (1, xmldata); ps.execUteUpdate ();
Esse método tornará muito o estresse do banco de dados, porque esse método é simples e não requer dependências adicionais. Esse método foi usado no início, mas durante o uso real, verificou-se que quando o comprimento do conteúdo excede cerca de 4000, ele lançará: ORA-01461: pode vincular um valor longo apenas para inserção em uma longa exceção da coluna. No começo, pensei que o motivo do uso do mybatis ainda era o mesmo ao usar o teste JDBC, e não havia solução ao usar muitos métodos. É impossível salvar dados com um comprimento inferior a 4000 ao usar esse campo grande no projeto. Dessa forma, o uso do VARCHAR2 é suficiente, então esse método é eliminado.
2. Use o tipo CLOB para operar. O XMLTYPE herda a existência de CLOB, para que possa ser operado através do CLOB. O método é criar dados CLOB no cliente e passá -lo para o banco de dados para construir o valor xmltype através da função xmltype () da Oracle:
String sql = "inserir nos valores xmltable (xml) (xmltype (?))"; String xmldata = "<brety> Este é um fragmento XML </celt>"; // crie clobclob tempclob = clob.createTemporary (conexão, false, clob.duration_session); // Abra CLOBTempClob.open (clob.mode_readwrite); // obtive writerwriter clobwriter = tempclob.setcharacterream (100); // grava dados clobwriter.write (xmldata); // fresh clobwriter.flush (); // estreita writerclobwriter.close (); // fechar clobtemp.close (); pst.setObject (1, tempclob);
Esse cliente e banco de dados de método são responsáveis pela criação do XMLTYPE ao mesmo tempo, portanto a pressão é relativamente média e não há problema de exceder o comprimento. No entanto, durante o uso real, verificou -se que o cabeçalho de conteúdo do XML não pode conter as seguintes informações:
<? xml versão = "1.0" coding = "utf-8"?>
Caso contrário, uma exceção será lançada:
Os nomes de PI começando com XML são reservados
Não vamos falar sobre se você encontrará algum problema de código distorcido ao processar o conteúdo da inclusão XML em chinês no futuro. Só de olhar para isso faz as pessoas se sentirem desconfortáveis, e os requisitos também exigem economia. Não há como, e esse método não funcionará.
3. Use a classe oracle.xdb.xmltype fornecida pelo Oracle. Depois que o cliente cria xmltype, o objeto é passado diretamente para o banco de dados:
Conexão Conn = ...; // Obter conexão Preparadostatement ps = ...; // Obtenha a String String SQL = "inserir em valores xmltable (xml) (?)"; String xmldata = "<brety> Este é um fragmento XML </celt>"; // Crie um objeto xmltype xmltype xmltype = xmltype.createxml (Conn, xmldata); ps.setObject (1, xmltype); ps.execUteUpdate ();
Esse método entrega completamente a tarefa de criar XMLType para o cliente, para que o cliente esteja sob grande pressão e o banco de dados esteja sob baixa pressão. Durante o teste real, dois pacotes JAR precisam ser adicionados; caso contrário, a classe não pode ser encontrada erro:
XDB.JARXMLPARSERV2.JAR
É necessário observar que este pacote JAR não possui anotação de versão, por isso é fácil cometer erros. No começo, baixei um xdb.jar, mas não importa como fiz isso, foi solicitado que eu não conseguisse encontrar uma determinada classe. Depois de verificar, descobri que ele pertence a uma versão anterior do Oracle. Depois de baixar um xdb.jar novamente, é normal.
Os três métodos acima foram comparados inserindo 200.000 dados:
O primeiro método: o menor tempo e o consumo de CPU do servidor é o maior;
O segundo método: o tempo mais longo é usado e o consumo de CPU do servidor é centrado;
O terceiro método: demorado e centrado, o consumo de CPU do servidor é mínimo.
Nesse ponto, o JDBC finalmente fez algumas pequenas coisas na operação de dados do tipo XMLTYPE. Escusado será dizer que a terceira solução é adotada, mas o projeto basicamente não usa diretamente o JDBC para operar. Por exemplo, no projeto atual, o mybatis é usado. O acima mencionou também que sempre há exceções ao usar o Mybatis. Depois de verificar o Mybatis, não há implementação do XMLTYPE. Parece que ainda existem alguns problemas, mas o JDBC foi feito, então a ideia é clara, certo?
Mybatis
Usando o mybatis para operar o XMLType, também mapeamos o tipo de string no lado java. Quando a operação direta não faz nenhum processamento, como o JDBC, tudo é normal quando o conteúdo transmitido é inferior a 4000. Quando o conteúdo transmitido é superior a cerca de 4000, uma exceção também é lançada:
ORA-01461: pode ligar um valor longo apenas para inserção em uma coluna longa
Pode -se observar que a operação da Mybatis é realmente a mesma que o JDBC, exceto que ele encapsula uma camada fora do JDBC, para que possamos usar arquivos de configuração e outros métodos de mapeamento para acessar mais convenientemente o banco de dados. O que precisamos fazer é inserir dados do tipo XMLType com base na conveniência original do Mybatis. Nesse caso, a implementação de um processador TypeHandler personalizado do tipo XMLType é a melhor opção.
Aqui, ainda usamos a solução três mencionadas acima. Naturalmente, os dois pacotes JAR: XDB.JAR e XMLPARSERV2.JAR também precisam ser adicionados.
Adicione um XMLTYPETYPEHANDLER para implementar a interface TypeHandler. Como a inserção de dados usa principalmente o método setParameter, apenas esse método está listado aqui. O outro código do método é omitido:
/*** Oracle sys.xmltype Tipo Processador personalizado*/public class XmltypeTypeHandler implementa TypeHandler <String> {@Override public void setParameter (preparado PS, int i, parâmetro de string, JDBCTYPE JDBCTYPE) lança sqlexception {}}…Esse método setParameter é usado pelo MyBatis para definir parâmetros ao inserir dados no banco de dados. Quanto aos parâmetros deste método, acredito que você já entendeu o código. Inseriremos o seguinte código aqui de acordo com o método anterior de implementação do JDBC:
public void setParameter (preparado PS, int i, parâmetro de string, jdbctype jdbctype) lança sqlexception {xmltype xmltype = xmltype.createxml (Ps.getConnection (), parâmetro); ps.setObject (i, xmltype);}E registre o conversor em mapero-config.xml, porque na enumeração definida por mybatis org.apache.ibatis.type.jdbctype, não há tipo de xmltype que precisamos, aqui o definimos como indefinido:
<figuration> <TepeHandlers> <typeHandler javatype = "string" jdbctype = "undefined" handler = "com.tyyyd.dw.context.xmltypetypehandler"/> </typeHandlers> </figuration>
Nos parâmetros do arquivo de configuração, use nosso conversor definido para que Mybatis possa encontrá -lo:
#{xmlfile, jdbctype = indefinido},Obviamente, você também pode ser mais padronizado e escrever seu tipo e o conversor que usa de maneira completa:
#{xmlfile, javatype = string, jdbctype = indefinido, typeHandler = com.tyyd.dw.context.xmltypetyndler},
Complete as etapas acima e logicamente tudo está feito, vamos executá -lo.
O resultado é lançado: java.lang.ClassCastException: org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to oracle.jdbc.OracleConnection
Não pode ser convertido no objeto de conexão da Oracle ORACLECONNECÇÃO. Após a verificação, descobrimos que nossa fonte de dados usa o DBCP da Apache, que deve ser incompatível com os dois. Eu verifiquei on -line e um cara disse que ele deu uma solução perfeita, que é carregar uma classe de motorista Oracle no método setParameter para criar uma conexão, como segue:
Class.ForName ("oracle.jdbc.oracledriver"); conexão de conexão = driverManager.getConnection (URL, nome de usuário, senha);Isso pode realmente resolver o problema de que o objeto de conexão não pode ser convertido 100%, mas em termos de implementação, haha, ainda não vou comentar. Há também pessoas que passam pela Internet, dizendo que podem ser convertidas em um objeto PoolableConnection e, em seguida, usam o método getDelegate para obter o link de proxy original. Isso parece viável, vamos tentar:
Conexão PoolableConnection = (PoolableConnection) Ps.getConnection (); xmltype xmltype = xmltype.createxml (conexão.getDelegate (), parâmetro); ps.setObject (i, xmltype);
Como resultado, outra exceção foi lançada:
org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to org.apache.commons.dbcp.PoolableConnection , não pode ser convertido.
Não há como, parece que os artigos que circulavam on -line não são confiáveis; portanto, não há atalho, então você deve verificar o código -fonte.
Observando o código -fonte, descobrimos que a PoolableConnection herda a classe DelegatingConnection e a classe DelegatingConnection implementa a interface de conexão. Vamos convertê -lo em uma delegatingConnection para tentar:
DelegatingConnection Connection = (DelegatingConnection) Ps.getConnection (); xmltype xmltype = xmltype.createxml (conexão.getDelegate (), parâmetro); Ps.setObject (i, xmltype);
Como resultado, foi lançada uma exceção: incapaz de construir descritores: argumentos inválidos; Exceção aninhada é Java.SQL.SQLEXCECTION: Não é possível construir descritores: argumentos inválidos, através da depuração do ponto de interrupção, descobri que o objeto de conexão é realmente nulo. Como poderia ser nulo? As pessoas na Internet usam bem, mas não funcionam comigo. É realmente uma dor. Isso não é insolúvel. Você realmente tem que carregar uma aula de motorista sozinha, como disse o cara acima? Não há como estudá -lo novamente.
Finalmente, descobri que a conexão proxy original pode ser obtida através do método getMetadata. É tão brilhante e o teste é tão claro. Finalmente é normal e não é fácil. O código final é o seguinte:
@OverridePublic void setParameter (preparado PS, int i, parâmetro de string, jdbctype jdbctype) lança sqlexception {delegatingConnection conexão = (delegatingConnection) ps.getConnection (). GetMetadata () .getConnection (); Xmltype xmltype = xmltype.createxml (conexão.getDelegate (), parâmetro); ps.setObject (i, xmltype);}Nesse ponto, o uso de Mybatis para operar os tipos XMLType finalmente foi realizado e o processo está cheio de reviravoltas. Obviamente, deve haver consultas quando os dados são inseridos. Em seguida, precisamos implementar operações de consulta do tipo XMLType.