سؤال

في العمل، يتعين علينا التعامل مع العديد من ملفات MS Access mdb، لذلك نستخدم برنامج تشغيل JdbcOdbcBridge الافتراضي الذي يأتي مع Sun JVM، ويعمل بشكل رائع في معظم الحالات.

المشكلة هي أنه عندما يتعين علينا التعامل مع بعض الملفات الكبيرة، نواجه عدة مرات استثناءات مع الرسالة "لا يمكن فتح أي جداول أخرى".كيف يمكننا تجنب ذلك؟

لقد قمنا بالفعل بإغلاق جميع مثيلات PreparedStatements وRecordSets، وقمنا أيضًا بتعيين متغيراتها على قيمة فارغة، ولكن على الرغم من ذلك يستمر هذا الاستثناء في الحدوث.ماذا علينا ان نفعل؟كيف يمكننا تجنب هذه الاستثناءات السيئة؟هل يعرف أحد هنا كيف؟

هل هناك أي تكوين إضافي لبرامج تشغيل ODBC على نظام التشغيل Windows يمكننا تغييره لتجنب هذه المشكلة؟

هل كانت مفيدة؟

المحلول

"لا يمكن فتح أي جداول أخرى" هي رسالة خطأ أفضل من رسالة الخطأ "لا يمكن فتح أي قواعد بيانات أخرى"، والتي يتم مواجهتها بشكل أكثر شيوعًا في تجربتي.في الواقع، هذه الرسالة الأخيرة تخفي دائمًا الرسالة الأولى.

لدى مشغل قاعدة بيانات Jet 4 حد 2048 جدول مقابض.ليس من الواضح تمامًا بالنسبة لي ما إذا كان هذا متزامنًا أم تراكميًا خلال حياة الاتصال.لقد افترضت دائمًا أنها تراكمية، نظرًا لأن فتح عدد أقل من مجموعات السجلات في وقت واحد من الناحية العملية يبدو أنه يجعل من الممكن تجنب المشكلة.

المشكلة هي أن "مقابض الجدول" لا تشير فقط إلى مقابض الجدول، بل إلى شيء أكثر من ذلك بكثير.

خذ بعين الاعتبار QueryDef المحفوظ باستخدام SQL هذا:

  SELECT tblInventory.* From tblInventory;

تشغيل QueryDef يستخدم مؤشري جدول.

ماذا؟، قد تسأل؟يستخدم طاولة واحدة فقط!ولكن يستخدم Jet مؤشر جدول للجدول ومقبض جدول لـ QueryDef المحفوظة.

وبالتالي، إذا كان لديك QueryDef مثل هذا:

  SELECT qryInventory.InventoryID, qryAuthor.AuthorName
  FROM qryInventory JOIN qryAuthor ON qryInventory.AuthorID = qryAuthor.AuthorID

...إذا كان كل استعلام من استعلاماتك المصدر يحتوي على جدولين، فأنت تستخدم مقابض الجدول هذه، واحد لكل منهما:

  Table 1 in qryInventory
  Table 2 in qryInventory
  qryInventory
  Table 1 in qryAuthor
  Table 2 in qryAuthor
  qryAuthor
  the top-level QueryDef

لذلك، قد تعتقد أن لديك أربعة جداول فقط (نظرًا لوجود أربعة جداول أساسية فقط)، ولكنك ستستخدم في الواقع 7 جداول مقابض من أجل استخدام تلك الجداول الأساسية الأربعة.

إذا كنت تستخدم في مجموعة سجلات، QueryDef المحفوظ الذي يستخدم 7 مقابض جدول، فقد استخدمت مقبض جدول آخر، ليصبح المجموع 8.

مرة أخرى في أيام Jet 3.5، كان الحد الأصلي لمقابض الجدول هو 1024، وقد اصطدمت به في الموعد النهائي عندما قمت بنسخ ملف البيانات بعد تصميم تطبيق يعمل.كانت المشكلة هي أن بعض جداول النسخ المتماثل تكون مفتوحة في جميع الأوقات (ربما لكل مجموعة سجلات؟)، وأن ذلك يستهلك عددًا كافيًا من مقابض الجدول لوضع التطبيق في الأعلى.

في التصميم الأصلي لهذا التطبيق، كنت أفتح مجموعة من النماذج ذات الوزن الثقيل مع الكثير من النماذج الفرعية ومربعات التحرير والسرد ومربعات القوائم، وفي ذلك الوقت استخدمت الكثير من QueryDefs المحفوظة لتجميع مجموعات السجلات القياسية مسبقًا التي سأستخدمها في العديد من الأماكن ( تمامًا كما تفعل مع طرق العرض على أي قاعدة بيانات خادم).ما حل المشكلة كان:

  1. تحميل النماذج الفرعية فقط عندما يتم عرضها.

  2. تحميل مصادر الصفوف لمربعات التحرير والسرد ومربعات القائمة فقط عندما تكون على الشاشة.

  3. التخلص من جميع QueryDefs المحفوظة واستخدام عبارات SQL التي انضمت إلى الجداول الأولية حيثما أمكن ذلك.

وقد أتاح لي ذلك نشر هذا التطبيق في مكتب لندن بعد أسبوع واحد فقط من الموعد المقرر.عندما ظهر Jet SP2، تضاعف عدد مقابض الطاولة، وهو ما لا يزال لدينا في Jet 4 (و، على ما أعتقد، ACE).

