دعونا أولاً نفهم نوع XMLType.
XMLType هو نوع بيانات فريد لـ Oracle منذ 9i. إنه وجود قوي يرث النقطة. يمكن استخدامه لتخزين XML ويوفر الكثير من وظائف التشغيل. من الناحية النظرية ، يمكن أن يحفظ بيانات 2G.
فكيف يمكنك إدراج بيانات XMLType عبر Java؟ يستخدم المشروع mybatis ، وهناك دائمًا استثناءات لا يمكن تفسيرها. لا يمكنني معرفة ما إذا كانت مشكلة MyBatis أو JDBC نفسها ، لذلك أخطط للقيام بذلك خطوة بخطوة ، أو أولاً حل JDBC ، ثم حل MyBatis.
JDBC
بعد فترة طويلة من النضال ، وجدت أن هناك ثلاث طرق رئيسية لتشغيل JDBC:
1. استخدم XMLType كسلسلة سلسلة في Java ، ويتم تسليم المهمة المحددة لإنشاء XMLType بالكامل إلى قاعدة البيانات:
String sql = "insert في قيم xmltable (xml) (sys.xmltype.createxml (؟))" ؛ String xmldata = "<label> هذا هو جزء XML </label>" ؛ ps.SetString (1 ، xmldata) ؛ ps.ExecuteUpdate () ؛
ستجعل هذه الطريقة ضغوط قاعدة البيانات أكثر من اللازم ، لأن هذه الطريقة بسيطة ولا تتطلب تبعيات إضافية. تم استخدام هذه الطريقة في البداية ، ولكن أثناء الاستخدام الفعلي ، وجد أنه عندما يتجاوز طول المحتوى حوالي 4000 ، سيتم رميه: ORA-01461: يمكن أن يربط قيمة طويلة فقط للإدراج في استثناء عمود طويل. في البداية اعتقدت أن سبب استخدام MyBatis كان لا يزال هو نفسه عند استخدام اختبار JDBC ، ولم يكن هناك حل عند استخدام العديد من الطرق. من المستحيل حفظ البيانات بطول أقل من 4000 عند استخدام هذا الحقل الكبير في المشروع. بهذه الطريقة ، فإن استخدام varchar2 يكفي ، لذلك يتم القضاء على هذه الطريقة.
2. استخدم نوع CLOB للعمل. يرث XMLType وجود CLOB ، بحيث يمكن تشغيله من خلال CLOB. تتمثل الطريقة في إنشاء بيانات CLOB على العميل ونقلها إلى قاعدة البيانات لإنشاء قيمة XMLTYPE من خلال وظيفة XMLTYPE () من Oracle:
String sql = "insert في قيم xmltable (xml) (xmltype (؟))" ؛ String xmldata = "<label> هذا هو جزء XML </label>" ؛ // إنشاء clobclob tempclob = clob.createTporary (connection ، false ، clob.duration_session) ؛ // open clobtempclob.open (clob.mode_readwrite) ؛ // Get Corrwriter clobwriter = tempclob.setcharacterstream (100) ؛ // اكتب data clobwriter.write (xmldata) ؛ // fresh clobwriter.flush () ؛ // close constrclobwriter.close () ؛ // close clobtempclob.close () ؛ PST.SetObject (1 ، tempclob) ؛
يعد عميل الطريقة وقاعدة البيانات هذه مسؤولة عن إنشاء XMLType في نفس الوقت ، وبالتالي فإن الضغط متوسط نسبيًا ولا توجد مشكلة في تجاوز الطول. ومع ذلك ، أثناء الاستخدام الفعلي ، وجد أن رأس المحتوى الخاص بـ XML لا يمكن أن يحتوي على المعلومات التالية:
<؟
خلاف ذلك ، سيتم طرح استثناء:
يتم حجز أسماء PI بدءًا من XML
دعونا لا نتحدث عما إذا كنت ستواجه أي مشاكل في التعليمات البرمجية المشوهة عند معالجة محتوى إدراج XML باللغة الصينية في المستقبل. مجرد النظر إلى ذلك يجعل الناس يشعرون بعدم الارتياح ، وتتطلب المتطلبات أيضًا الادخار. لا توجد طريقة ، وهذه الطريقة لن تعمل.
3. استخدم فئة Oracle.xdb.xmltype المقدمة من Oracle. بعد إنشاء العميل XMLType ، يتم تمرير الكائن مباشرة إلى قاعدة البيانات:
connection conn = ... ؛ // احصل على connection repartatement ps = ... ؛ // get repartsatement string sql = "insert في قيم xmltable (xml) (؟)" ؛ String xmldata = "<label> هذا هو جزء XML </label>" ؛ // إنشاء كائن xmltype xmltype xmltype = xmltype.createxml (conn ، xmldata) ؛ ps.SetObject (1 ، xmltype) ؛ ps.ExecuteUpdate () ؛
تقوم هذه الطريقة بتسليم مهمة إنشاء XMLType للعميل تمامًا ، وبالتالي فإن العميل تحت ضغط كبير وقاعدة البيانات تحت الضغط المنخفض. أثناء الاختبار الفعلي ، يجب إضافة حزمة جرة ، وإلا لا يمكن العثور على فئة خطأ:
xdb.jarxmlparserv2.jar
من الضروري أن نلاحظ أن حزمة الجرة هذه لا تحتوي على شرح توضيحي للنسخة ، لذلك من السهل ارتكاب أخطاء. في البداية ، قمت بتنزيل XDB.jar ، ولكن بغض النظر عن كيفية القيام بذلك ، فقد دفعت إلى أنه لا يمكنني العثور على فصل معين. بعد التحقق ، وجدت أنه ينتمي إلى إصدار سابق من Oracle. بعد تنزيل XDB.JAR مرة أخرى ، من الطبيعي.
وتمت مقارنة الطرق الثلاثة المذكورة أعلاه عن طريق إدخال 200000 قطعة من البيانات:
الطريقة الأولى: أقصر وقت واستهلاك وحدة المعالجة المركزية الخادم هو الأكبر ؛
الطريقة الثانية: يتم استخدام أطول وقت ، ويتمحور استهلاك وحدة المعالجة المركزية الخادم ؛
الطريقة الثالثة: مستهلكة للوقت وتركز على استهلاك وحدة المعالجة المركزية الخادم الحد الأدنى.
في هذه المرحلة ، قامت JDBC أخيرًا ببعض الأشياء الصغيرة في تشغيل بيانات نوع XMLType. وغني عن القول ، يتم اعتماد الحل الثالث ، لكن المشروع لا يستخدم بشكل مباشر JDBC للعمل. على سبيل المثال ، في المشروع الحالي ، يتم استخدام MyBatis. ذكر ما ورد أعلاه أيضًا أن هناك دائمًا استثناءات عند استخدام MyBatis. بعد التحقق من MyBatis ، لا يوجد تطبيق XMLType. يبدو أنه لا يزال هناك بعض المشاكل ، ولكن تم تنفيذ JDBC ، وبالتالي فإن الفكرة واضحة ، أليس كذلك؟
mybatis
باستخدام MyBatis لتشغيل XMLType ، نقوم أيضًا بتخطيط لسلسلة النوع على جانب Java. عندما لا تقوم العملية المباشرة بأي معالجة ، مثل JDBC ، يكون كل شيء طبيعيًا عندما يكون المحتوى المنقول أقل من 4000
ORA-01461: يمكن أن يربط قيمة طويلة فقط للإدراج في عمود طويل
يمكن ملاحظة أن عملية MyBatis هي في الواقع مثل JDBC ، باستثناء أنها تغلف طبقة خارج JDBC ، حتى نتمكن من استخدام ملفات التكوين وطرق التعيين الأخرى للوصول إلى قاعدة البيانات بشكل أكثر ملاءمة. ما يتعين علينا القيام به هو إدراج بيانات نوع XMLType بناءً على راحة MyBatis الأصلية. في هذه الحالة ، يعد تطبيق معالج TypeHandler المخصص لنوع XMLType هو الخيار الأفضل.
هنا ، ما زلنا نستخدم الحل ثلاثة أعلاه. وبطبيعة الحال ، يجب إضافة حزم اثنين من الجرة: xdb.jar و xmlparserv2.jar أيضًا.
إضافة XMLTYPETYPEHandler لتنفيذ واجهة TypeHandler. نظرًا لأن إدخال البيانات يستخدم بشكل أساسي طريقة SetParameter ، يتم سرد هذه الطريقة فقط هنا. تم حذف رمز الطريقة الأخرى:
/*** Oracle sys.xmltype Type Type Custom Processor*/public class xmltypepepeyhandler تنفذ typehandler <string> {Override public void setParameter (preparedStatement PS ، int I ، String Parameter ، jdbctype jdbctype)يتم استخدام طريقة setParameter هذه بواسطة MyBatis لتعيين المعلمات عند إدخال البيانات في قاعدة البيانات. بالنسبة لمعلمات هذه الطريقة ، أعتقد أنك فهمت الكود بالفعل. سنقوم بإدراج الرمز التالي هنا وفقًا لطريقة تنفيذ JDBC السابقة:
public void setParameter (preparedStatement PS ، int I ، string parameter ، jdbctype jdbctype) يلقي sqlexception {xmltype xmltype = xmltype.createxml (ps.getConnection () ، المعلمة) ؛ ps.setObject (i ، xmltype) ؛}وتسجيل المحول في mapper-config.xml ، لأنه في التعداد المحدد بواسطة mybatis org.apache.ibatis.type.jdbctype ، لا يوجد نوع من XmlType الذي نحتاجه ، هنا نحدده على النحو غير محدد:
<IGUNCET> <TypeHandlers> <TypeHandler javatype = "string" jdbctype = "undefined" handler = "com.tyyd.dw.context.xmltypepehandler"/> </typeHandlers> </iscification>
في معلمات ملف التكوين ، استخدم محولنا المحدد حتى يتمكن MyBatis من العثور عليه:
#{xmlfile ، jdbctype = undefined} ،بالطبع ، يمكنك أيضًا أن تكون أكثر توحيدًا وكتابة نوعه والمحول الذي تستخدمه بطريقة كاملة:
#{xmlfile ، javatype = string ، jdbctype = undefined ، typeHandler = com.tyyd.dw.context.xmltypepehandler} ،
أكمل الخطوات المذكورة أعلاه ويتم كل شيء منطقياً ، دعنا نديرها.
يتم طرح النتيجة: java.lang.ClassCastException: org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to oracle.jdbc.OracleConnection
لا يمكن تحويله إلى كائن اتصال Oracle OracleConnection. بعد التحقق ، وجدنا أن مصدر البيانات الخاص بنا يستخدم DBCP من Apache ، والذي يجب أن يكون غير متوافق مع الاثنين. لقد راجعت عبر الإنترنت وقال رجل إنه قدم حلاً مثاليًا ، وهو تحميل فئة سائق Oracle في طريقة SetParameter لإنشاء اتصال ، على النحو التالي:
class.forname ("oracle.jdbc.oracledriver") ؛ اتصال الاتصال = drivermanager.getConnection (url ، اسم المستخدم ، كلمة المرور) ؛يمكن أن يحل هذا بالفعل المشكلة التي لا يمكن تحويل كائن الاتصال بنسبة 100 ٪ ، ولكن من حيث التنفيذ ، هاها ، ما زلت لا أعلق. هناك أيضًا أشخاص يمرون عبر الإنترنت ، قائلين إنه يمكن تحويلهم إلى كائن BoolableConnection ، ثم يستخدمون طريقة getDelegate للحصول على رابط الوكيل الأصلي. هذا يبدو ممكنا ، دعنا نحاول:
اتصال poolableConnection = (poolableConnection) ps.getConnection () ؛ xmltype xmltype = xmltype.createxml (connection.getDelegate () ، المعلمة) ؛ ps.setObject (i ، xmltype) ؛
نتيجة لذلك ، تم طرح استثناء آخر:
org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to org.apache.commons.dbcp.PoolableConnection ،.
لا توجد طريقة ، يبدو أن المقالات التي تدور عبر الإنترنت غير موثوقة ، لذلك لا يوجد اختصار ، لذلك يجب عليك التحقق من الكود المصدر بنفسك.
من خلال النظر إلى الكود المصدري ، وجدنا أن PoolableConnection يرث فئة DeLegatingConnection ، وينفذ فئة DeLegatingConnection واجهة الاتصال. دعونا نحوله إلى مفوضية لمحاولة:
devitingConnection Connection = (devatingConnection) ps.getConnection () ؛ xmltype xmltype = xmltype.createxml (connection.getDelegate () ، parameter) ؛ ps.setObject (i ، xmltype) ؛
نتيجة لذلك ، تم طرح استثناء: غير قادر على بناء الواصفات: وسيطات غير صالحة ؛ الاستثناء المتداخل هو java.sql.sqlexception: غير قادر على إنشاء واصفات: وسيطات غير صالحة ، من خلال تصحيح تصحيح نقطة الإيقاف ، وجدت أن كائن الاتصال لاغية بالفعل. كيف يمكن أن تكون فارغة؟ يستخدمه الأشخاص على الإنترنت بشكل جيد ، لكنه لن يعمل معي. إنه حقًا ألم. هذا ليس غير قابل للحل. هل يجب عليك حقًا تحميل فئة السائق بمفرده كما قال الرجل أعلاه؟ لا توجد طريقة ، دعنا ندرسها مرة أخرى.
أخيرًا ، وجدت أنه يمكن الحصول على اتصال الوكيل الأصلي من خلال طريقة getMetadata. إنه مشرق للغاية والاختبار واضح للغاية. إنه أمر طبيعي أخيرًا وليس سهلاً. الرمز النهائي هو كما يلي:
Overridepublic void setParameter (preparedStatement PS ، int I ، معلمة السلسلة ، JDBCType jdbctype) يلقي sqlexception {devatingConnection Connection = (devatingConnection) ps.getConnection (). getMetadata () .getConnection () ؛ xmltype xmltype = xmltype.createxml (connection.getDelegate () ، المعلمة) ؛ ps.setObject (i ، xmltype) ؛}في هذه المرحلة ، تم استخدام MyBatis لتشغيل أنواع XMLType أخيرًا ، وكانت العملية مليئة بالتحولات والمنعطفات. بالطبع ، يجب أن يكون هناك استفسارات عند إدراج البيانات. بعد ذلك ، نحتاج إلى تنفيذ عمليات الاستعلام عن نوع XMLTYPE.