ExecuteReader को एक खुले और उपलब्ध कनेक्शन की आवश्यकता होती है। कनेक्शन की वर्तमान स्थिति कनेक्ट हो रही है


114

जब ASP.NET ऑनलाइन के माध्यम से MSSQL डेटाबेस से कनेक्ट करने का प्रयास किया जाता है, तो मुझे दो या दो से अधिक लोगों को एक साथ जोड़ने पर निम्नलिखित मिलेगा:

ExecuteReader को एक खुले और उपलब्ध कनेक्शन की आवश्यकता होती है। कनेक्शन की वर्तमान स्थिति कनेक्ट हो रही है।

साइट मेरे लोकलहोस्ट सर्वर पर ठीक काम करती है।

यह रफ कोड है।

public Promotion retrievePromotion()
{
    int promotionID = 0;
    string promotionTitle = "";
    string promotionUrl = "";
    Promotion promotion = null;
    SqlOpenConnection();
    SqlCommand sql = SqlCommandConnection();

    sql.CommandText = "SELECT TOP 1 PromotionID, PromotionTitle, PromotionURL FROM Promotion";

    SqlDataReader dr = sql.ExecuteReader();
    while (dr.Read())
    {
        promotionID = DB2int(dr["PromotionID"]);
        promotionTitle = DB2string(dr["PromotionTitle"]);
        promotionUrl = DB2string(dr["PromotionURL"]);
        promotion = new Promotion(promotionID, promotionTitle, promotionUrl);
    }
    dr.Dispose();
    sql.Dispose();
    CloseConnection();
    return promotion;
}

क्या मुझे पता है कि क्या गलत हो सकता है और मैं इसे कैसे ठीक करूं?

संपादित करें: नहीं भूलना, मेरा कनेक्शन स्ट्रिंग और कनेक्शन दोनों स्थैतिक हैं। मेरा मानना ​​है कि यही कारण है। कृपया सलाह दें।

public static string conString = ConfigurationManager.ConnectionStrings["dbConnection"].ConnectionString;
public static SqlConnection conn = null;

24
ASP.NET जैसे मल्टीथ्रेडिंग-वातावरण में साझा / स्थिर कनेक्शन का उपयोग न करें क्योंकि आप ताले या अपवाद (बहुत सारे खुले कनेक्शन आदि) उत्पन्न कर रहे हैं। अपनी डीबी-क्लास को कचरे में फेंक दें और जहां आप की आवश्यकता हो, वहां ado.net ऑब्जेक्ट्स बनाएं, खोलें, उपयोग करें, बंद करें, डिस्पोज़ करें। साथ ही उपयोग-कथन पर एक नज़र डालें।
टिम श्मेल्टर

2
क्या आप मुझे SqlOpenConnection (), और sql.ExecuteReader () के बारे में विस्तार दे सकते हैं; कार्य? ..
अंकित राजपूत

निजी शून्य SqlOpenConnection () {try {conn = new SqlConnection (); con.ConnectionString = conString; conn.Open (); } catch (SqlException ex) {फेंक पूर्व; }}
गुओ होंग लिम

@GuoHongLim: मैं यह उल्लेख करना भूल गया हूँ कि एक स्थैतिक conStringभी प्रदर्शन के मामले में कुछ नहीं जोड़ता क्योंकि यह डिफ़ॉल्ट रूप से कैश्ड है (वैसे भी वर्तमान एप्लिकेशन के लिए हर कॉन्फ़िगरेशन मान)।
टिम श्मेल्टर

... और बस इसे एक ज्ञात-अज्ञात बनाने के लिए: यह सुनिश्चित करना कि आप अपने डेटाबेस लेनदेन को संभालना / यूनिट-ऑफ-वर्क सही को पाठक के लिए एक अभ्यास के रूप में छोड़ दें।
मावरम

जवाबों:


226

केवल पहली टिप्पणी करने के लिए क्षमा करें, लेकिन मैं लगभग हर दिन एक समान टिप्पणी पोस्ट कर रहा हूं क्योंकि बहुत से लोग सोचते हैं कि ADO.NET कार्यक्षमता को DB-Class (मुझे भी 10 साल पहले) में एन्क्रिप्ट करना स्मार्ट होगा। ज्यादातर वे स्थिर / साझा वस्तुओं का उपयोग करने का निर्णय लेते हैं क्योंकि यह किसी भी कार्रवाई के लिए एक नई वस्तु बनाने की तुलना में तेज़ प्रतीत होता है।

यह न तो peformance के संदर्भ में एक अच्छा विचार है और न ही विफल-सुरक्षा के संदर्भ में।

