まず、XMLTYPEタイプとは何かを理解しましょう。
XMLTYPEは、9i以来のOracleのユニークなデータ型です。それは塊を継承する強力な存在です。 XMLを保存するために使用でき、多くの操作機能を提供します。理論的には、2Gデータを保存できます。
では、Javaを介してXMLTYPEデータをどのように挿入しますか?このプロジェクトはMyBatisを使用しており、常に不可解な例外があります。それがMybatisの問題であるかJDBC自体であるかを理解できないので、段階的にそれを行い、最初にJDBCを解き、次にMybatisを解決する予定です。
JDBC
長い闘争の後、JDBC操作には3つの主要な方法があることがわかりました。
1. xmltypeをJavaの文字列として使用すると、xmltypeを作成する特定のタスクがデータベースに完全に引き渡されます。
string sql = "xmltable(xml)値に挿入(sys.xmltype.createxml(?))"; string xmldata = "<label>これはxmlフラグメント</label>"; ps.setString(1、xmldata); ps.executeUpdate();
この方法は、この方法が単純であり、追加の依存関係を必要としないため、データベースのストレスが多すぎます。この方法は最初に使用されていましたが、実際の使用中に、コンテンツの長さが約4000を超えると、ORA-01461:長い列の例外に挿入のためにのみ長い値にバインドできることがわかりました。最初は、JDBCテストを使用する場合、MyBatisを使用する理由は依然として同じであり、多くの方法を使用する場合は解決策がなかったと思いました。プロジェクトでこの大きなフィールドを使用する場合、長さ4000未満のデータを保存することは不可能です。このようにして、Varchar2を使用するだけで十分なため、この方法は排除されます。
2。CLOBタイプを使用して操作します。 XMLTYPEはCLOBの存在を継承するため、CLOBを介して動作できます。この方法は、クライアントにCLOBデータを作成し、それをデータベースに渡して、OracleのXMLType()関数を介してXMLType値を構築することです。
string sql = "xmltable(xml)値(xmltype(?))に挿入string xmldata = "<label>これはxmlフラグメント</label>"; // clobclob tempclob = clob.createTemporary(connection、false、clob.duration_session); // clobtempclob.openを開く(clob.mode_readwrite); // get Writterwriter clobwriter = tempclob.setcharacterstream(100); // write data clobwriter.write(xmldata); // freshclobwriter.flush(); // close writerclobwriter.close(); // close clobtempclob.close(); pst.setobject(1、tempclob);
このメソッドクライアントとデータベースは、XMLTypeを同時に作成する責任があるため、圧力は比較的平均的であり、長さを超える問題はありません。ただし、実際の使用中に、XMLのコンテンツヘッダーには次の情報が含まれないことがわかりました。
<?xml version = "1.0" encoding = "utf-8"?>
それ以外の場合は、例外がスローされます。
XMLで始まるPI名は予約されています
将来、中国語でXMLインクルージョンのコンテンツを処理するときに、文字化けしたコードの問題に遭遇するかどうかについて話しないでください。それを見るだけで、人々は不快感を覚え、要件にも節約が必要です。方法はありません。この方法は機能しません。
3。Oracleが提供するOracle.xdb.xmltypeクラスを使用します。クライアントがXMLTYPEを作成した後、オブジェクトはデータベースに直接渡されます。
接続conn = ...; //接続準備ps = ...; // reportsatement string sql = "xmltable(xml)values(?)"に挿入します "; string xmldata = "<label>これはxmlフラグメント</label>"; // xmltypeオブジェクトを作成xmltype xmltype = xmltype.createxml(conn、xmldata); ps.setobject(1、xmltype); ps.executeUpdate();
この方法は、クライアントにXMLTypeを作成するタスクを完全に渡すため、クライアントは大きなプレッシャーにさらされており、データベースは低圧になります。実際のテスト中に、2つのJARパッケージを追加する必要があります。そうしないと、クラスが見つかりませんエラー:
xdb.jarxmlparserv2.jar
このJARパッケージにはバージョンの注釈がないため、間違いを犯すのは簡単です。最初はXDB.jarをダウンロードしましたが、どのようにしても、特定のクラスを見つけることができないことが促されました。チェックした後、私はそれが以前のバージョンのOracleに属していることを発見しました。 xdb.jarをもう一度ダウンロードした後、それは正常です。
上記の3つの方法は、200,000個のデータを挿入することによって比較されました。
最初の方法:最短時間とサーバーCPU消費は最大です。
2番目の方法:最も長い時間が使用され、サーバーCPUの消費が中心です。
3番目の方法:時間がかかり、中央にあるサーバーCPUの消費は最小限です。
この時点で、JDBCはついにXMLTYPEタイプデータの操作でいくつかの小さなことを行いました。言うまでもなく、3番目のソリューションが採用されていますが、プロジェクトは基本的にJDBCを直接使用して動作しません。たとえば、現在のプロジェクトでは、MyBatisが使用されています。上記は、MyBatisを使用する場合は常に例外があることも述べています。 MyBatisをチェックした後、XMLTYPEの実装はありません。まだいくつかのトラブルがあるようですが、JDBCが行われたので、アイデアは明確ですよね?
mybatis
MyBatisを使用してXMLTypeを操作すると、Java側の文字列タイプにもマッピングされます。直接操作がJDBCのように処理を行わない場合、送信されたコンテンツが4000未満の場合、すべてが正常です。送信されたコンテンツが約4000を超える場合、例外もスローされます。
ORA-01461:長い列に挿入するためだけに長い値をバインドできます
MyBatisの操作は実際にはJDBCと同じであることがわかりますが、JDBCの外側のレイヤーをカプセル化しているため、構成ファイルやその他のマッピングメソッドを使用して、データベースに便利にアクセスできます。私たちがする必要があるのは、元のMyBatisの利便性に基づいてXMLTYPEタイプデータを挿入することです。この場合、XMLTYPEタイプのカスタムTypeHandlerプロセッサを実装することが最良の選択です。
ここでは、上記のソリューション3を使用しています。当然、2つのJARパッケージ:XDB.JARとXMLPARSERV2.JARも追加する必要があります。
xmltypetypehandlerを追加して、typehandlerインターフェイスを実装します。データの挿入は主にSetParameterメソッドを使用するため、この方法のみがここにリストされています。他のメソッドコードは省略されています。
/*** ORACLE SYS.XMLTYPEタイプカスタムプロセッサ*/パブリッククラスXMLTYPETYPETYPEHANDLERSEMPLEMENTS TYPEHANDLER <STRING> {@Override public void setParameter(predetStatement ps、int i、string parameter、jdbctype jdbctype)スローSqlexception {} ...} ...}このSetParameterメソッドは、データベースにデータを挿入するときにパラメーターを設定するためにMyBatisによって使用されます。この方法のパラメーターについては、あなたはすでにコードを理解していると思います。以前のJDBC実装方法に従って、次のコードをここに挿入します。
public void setParameter(preatedStatement PS、int i、string parameter、jdbctype jdbctype)sqlexception {xmltype xmltype = xmltype.createxml(ps.getConnection()、パラメーター); ps.setObject(i、xmltype);}Mybatis org.apache.ibatis.type.jdbctypeで定義された列挙では、必要なxmltypeタイプはありません。ここでは定義されていないと定義するため、コンバーターをmapper-config.xmlに登録します。
<configuration> <typehandlers> <typehandler javatype = "string" jdbctype = "undefined" handler = "com.tyyd.dw.context.xmltypetypehandler"/> </typehandlers> </configuration>
構成ファイルパラメーターで、MyBatisがそれを見つけることができるように、定義されたコンバーターを使用してください。
#{xmlfile、jdbctype = undefined}、もちろん、より標準化され、そのタイプと使用したコンバーターを完全な方法で書き出すこともできます。
#{xmlfile、javatype = string、jdbctype = undefined、typehandler = com.tyyd.dw.context.xmltypetypehandler}、
上記の手順を完了すると、論理的にすべてが完了します。実行しましょう。
結果がスローされます: java.lang.ClassCastException: org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to oracle.jdbc.OracleConnection
Oracleの接続オブジェクトOracLeconnectionに変換することはできません。チェック後、データソースはApacheのDBCPを使用していることがわかりました。これは2つと互換性がありません。私はオンラインでチェックしましたが、男は彼が完璧なソリューションを提供したと言いました。これは、次のように、SetParameterメソッドにOracle Driverクラスをロードして接続を作成することです。
class.forname( "oracle.jdbc.oracledriver"); connection connection = drivermanager.getConnection(url、username、password);
これにより、接続オブジェクトを100%変換できないという問題を実際に解決できますが、実装の観点からは、私はまだコメントしません。また、インターネットを渡す人もいます。それらはPoolableConnectionオブジェクトに変換できると言って、GetDelegateメソッドを使用して元のプロキシリンクを取得します。これは実行可能です、試してみましょう:
poolableconnection connection =(poolableconnection)ps.getConnection(); xmltype xmltype = xmltype.createxml(connection.getDelegate()、parameter); ps.setObject(i、xmltype);
その結果、別の例外がスローされました。
org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to org.apache.commons.dbcp.PoolableConnection 。変換できません。
方法はありません。オンラインで流通している記事は信頼できないため、ショートカットはありませんので、ソースコードを自分で確認する必要があります。
ソースコードを見ると、PoolableConnectionがDelegatingConnectionクラスを継承し、DelegatingConnectionクラスが接続インターフェイスを実装することがわかりました。それを委任接続に変換して、次のことを試してみましょう。
DelegatingConnection Connection =(DelegatingConnection)ps.getConnection(); xmltype xmltype = xmltype.createxml(connection.getDelegate()、parameter); ps.setObject(i、xmltype);
その結果、例外がスローされました。記述子を構築できません:無効な引数。ネストされた例外はjava.sql.sqlexception:記述子を構築できません:無効な引数、ブレークポイントのデバッグを通じて、接続オブジェクトが実際にnullであることがわかりました。どうしてnullになるのでしょうか?インターネット上の人々はそれをうまく使用しますが、それは私とはうまくいきません。それは本当に痛みです。これは解決できません。上記の男が言ったように、あなたは本当にドライバークラスだけをロードする必要がありますか?方法はありません、もう一度勉強しましょう。
最後に、元のプロキシ接続をGetMetadataメソッドを使用して取得できることがわかりました。それはとても明るく、テストはとても明確です。最終的に正常であり、簡単ではありません。最終コードは次のとおりです。
@OverridePublic void setParameter(preatedStatement PS、int i、stringパラメーター、jdbctype jdbctype)sqlexception {DelegatingConnection Connection =(DelegatingConnection)ps.GetConnection()。GetMetadata().GetConnection().GetConnection(); xmltype xmltype = xmltype.createxml(connection.getDelegate()、parameter); ps.setObject(i、xmltype);}この時点で、MyBatisを使用してXMLTYPEタイプを操作することが最終的に行われ、プロセスはtwist余曲折に満ちています。もちろん、データが挿入されるときにクエリが必要です。次に、XMLTYPEタイプクエリ操作を実装する必要があります。