فيما يتعلق باستخدام Jet من Java عبر ODBC، أعتقد أن النقطة الأساسية ستكون:

  1. استخدم اتصالاً واحدًا في جميع أنحاء تطبيقك، بدلاً من فتحه وإغلاقه حسب الحاجة (مما يعرضك لخطر الفشل في إغلاقه).

  2. افتح مجموعات السجلات فقط عندما تحتاج إليها، وقم بتنظيف مواردها وتحريرها عند الانتهاء.

الآن، من الممكن أن يكون هناك تسرب للذاكرة في مكان ما في JDBC=>ODBC=>Jet chain حيث يمكنك يفكر أنت تقوم بتحرير الموارد ولا يتم إطلاقها على الإطلاق.ليس لدي أي نصيحة خاصة بـ JDBC (لأنني لا أستخدمه - أنا مبرمج Access، بعد كل شيء)، ولكن في VBA علينا أن نكون حذرين بشأن إغلاق كائناتنا بشكل صريح وإطلاق هياكل الذاكرة الخاصة بها لأن يستخدم VBA حساب المراجع، وفي بعض الأحيان لا يعرف أنه قد تم تحرير مرجع إلى كائن، لذلك لا يقوم بتحرير الذاكرة لهذا الكائن عندما يخرج عن النطاق.

لذا، في كود VBA، في أي وقت تقوم فيه بذلك:

  Dim db As DAO.Database
  Dim rs As DAO.Recordset

  Set db = DBEngine(0).OpenDatabase("[database path/name]")
  Set rs = db.OpenRecordset("[SQL String]")

...بعد الانتهاء من ما عليك القيام به، عليك الانتهاء مما يلي:

  rs.Close         ' closes the recordset
  Set rs = Nothing ' clears the pointer to the memory formerly used by it
  db.Close
  Set db = Nothing

...وهذا حتى لو خرجت متغيراتك المعلنة عن النطاق مباشرة بعد هذا الرمز (والذي يجب أن يحرر كل الذاكرة المستخدمة من قبلها، لكنه لا يفعل ذلك بشكل موثوق بنسبة 100٪).

الآن، أنا لا أقول أن هذا هو ما تفعله في Java، لكنني أقترح ببساطة أنه إذا كنت تواجه مشكلات وتعتقد أنك تقوم بتحرير جميع مواردك، فربما تحتاج إلى تحديد ما إذا كنت تعتمد على جمع البيانات المهملة للقيام بذلك وبدلاً من ذلك تحتاج إلى القيام بذلك بشكل صريح.

سامحني إذا قلت أي شيء غبي فيما يتعلق بـ Java وJDBC - أنا فقط أبلغ عن بعض المشكلات التي واجهها مطورو Access في التفاعل مع Jet (عبر DAO، وليس ODBC) والتي أبلغت عن نفس رسالة الخطأ التي الذي تحصل عليه، على أمل أن تقترح خبرتنا وممارستنا حلاً لبيئة البرمجة الخاصة بك.

نصائح أخرى

ومؤخرا حاولت UCanAccess - محض سائق جافا JDBC من أجل الوصول MS. راجع: http://sourceforge.net/projects/ucanaccess/ - يعمل على لينكس جدا؛ - ) لتحميل المكتبات المطلوبة، هناك حاجة إلى بعض الوقت. أنا لم نجرب ذلك لأكثر من أغراض للقراءة فقط حتى الان.

وعلى أي حال، لقد واجهت مشاكل كما هو موضح أعلاه مع sun.jdbc.odbc.JdbcOdbcDriver. بعد إضافة وثيقة () العبارات التالية إنشاء كائنات بيان (ويدعو إلى executeUpdate على تلك)، وكذلك System.gc () البيانات، توقفت رسائل الخطأ؛ -)

وهناك فرصة ضئيلة أنك ببساطة نفاد اتصالات الشبكة الحرة. كان لدينا هذه المشكلة على نظام مشغول في العمل.

وشيء هو أن نلاحظ أن شبكة اتصالات، على الرغم مغلقة، قد لا حرر مأخذ حتى وقت جمع القمامة. هل يمكن أن تحقق هذا مع NETSTAT /A /N /P TCP. إذا كان لديك الكثير من الاتصالات في حالة TIME_WAIT، قد تتمكن من محاولة فرض المهملة على اتصال يغلق أو ربما فترات منتظمة.

ويجب أيضا إغلاق كائن اتصال بك.

وسوف تبحث في كبديل للسائق دبك جدبك أيضا أن يكون فكرة جيدة. لم يكن لديك أي خبرة مع بديل نفسي ولكن هذا سيكون مكانا جيدا للبدء:

هل هناك بديل لاستخدام sun.jdbc .odbc.JdbcOdbcDriver؟

وكان لي نفس المشكلة ولكن لا شيء ما سبق كان يعمل. I locataed eventualy هذه المسألة. كنت تستخدم هذا لقراءة قيمة نموذج لإعادتها إلى مصدر سجل قائمة البحث.

LocationCode = [Forms]![Support].[LocationCode].Column(2)
ContactCode = Forms("Support")("TakenFrom")

وتغييره إلى أدناه، وأنه يعمل.

LocationCode = Forms("Support")("LocationCode")
ContactCode = Forms("Support")("TakenFrom")

وأنا أعلم أنني يجب أن يكون مكتوب بشكل أفضل ولكن آمل أن يساعد هذا شخص آخر في نفس الوضع.

والشكر جريج

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top