कनेक्शन-पूल के क्षेत्र में शिकार न करें

वहाँ एक अच्छा कारण है ADO.NET आंतरिक रूप में डीबीएमएस करने के लिए अंतर्निहित कनेक्शन का प्रबंधन करता है ADO-NET कनेक्शन-ताल :

व्यवहार में, अधिकांश एप्लिकेशन कनेक्शन के लिए केवल एक या कुछ अलग कॉन्फ़िगरेशन का उपयोग करते हैं। इसका मतलब है कि आवेदन निष्पादन के दौरान, कई समान कनेक्शन बार-बार खोले और बंद किए जाएंगे। कनेक्शन खोलने की लागत को कम करने के लिए, ADO.NET कनेक्शन पूलिंग नामक एक अनुकूलन तकनीक का उपयोग करता है।

कनेक्शन पूलिंग नए कनेक्शन खोलने की संख्या को कम करता है। पूलर शारीरिक संबंध के स्वामित्व को बनाए रखता है। यह प्रत्येक दिए गए कनेक्शन कॉन्फ़िगरेशन के लिए सक्रिय कनेक्शन का एक सेट जीवित रखकर कनेक्शन का प्रबंधन करता है। जब भी कोई उपयोगकर्ता किसी कनेक्शन पर ओपन कॉल करता है, तो पूल में उपलब्ध कनेक्शन के लिए पूलर दिखता है। यदि कोई पूल किया गया कनेक्शन उपलब्ध है, तो वह नया कनेक्शन खोलने के बजाय कॉल करने वाले को वापस कर देता है। जब एप्लिकेशन कनेक्शन पर कॉल बंद करता है, तो पूलर इसे बंद करने के बजाय सक्रिय कनेक्शन के पूल किए गए सेट पर लौटा देता है। एक बार कनेक्शन पूल में वापस आने के बाद, यह अगले ओपन कॉल पर पुन: उपयोग किए जाने के लिए तैयार है।

तो जाहिर है कि कनेक्शन बनाने, खोलने या बंद करने से बचने का कोई कारण नहीं है क्योंकि वे वास्तव में बनाए, खोले और बंद नहीं हुए हैं। यह कनेक्शन पूल के लिए "केवल" एक ध्वज है, यह जानने के लिए कि कनेक्शन का पुन: उपयोग किया जा सकता है या नहीं। लेकिन यह एक बहुत महत्वपूर्ण ध्वज है, क्योंकि यदि कोई कनेक्शन "उपयोग में है" (कनेक्शन पूल मानता है), तो एक नया भौतिक कनेक्शन DBMS के लिए खुला होना चाहिए जो बहुत महंगा है।

तो आप कोई प्रदर्शन सुधार नहीं बल्कि विपरीत प्राप्त कर रहे हैं। यदि निर्दिष्ट अधिकतम पूल आकार (100 डिफ़ॉल्ट है) तक पहुँच गया है, तो आपको अपवाद (बहुत सारे खुले कनेक्शन ...) भी मिलेंगे। तो यह न केवल प्रदर्शन को जबरदस्त रूप से प्रभावित करेगा, बल्कि यह एक त्रुटि के लिए एक स्रोत भी होगा और (लेनदेन का उपयोग किए बिना) डेटा-डंपिंग-क्षेत्र।

यदि आप स्थैतिक कनेक्शन का उपयोग कर रहे हैं, तो आप इस ऑब्जेक्ट तक पहुँचने के लिए कोशिश कर रहे प्रत्येक थ्रेड के लिए एक लॉक बना रहे हैं। ASP.NET प्रकृति द्वारा एक बहुस्तरीय वातावरण है। तो इन तालों के लिए एक शानदार मौका है जो सबसे अच्छे प्रदर्शन का कारण बनता है। वास्तव में जितनी जल्दी या बाद में आपको कई अलग-अलग अपवाद मिलेंगे (जैसे आपके ExecuteReader को एक खुले और उपलब्ध कनेक्शन की आवश्यकता है )।

निष्कर्ष :

  • कनेक्शन या किसी भी ADO.NET ऑब्जेक्ट का पुन: उपयोग न करें।
  • उन्हें स्थिर / साझा न करें (VB.NET में)
  • हमेशा बनाएं, खोलें (कनेक्शनों के मामले में), उपयोग करें, उन्हें बंद करें और उन्हें डिस्पोज करें जहां आपको उनकी आवश्यकता है (एक विधि में फ़े)
  • का उपयोग using-statementनिपटान के लिए और करीब (कनेक्शन के मामले में) implicitely

