سؤال

والنظر في التعليمة البرمجية:

PreparedStatement ps = null;
ResultSet rs = null;
try {
  ps = conn.createStatement(myQueryString);
  rs = ps.executeQuery();
  // process the results...
} catch (java.sql.SQLException e) {
  log.error("an error!", e);
  throw new MyAppException("I'm sorry. Your query did not work.");
} finally {
  ps.close();
  rs.close();
}

ما سبق لا تجمع، لأن كلا PreparedStatement.close() وResultSet.close() رمي java.sql.SQLException. لذلك أود أن أضيف كتلة حاول / catch لشرط أخيرا؟ أو نقل البيانات وثيقة في بند المحاولة؟ أو فقط لا تهتم استدعاء قريب؟

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

المحلول

لملف I / O، I عموما إضافة حاول / catch لمنع أخيرا. ومع ذلك، يجب أن تكون حريصا على عدم رمي أي استثناءات من كتلة وأخيرا، لأنها سوف تتسبب في استثناء الأصلي (إن وجدت) أن تضيع.

هذه المقالة لمثال أكثر تحديدا من إغلاق اتصال قاعدة البيانات.

نصائح أخرى

في جافا 7، يجب أن لا إغلاقها بشكل واضح، ولكن استخدام التلقائي إدارة الموارد للتأكد من أن الموارد href="http://docs.oracle.com/javase/7/docs/api/java/lang/AutoCloseable.html" rel="noreferrer"> مغلقة ويتم التعامل مع الاستثناءات بشكل مناسب. معالجة الاستثناء يعمل مثل هذا:

Exception in try | Exception in close | Result
-----------------+--------------------+----------------------------------------
      No         |        No          | Continue normally
      No         |        Yes         | Throw the close() exception
      Yes        |        No          | Throw the exception from try block
      Yes        |        Yes         | Add close() exception to main exception
                 |                    |  as "suppressed", throw main exception

ونأمل أن من المنطقي. في كود يسمح جميلة، مثل هذا:

private void doEverythingInOneSillyMethod(String key)
  throws MyAppException
{
  try (Connection db = ds.getConnection()) {
    db.setReadOnly(true);
    ...
    try (PreparedStatement ps = db.prepareStatement(...)) {
      ps.setString(1, key);
      ...
      try (ResultSet rs = ps.executeQuery()) {
        ...
      }
    }
  } catch (SQLException ex) {
    throw new MyAppException("Query failed.", ex);
  }
}

وقبل جافا 7، فمن الأفضل لاستخدام متداخلة كتل أخيرا، بدلا من اختبار الإشارات لاغية.

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

Connection db = ds.getConnection();
try {
  PreparedStatement ps = ...;
  try {
    ResultSet rs = ...
    try {
      ...
    }
    finally {
      rs.close();
    }
  } 
  finally {
    ps.close();
  }
} 
finally {
  db.close();
}

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

ويمكنك القيام بشيء بسيط مثل هذا، الذي يخفي ما لا يقل عن الفوضى، ويضمن أن لا ننسى شيئا.

public static void close(ResultSet rs, Statement ps, Connection conn)
{
    if (rs!=null)
    {
        try
        {
            rs.close();

        }
        catch(SQLException e)
        {
            logger.error("The result set cannot be closed.", e);
        }
    }
    if (ps != null)
    {
        try
        {
            ps.close();
        } catch (SQLException e)
        {
            logger.error("The statement cannot be closed.", e);
        }
    }
    if (conn != null)
    {
        try
        {
            conn.close();
        } catch (SQLException e)
        {
            logger.error("The data source connection cannot be closed.", e);
        }
    }

}

ثم

finally {
    close(rs, ps, null); 
}

لا تضيعوا وقتكم الترميز إدارة استثناء على مستوى منخفض، استخدام API ذات المستوى العالي مثل الربيع JDBC، أو مجمع مخصص حول الاتصال / بيان / كائنات التمرير، لإخفاء الفوضى محاولة اللحاق كود تعصف بها.

لاحظ أيضا:

و"عند إغلاق كائن البيان، الكائن resultset والحالي، في حال وجودها، يتم إغلاق أيضا."

HTTP: // java.sun.com/j2se/1.5.0/docs/api/java/sql/Statement.html#close ()

وينبغي أن يكون كافيا لإغلاق فقط PreparedStatement في نهاية المطاف، وفقط إذا لم يتم إغلاقه بالفعل. إذا كنت تريد أن تكون خاصة جدا على الرغم من إغلاق resultset والأول، وليس بعد إغلاق PreparedStatement (إغلاقه بعد، مثل بعض الأمثلة هنا، يجب أن يضمن في الواقع استثناء، لأنها بالفعل مغلقة).

