سؤال

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

Connection conn = dataSource.getConnection();

try{
    PreparedStatement stmt = conn.prepareStatement();
    //initialize the statement
    stmt.execute();
    ResultSet rs =  stmt.getResultSet();
    //get data
}finally{
    conn.close();
}

كان الخطأ هو أن هذا الرمز قد لا يحرر الموارد.لقد اكتشفت أن ResultSet والبيان لم يتم إغلاقهما، لذلك أغلقتهما أخيرًا:

finally{
    try{
        rs.close()
    }catch(SqlException se){
        //log it
    }
    try{
        stmt.close();
    }catch(SqlException se){
        //log it
    }
    conn.close();
}

لكنني واجهت النمط المذكور أعلاه في العديد من المشاريع (من عدد قليل من الشركات)، ولم يكن أحد يغلق ResultSets أو البيانات.

هل واجهت مشاكل مع عدم إغلاق مجموعات النتائج والبيانات عند إغلاق الاتصال؟

وجدت فقط هذا ويشير إلى أن Oracle تواجه مشكلات في إغلاق ResultSets عند إغلاق الاتصالات (نستخدم Oracle db، ومن ثم تصحيحاتي).لا يقول java.sql.api شيئًا في Connection.Close() javadoc.

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

المحلول

إحدى مشكلات إغلاق الاتصال فقط وليس مجموعة النتائج، هي أنه إذا كان رمز إدارة الاتصال الخاص بك يستخدم تجمع الاتصالات، فإن connection.close() سيعيد الاتصال مرة أخرى إلى حوض السباحة.بالإضافة إلى ذلك، تحتوي بعض قواعد البيانات على مورد مؤشر على الخادم والذي لن يتم تحريره بشكل صحيح ما لم يتم إغلاقه بشكل صريح.

نصائح أخرى

لقد واجهت مشكلات مع مجموعات النتائج غير المغلقة في Oracle، على الرغم من إغلاق الاتصال.الخطأ الذي حصلت عليه كان

"ORA-01000: maximum open cursors exceeded"

لذا:قم دائمًا بإغلاق مجموعة النتائج الخاصة بك!

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

فيما يلي طريقة مساعدة يمكن استخدامها من الكتلة النهائية:

public static void closeEverything(ResultSet rs, Statement stmt,
        Connection con) {
    if (rs != null) {
        try {
            rs.close();
        } catch (SQLException e) {
        }
    }
    if (stmt != null) {
        try {
            stmt.close();
        } catch (SQLException e) {
        }
    }
    if (con != null) {
        try {
            con.close();
        } catch (SQLException e) {
        }
    }
}

ستعطيك Oracle أخطاء حول المؤشرات المفتوحة في هذه الحالة.

وفق: http://java.sun.com/javase/6/docs/api/Java/sql/Statement.html

يبدو أن إعادة استخدام عبارة ستؤدي إلى إغلاق أي مجموعات نتائج مفتوحة، وسيؤدي إغلاق العبارة إلى إغلاق أي مجموعات نتائج، لكنني لا أرى أي شيء يتعلق بإغلاق الاتصال سيؤدي إلى إغلاق أي من الموارد التي أنشأها.

يتم ترك كل هذه التفاصيل لموفر برنامج تشغيل JDBC.

من الأكثر أمانًا دائمًا إغلاق كل شيء بشكل صريح.لقد كتبنا فئة util التي تغلف كل شيء باستخدام محاولة { xxx } Catch (Throwable {} بحيث يمكنك فقط الاتصال بـ Utils. Close (rs) وUtils. Close (stmt)، وما إلى ذلك دون الحاجة إلى القلق بشأن الاستثناءات التي من المفترض أن تؤدي إلى إغلاق الفحص .

يمكن أن يؤدي جسر ODBC إلى حدوث تسرب للذاكرة مع بعض برامج تشغيل ODBC.

إذا كنت تستخدم برنامج تشغيل JDBC جيدًا، فمن المفترض ألا تواجه أي مشاكل في إغلاق الاتصال.ولكن هناك مشكلتين:

  • هل تعرف إذا كان لديك سائق جيد؟
  • هل ستستخدم برامج تشغيل JDBC أخرى في المستقبل؟

أن أفضل الممارسات هي إغلاق كل شيء.

أنا أعمل في بيئة ويب J2EE كبيرة.لدينا العديد من قواعد البيانات التي يمكن الاتصال بها في طلب واحد.بدأنا نواجه مآزق منطقية في بعض تطبيقاتنا.وكانت المسألة كالتالي:

  1. سيطلب المستخدم الصفحة
  2. يتصل الخادم بقاعدة البيانات 1
  3. يختار الخادم على قاعدة البيانات 1
  4. الخادم "يغلق" الاتصال بقاعدة البيانات 1
  5. يتصل الخادم بقاعدة البيانات 2
  6. في طريق مسدود!

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

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

مثال:

<resource-ref>
    <description>My Database</description>
    <res-ref-name>jdbc/jndi/pathtodatasource</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <res-sharing-scope>Unshareable</res-sharing-scope>
</resource-ref>

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

في Java، ترتبط البيانات (وليس مجموعات النتائج) بالمؤشرات في Oracle.من الأفضل إغلاق الموارد التي تفتحها حيث يمكن أن يحدث سلوك غير متوقع فيما يتعلق بـ JVM وموارد النظام.

بالإضافة إلى ذلك، تقوم بعض أطر عمل تجميع JDBC بتجميع البيانات والاتصالات، لذا فإن عدم إغلاقها قد لا يضع علامة على هذه الكائنات على أنها مجانية في التجمع، ويسبب مشكلات في الأداء في إطار العمل.

بشكل عام، إذا كان هناك أسلوب إغلاق () أو تدمير () على كائن ما، فهناك سبب لاستدعائه، وتجاهله يتم على مسؤوليتك الخاصة.

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