यह न केवल कनेक्शन के लिए सच है (हालांकि सबसे अधिक ध्यान देने योग्य)। लागू IDisposableहोने वाली प्रत्येक वस्तु का निपटान किया जाना चाहिए (सबसे सरल using-statement), System.Data.SqlClientनाम स्थान में सभी अधिक ।

उपरोक्त सभी एक कस्टम डीबी-क्लास के खिलाफ बोलते हैं जो सभी वस्तुओं को इनकैप्सुलेट और पुनः उपयोग करता है। यही कारण है कि मैंने इसे कचरा करने के लिए टिप्पणी की। यह केवल एक समस्या का स्रोत है।


संपादित करें : यहाँ अपने retrievePromotion-मिथोड का एक संभावित कार्यान्वयन है :

public Promotion retrievePromotion(int promotionID)
{
    Promotion promo = null;
    var connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["MainConnStr"].ConnectionString;
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        var queryString = "SELECT PromotionID, PromotionTitle, PromotionURL FROM Promotion WHERE PromotionID=@PromotionID";
        using (var da = new SqlDataAdapter(queryString, connection))
        {
            // you could also use a SqlDataReader instead
            // note that a DataTable does not need to be disposed since it does not implement IDisposable
            var tblPromotion = new DataTable();
            // avoid SQL-Injection
            da.SelectCommand.Parameters.Add("@PromotionID", SqlDbType.Int);
            da.SelectCommand.Parameters["@PromotionID"].Value = promotionID;
            try
            {
                connection.Open(); // not necessarily needed in this case because DataAdapter.Fill does it otherwise 
                da.Fill(tblPromotion);
                if (tblPromotion.Rows.Count != 0)
                {
                    var promoRow = tblPromotion.Rows[0];
                    promo = new Promotion()
                    {
                        promotionID    = promotionID,
                        promotionTitle = promoRow.Field<String>("PromotionTitle"),
                        promotionUrl   = promoRow.Field<String>("PromotionURL")
                    };
                }
            }
            catch (Exception ex)
            {
                // log this exception or throw it up the StackTrace
                // we do not need a finally-block to close the connection since it will be closed implicitely in an using-statement
                throw;
            }
        }
    }
    return promo;
}

यह कनेक्शन कार्य प्रतिमान देने के लिए वास्तव में उपयोगी है। इस स्पष्टीकरण के लिए धन्यवाद।
एमिन्विनेंट जूल

अच्छी तरह से लिखा, कुछ लोगों के लिए एक स्पष्टीकरण गलती से पता चलता है, और मैं चाहता हूं कि अधिक लोग यह जानते थे। (+1)
एंड्रयू हिल

1
धन्यवाद सर, मुझे लगता है कि यह इस विषय पर सबसे अच्छा स्पष्टीकरण है जिसे मैंने कभी पढ़ा है, एक ऐसा विषय जो बहुत महत्वपूर्ण है और जिसमें कई newbies की गलती है। आपकी उत्कृष्ट लेखन क्षमता के लिए मुझे आपकी प्रशंसा करनी चाहिए।
सासिनोॉफ्ट

@ टिम Schmelter मैं अपने प्रश्नों को विभिन्न थ्रेड पर कैसे चला सकता हूं जो आपके सुझाए गए दृष्टिकोण का उपयोग करके वापस करने / रोल करने के लिए एकल लेनदेन का उपयोग करता है?
14

1

मैंने कुछ दिन पहले यह त्रुटि पकड़ी थी।

मेरे मामले में यह इसलिए था क्योंकि मैं एक सिंगलटन पर एक लेन-देन का उपयोग कर रहा था।

.Net ऊपर बताए अनुसार सिंगलटन के साथ अच्छी तरह से काम नहीं करता है।

मेरा समाधान यह था:

public class DbHelper : DbHelperCore
{
    public DbHelper()
    {
        Connection = null;
        Transaction = null;
    }

    public static DbHelper instance
    {
        get
        {
            if (HttpContext.Current is null)
                return new DbHelper();
            else if (HttpContext.Current.Items["dbh"] == null)
                HttpContext.Current.Items["dbh"] = new DbHelper();

            return (DbHelper)HttpContext.Current.Items["dbh"];
        }
    }

    public override void BeginTransaction()
    {
        Connection = new SqlConnection(Entity.Connection.getCon);
        if (Connection.State == System.Data.ConnectionState.Closed)
            Connection.Open();
        Transaction = Connection.BeginTransaction();
    }
}

मैंने अपने उदाहरण के लिए HttpContext.Current.Items का उपयोग किया। यह वर्ग DbHelper और DbHelperCore मेरी अपनी कक्षा है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.