وأنا عادة ما يكون وسيلة الأداة التي يمكن إغلاق مثل هذه الامور، بما في ذلك الرعاية جني لا تحاول أن تفعل أي شيء مع مرجع فارغة.

وعادة إذا close() يطرح استثناء لا يهمني في الواقع، لذلك أنا فقط تسجيل استثناء وابتلاعها - ولكن ثمة بديل آخر يتمثل في تحويله إلى RuntimeException. وفي كلتا الحالتين، وأنا أوصي به في طريقة الأداة التي من السهل أن ندعو، كما قد تحتاج أيضا إلى القيام بذلك في كثير من الأماكن.

لاحظ أن الحل الحالي الخاص بك وسوف يتم إغلاق resultset وإذا فشل إغلاق PreparedStatement - أنه من الأفضل استخدام متداخلة كتل أخيرا

وإذا كان لديك تستخدم جافا 7 يمكنك استخدام التحسينات في آليات معالجة الاستثناء في تلك الفئات التي تقوم بتنفيذ <لأ href = "http://docs.oracle.com/javase/7/docs/api/java/lang /AutoCloseable.html "يختلط =" نوفولو noreferrer "> AutoCloseable (أي PreparedStatement، Resultset)

وقد تجد أيضا هذه مسألة مثيرة للاهتمام: إغلاق resultset وفي جافا 7

وأعرف أن هذا هو السؤال القديم، ولكن فقط في حالة شخص ما يبحث عن الجواب، جافا لديها الآن الحل المحاولة، مع من resouce.

static String readFirstLineFromFile(String path) throws IOException {
      try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

هل لا احذف الدعوة وثيق. فإنه قد يسبب مشاكل.

وانا افضل بإضافة كتلة حاول / catch إلى النهاية.

وربما على الطريقة القديمة (على بساطتها) أن تفعل أشياء، لكنه لا يزال يعمل:

public class DatabaseTest {

    private Connection conn;    
    private Statement st;   
    private ResultSet rs;
    private PreparedStatement ps;

    public DatabaseTest() {
        // if needed
    }

    public String getSomethingFromDatabase(...) {
        String something = null;

        // code here

        try {
            // code here

        } catch(SQLException se) {
            se.printStackTrace();

        } finally { // will always execute even after a return statement
            closeDatabaseResources();
        }

        return something;
    }

    private void closeDatabaseResources() {
        try {
            if(conn != null) {
                System.out.println("conn closed");
                conn.close();
            }

            if(st != null) {
                System.out.println("st closed");
                st.close();
            }

            if(rs != null) {
                System.out.println("rs closed");
                rs.close();
            }

            if(ps != null) {
                System.out.println("ps closed");
                ps.close();
            }

        } catch(SQLException se) {
            se.printStackTrace();
        }               
    }
}

وبناء على الجواب @ إريكسون، لماذا ليس فقط تفعل ذلك في كتلة try واحد مثل هذا؟

private void doEverythingInOneSillyMethod(String key) throws MyAppException
{
  try (Connection db = ds.getConnection();
       PreparedStatement ps = db.prepareStatement(...)) {

    db.setReadOnly(true);
    ps.setString(1, key);
    ResultSet rs = ps.executeQuery()
    ...
  } catch (SQLException ex) {
    throw new MyAppException("Query failed.", ex);
  }
}

لاحظ أنك لا تحتاج إلى إنشاء كائن ResultSet داخل كتلة try كما يتم إغلاق في ResultSet تلقائيا عندما يتم إغلاق الكائن PreparedStatement.

<اقتباس فقرة>   

وإغلاق كائن resultset وتلقائيا عند الكائن بيان   التي ولدت يتم إغلاقه، وإعادة تنفيذها، أو استخدامه لاسترداد المقبل   ينتج عن سلسلة من عدة نتائج.

والمرجعي: https://docs.oracle كوم / javase / 7 / مستندات / المعهد / جافا / SQL / ResultSet.html

والتركيز بند أخيرا،

finally {
   try {
      rs.close();
      ps.close();
   } catch (Exception e) {
      // Do something
   }
}

وأعتقد أن لديك لتعديل 2 نقطة.

أولا، استخدام محاولة واللحاق به مرة أخرى في الفقرة fainlly.

وثانيا، هل rs.close () قبل القيام ps.close ().

وfly1997@naver.com

وأنا استخدم هذا ..

finally
{
    if (ps != null) ps.close();
    if (rs != null) rs.close();
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top