Pertama -tama mari kita pahami apa tipe xmlType.
XMLType adalah tipe data yang unik untuk Oracle sejak 9i. Ini adalah keberadaan yang kuat yang mewarisi gumpalan. Ini dapat digunakan untuk menyimpan XML dan menyediakan banyak fungsi operasi. Secara teori, dapat menyimpan data 2G.
Jadi, bagaimana Anda memasukkan data xmlType melalui java? Proyek ini menggunakan mybatis, dan selalu ada pengecualian yang tidak dapat dijelaskan. Saya tidak tahu apakah itu masalah mybatis atau jdbc itu sendiri, jadi saya berencana untuk melakukannya langkah demi langkah, pertama -tama selesaikan JDBC, dan kemudian selesaikan mybatis.
Jdbc
Setelah perjuangan yang lama, saya menemukan bahwa ada tiga metode utama untuk operasi JDBC:
1. Gunakan xmlType sebagai string string di java, dan tugas spesifik untuk membuat xmlType sepenuhnya diserahkan ke database:
String sql = "masukkan ke dalam nilai xmltable (xml) (sys.xmltype.createexml (?))"; String xmldata = "<label> Ini adalah fragmen xml </label>"; ps.setstring (1, xmldata); ps.executeUpdate ();
Metode ini akan membuat stres basis data terlalu banyak, karena metode ini sederhana dan tidak memerlukan dependensi tambahan. Metode ini digunakan di awal, tetapi selama penggunaan aktual, ditemukan bahwa ketika panjang konten melebihi sekitar 4000, itu akan melempar: ORA-01461: dapat mengikat nilai panjang hanya untuk dimasukkan ke dalam pengecualian kolom panjang. Pada awalnya saya pikir alasan menggunakan mybatis masih sama ketika menggunakan tes JDBC, dan tidak ada solusi saat menggunakan banyak metode. Tidak mungkin untuk menyimpan data dengan panjang kurang dari 4000 saat menggunakan bidang besar ini dalam proyek. Dengan cara ini, menggunakan varchar2 sudah cukup, jadi metode ini dihilangkan.
2. Gunakan tipe clob untuk beroperasi. XmlType mewarisi keberadaan clob, sehingga dapat dioperasikan melalui clob. Metode ini adalah membuat data clob pada klien dan meneruskannya ke dalam database untuk membangun nilai xmlType melalui fungsi XMLType () Oracle:
String sql = "masukkan ke dalam nilai xmltable (xml) (xmlType (?))"; String xmldata = "<label> Ini adalah fragmen xml </label>"; // buat clobclob tempclob = clob.createTemporary (koneksi, false, clob.duration_session); // buka clobtempclob.open (clob.mode_readwrite); // Dapatkan penulis penulis clobwriter = tempclob.setcharacterstream (100); // tulis data clobwriter.write (xmldata); // fresh clobwriter.flush (); // tutup writerclobwriter.close (); // tutup clobtempclob.close (); PST.SetObject (1, templob);
Metode ini klien dan basis data bertanggung jawab untuk membuat xmlType pada saat yang sama, sehingga tekanannya relatif rata -rata dan tidak ada masalah melebihi panjangnya. Namun, selama penggunaan aktual, ditemukan bahwa header konten XML tidak dapat berisi informasi berikut:
<? Xml Version = "1.0" encoding = "UTF-8"?>
Jika tidak, pengecualian akan dilemparkan:
Nama pi yang dimulai dengan XML dicadangkan
Jangan bicarakan apakah Anda akan menghadapi masalah kode kacau saat memproses konten inklusi XML dalam bahasa Cina di masa depan. Hanya melihatnya membuat orang merasa tidak nyaman, dan persyaratannya juga membutuhkan penghematan. Tidak mungkin, dan metode ini tidak akan berhasil.
3. Gunakan kelas Oracle.xdb.xmlType yang disediakan oleh Oracle. Setelah klien membuat xmlType, objek langsung diteruskan ke database:
Koneksi conn = ...; // Dapatkan koneksi disiapkan ps = ...;; // dapatkan string disiapkan sql = "masukkan ke dalam nilai xmltable (xml) (?)"; String xmldata = "<label> Ini adalah fragmen xml </label>"; // Buat objek XMLType xmlType xmltype = xmltype.createexml (conn, xmldata); ps.setObject (1, xmlType); ps.executeUpdate ();
Metode ini sepenuhnya memberikan tugas membuat xmlType ke klien, sehingga klien berada di bawah tekanan besar dan database berada di bawah tekanan rendah. Selama tes aktual, dua paket JAR perlu ditambahkan, jika tidak, kelas tidak dapat ditemukan kesalahan:
xdb.jarxmlparserv2.jar
Penting untuk dicatat bahwa paket JAR ini tidak memiliki anotasi versi, jadi mudah untuk membuat kesalahan. Pada awalnya, saya mengunduh XDB.Jar, tetapi tidak peduli bagaimana saya melakukannya, diminta bahwa saya tidak dapat menemukan kelas tertentu. Setelah memeriksa, saya menemukan bahwa itu milik Oracle versi sebelumnya. Setelah mengunduh XDB.Jar lagi, itu normal.
Tiga metode di atas dibandingkan dengan memasukkan 200.000 data:
Metode pertama: waktu terpendek dan konsumsi CPU server adalah yang terbesar;
Metode kedua: waktu terpanjang digunakan, dan konsumsi CPU server terpusat;
Metode ketiga: memakan waktu dan terpusat, konsumsi CPU server minimal.
Pada titik ini, JDBC akhirnya melakukan beberapa hal kecil dalam pengoperasian data tipe XMLType. Tak perlu dikatakan, solusi ketiga diadopsi, tetapi proyek pada dasarnya tidak secara langsung menggunakan JDBC untuk beroperasi. Misalnya, dalam proyek saat ini, MyBatis digunakan. Di atas juga menyebutkan bahwa selalu ada pengecualian saat menggunakan mybatis. Setelah memeriksa mybatis, tidak ada implementasi xmlType. Tampaknya masih ada beberapa masalah, tetapi JDBC telah dilakukan, jadi idenya jelas, bukan?
Mybatis
Menggunakan mybatis untuk mengoperasikan xmlType, kami juga memetakan jenis string di sisi java. Ketika operasi langsung tidak melakukan pemrosesan, seperti JDBC, semuanya normal ketika konten yang ditransmisikan kurang dari 4000. Ketika konten yang ditransmisikan lebih dari sekitar 4000, pengecualian juga dilemparkan:
ORA-01461: Dapat mengikat nilai panjang hanya untuk dimasukkan ke dalam kolom yang panjang
Dapat dilihat bahwa operasi MyBatis sebenarnya sama dengan JDBC, kecuali bahwa ia merangkum lapisan di luar JDBC, sehingga kami dapat menggunakan file konfigurasi dan metode pemetaan lainnya untuk lebih mudah mengakses database. Yang perlu kita lakukan adalah memasukkan data tipe xmlType berdasarkan kenyamanan mybatis asli. Dalam hal ini, menerapkan prosesor tipe XMLType kustom adalah pilihan terbaik.
Di sini, kami masih menggunakan solusi tiga yang disebutkan di atas. Secara alami, dua paket toples: xdb.jar dan xmlparserv2.jar juga perlu ditambahkan.
Tambahkan xmltypetypehandler untuk mengimplementasikan antarmuka TypeHandler. Karena memasukkan data terutama menggunakan metode setParameter, hanya metode ini yang tercantum di sini. Kode metode lainnya dihilangkan:
/*** oracle sys.xmlType Jenis prosesor kustom*/kelas publik xmltypetypehandler mengimplementasikan typeHandler <string> {@Override public void setParameter (disiapkan PS, int i, parameter string, jdbctype jdbctype) melempar sqlexception {} ...}Metode setParameter ini digunakan oleh MyBatis untuk mengatur parameter saat memasukkan data ke dalam database. Adapun parameter metode ini, saya yakin Anda sudah memahami kode. Kami akan memasukkan kode berikut di sini sesuai dengan metode implementasi JDBC sebelumnya:
setParameter public void (disiapkan PS, int i, parameter string, jdbctype jdbctype) melempar sqlexception {xmlType xmltype = xmltype.createexml (ps.getConnection (), parameter); ps.setObject (i, xmltype);}Dan daftarkan konverter di mapper-config.xml, karena dalam enumerasi yang ditentukan oleh mybatis org.apache.iathis.type.jdbctype, tidak ada tipe xmltype yang kita butuhkan, di sini kita mendefinisikannya sebagai tidak terdefinisi:
<Configuration> <exhandlers> <typeHandler javatype = "string" jdbctype = "tidak terdefinisi" handler = "com.tyyd.dw.context.xmlTypetypehandler"/> </peiphandlers> </onfiguration>
Dalam parameter file konfigurasi, gunakan konverter yang ditentukan sehingga mybatis dapat menemukannya:
#{xmlfile, jdbctype = tidak terdefinisi},Tentu saja, Anda juga dapat lebih terstandarisasi dan menuliskan jenisnya dan konverter yang Anda gunakan secara lengkap:
#{xmlfile, javatype = string, jdbctype = undefined, typeHandler = com.tyyd.dw.context.xmlTypetypehandler},
Lengkapi langkah -langkah di atas dan secara logis semuanya dilakukan, mari kita jalankan.
Hasilnya dilemparkan: java.lang.ClassCastException: org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to oracle.jdbc.OracleConnection
Itu tidak dapat dikonversi menjadi objek koneksi Oracle Oracleconnection. Setelah memeriksa, kami menemukan bahwa sumber data kami menggunakan DBCP Apache, yang seharusnya tidak kompatibel dengan keduanya. Saya memeriksa secara online dan seorang pria mengatakan bahwa dia memberikan solusi yang sempurna, yaitu memuat kelas driver Oracle dalam metode setParameter untuk membuat koneksi, sebagai berikut:
Class.forname ("oracle.jdbc.oracledriver"); koneksi koneksi = driverManager.getConnection (url, nama pengguna, kata sandi);Ini memang dapat menyelesaikan masalah bahwa objek koneksi tidak dapat dikonversi 100%, tetapi dalam hal implementasi, haha, saya masih tidak akan berkomentar. Ada juga orang -orang yang melewati internet, mengatakan bahwa mereka dapat dikonversi menjadi objek PoolableConnection, dan kemudian menggunakan metode GetDelegate untuk mendapatkan tautan proxy asli. Ini tampaknya layak, mari kita coba:
Poolableconnection connection = (poolableconnection) ps.getConnection (); xmltype xmltype = xmltype.createxml (connection.getDelegate (), parameter); ps.setObject (i, xmltype);
Akibatnya, pengecualian lain dilemparkan:
org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to org.apache.commons.dbcp.PoolableConnection , tidak dapat dikonversi.
Tidak mungkin, tampaknya artikel yang beredar online tidak dapat diandalkan, jadi tidak ada jalan pintas, jadi Anda harus memeriksa kode sumbernya sendiri.
Dengan melihat kode sumber, kami menemukan bahwa Poolableconnection mewarisi kelas DelegatingConnection, dan kelas DelegatingConnection mengimplementasikan antarmuka koneksi. Mari kita ubah menjadi koneksi delegasi untuk mencoba:
DelegatingConnection Connection = (DelegatingConnection) ps.getConnection (); xmlType xmltype = xmltype.createexml (connection.getDelegate (), parameter); ps.setObject (i, xmltype);
Akibatnya, pengecualian dilemparkan: tidak dapat membangun deskriptor: argumen tidak valid; Pengecualian bersarang adalah java.sql.sqlexception: Tidak dapat membangun deskriptor: argumen yang tidak valid, melalui debugging breakpoint, saya menemukan bahwa objek koneksi sebenarnya nol. Bagaimana mungkin nol? Orang -orang di internet menggunakannya dengan baik, tetapi itu tidak akan berhasil dengan saya. Ini benar -benar menyakitkan. Ini tidak dapat diselesaikan. Apakah Anda benar -benar harus memuat kelas pengemudi saja seperti yang dikatakan orang di atas? Tidak mungkin, mari kita pelajari lagi.
Akhirnya, saya menemukan bahwa koneksi proxy asli dapat diperoleh melalui metode GetMetadata. Sangat cerah dan tesnya sangat jelas. Akhirnya normal dan tidak mudah. Kode terakhir adalah sebagai berikut:
@Overridepublic void setParameter (disiapkan PS, int i, parameter string, jdbctype jdbctype) melempar sqlexception {delegatingConnection connection = (delegatingConnection) ps.getConnection (). GetMetadata () .getConnection (); XmlType xmlType = xmltype.createexml (connection.getDelegate (), parameter); ps.setObject (i, xmltype);}Pada titik ini, menggunakan mybatis untuk mengoperasikan tipe XMLType akhirnya telah dilakukan, dan prosesnya penuh dengan tikungan dan belokan. Tentu saja, harus ada pertanyaan ketika data dimasukkan. Selanjutnya, kita perlu mengimplementasikan operasi kueri tipe XMLType.