इस प्रश्न को पोस्ट किए हुए काफी समय हो गया है, और मैं एक उत्तर पोस्ट करना चाहता हूं जो सटीक परिदृश्य का वर्णन करता है जिसके कारण यह मुश्किल NullPointerException
हुआ। ।
मुझे लगता है कि यह भविष्य के पाठकों की मदद कर सकता है जो इस तरह के भ्रमित अपवाद का सामना करते हैं, बॉक्स के बाहर सोचते हैं, क्योंकि मेरे पास संदेह करने का लगभग हर कारण था कि यह एक MySQL कनेक्टर बग था, भले ही यह बिल्कुल नहीं था।
इस अपवाद की जांच करते समय मुझे यकीन था कि मेरा एप्लिकेशन संभवतः डीबी कनेक्शन को बंद नहीं कर सकता है, जबकि इससे डेटा पढ़ने की कोशिश कर रहा है, क्योंकि मेरे डीबी कनेक्शन थ्रेड में साझा नहीं किए जाते हैं, और यदि एक ही थ्रेड ने कनेक्शन बंद कर दिया और फिर एक्सेस करने का प्रयास किया यह, एक अलग अपवाद फेंका जाना चाहिए था (कुछ SQLException
) यही मुख्य कारण था कि मुझे mysql कनेक्टर बग पर संदेह हुआ।
यह पता चला कि एक ही कनेक्शन को एक्सेस करने वाले दो थ्रेड थे आख़िरकार। इसका पता लगाना कठिन था क्योंकि इनमें से एक धागा कचरा संग्रहकर्ता धागा था ।
मेरे द्वारा पोस्ट किए गए कोड पर वापस जा रहे हैं:
Connection conn = ... // the connection is open
...
for (String someID : someIDs) {
SomeClass sc = null;
PreparedStatement
stmt = conn.prepareStatement ("SELECT A, B, C, D, E, F, G, H FROM T WHERE A = ?");
stmt.setString (1, "someID");
ResultSet res = stmt.executeQuery ();
if (res.next ()) {
sc = new SomeClass ();
sc.setA (res.getString (1));
sc.setB (res.getString (2));
sc.setC (res.getString (3));
sc.setD (res.getString (4));
sc.setE (res.getString (5));
sc.setF (res.getInt (6));
sc.setG (res.getString (7));
sc.setH (res.getByte (8)); // the exception is thrown here
}
stmt.close ();
conn.commit ();
if (sc != null) {
// do some processing that involves loading other records from the
// DB using the same connection
}
}
conn.close();
समस्या "कुछ प्रसंस्करण करें जिसमें एक ही कनेक्शन का उपयोग कर डीबी से अन्य रिकॉर्ड लोड करना शामिल है" खंड में निहित है, दुर्भाग्य से, मैंने अपने मूल प्रश्न में शामिल नहीं किया, क्योंकि मुझे नहीं लगता था कि समस्या वहां थी।
उस अनुभाग में ज़ूम करते हुए, हमारे पास है:
if (sc != null) {
...
someMethod (conn);
...
}
और someMethod
ऐसा दिखता है:
public void someMethod (Connection conn)
{
...
SomeOtherClass instance = new SomeOtherClass (conn);
...
}
SomeOtherClass
इस तरह दिखता है (बेशक मैं यहाँ सरल कर रहा हूँ):
public class SomeOtherClass
{
Connection conn;
public SomeOtherClass (Connection conn)
{
this.conn = conn;
}
protected void finalize() throws Throwable
{
if (this.conn != null)
conn.close();
}
}
SomeOtherClass
कुछ परिदृश्यों में अपना स्वयं का DB कनेक्शन बना सकता है, लेकिन अन्य परिदृश्यों में मौजूदा कनेक्शन को स्वीकार कर सकता है, जैसे कि हमारे यहाँ है।
जैसा कि आप देख सकते हैं, उस अनुभाग में someMethod
. के लिए एक कॉल है जो खुले कनेक्शन को तर्क के रूप में स्वीकार करता है। someMethod
SomeOtherClass
. के स्थानीय उदाहरण से कनेक्शन पास करता है . SomeOtherClass
एक finalize
. था विधि जो कनेक्शन को बंद कर देती है।
अब, someMethod
. के बाद रिटर्न, instance
कचरा संग्रहण के लिए पात्र हो जाता है। जब यह कचरा एकत्र किया जाता है, तो इसे finalize
मेथड को गारबेज कलेक्टर थ्रेड द्वारा कॉल किया जाता है, जो कनेक्शन को बंद कर देता है।
अब हम लूप के लिए वापस आते हैं, जो उसी कनेक्शन का उपयोग करके SELECT स्टेटमेंट को निष्पादित करना जारी रखता है जिसे कचरा कलेक्टर थ्रेड द्वारा किसी भी समय बंद किया जा सकता है।
यदि गारबेज कलेक्टर थ्रेड कनेक्शन को बंद करने के लिए होता है, जबकि एप्लिकेशन थ्रेड कुछ mysql कनेक्टर विधि के बीच में होता है जो खुले होने वाले कनेक्शन पर निर्भर करता है, एक NullPointerException
हो सकता है।
finalize
को हटा रहा है विधि ने समस्या का समाधान किया।
हम अक्सर finalize
को ओवरराइड नहीं करते हैं हमारी कक्षाओं में विधि, जिससे बग का पता लगाना बहुत मुश्किल हो गया।