webForumDet fria alternativet

"Too many connections"

.NETur .NET

20 svar · 861 visningar · startad av k0ffe

Medlem sedan maj 2003352 inlägg
Frågan#1

Hej!

Scenariot lyder:

Jag har ett projekt där jag läser in olika delar av sajten med funktionsanrop till funktioner, vilka jag har i en global class-fil under App_Code.

Nu har jag stött på problem under dessa experiment. Som rubriken säger får jag "Too many connections.."-exeptions ibland.

Kodexempel, default.aspx:

<h3 ID="h3_Title" runat="server" ></h3>

default.aspx.cs:

int pageID = 10;
h3_Title.InnerHtml = CommonFunctions.getPageTitle(pageID);

functions.cs

public static string strConn = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;

public static string getPageTitle(int ID)
    {
        OdbcConnection connection = new OdbcConnection(strConn);
        OdbcCommand cmd = new OdbcCommand();
        OdbcDataReader dr;
        cmd.Connection = connection;
        cmd.CommandText = "SELECT title FROM page WHERE id = ?";
        cmd.Parameters.AddWithValue("ID", ID);
        connection.Open();
        dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
        if (dr.Read())
        {
            return (string)dr["title"];
        }
        else
        {
            return null;
        }

    }

Kan man göra såhär? Rent generellt så känns det som att min connection aldrig stängs här:

dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);

Problemet inträffar alltså när jag tillämpar denna metod flertalet gånger på samma aspx-sida.

Bör jag istället skapa mitt connection-objekt i default.aspx.cs och skicka med detta i funktionsanropet för att, när jag har anropat alla funktioner, stänga det?

Medlem sedan dec. 20025 483 inlägg
#2

Ja, anslutningarna stängs aldrig. I stället kan du använda 'using':

using (OdbcConnection connection = new OdbcConnection(strConn))
{
  // resten av koden
}

Då sköts stängning och uppstädning automagiskt.

Medlem sedan maj 2003352 inlägg
#3

Oj, snabbt svar!

OK, jag bör alltså bygga om funktionerna enligt nedan:

public static string getPageTitle(int ID)
    {
      using(OdbcConnection connection = new OdbcConnection(strConn))
       {
        OdbcCommand cmd = new OdbcCommand();
        OdbcDataReader dr;
        cmd.Connection = connection;
        cmd.CommandText = "SELECT title FROM page WHERE id = ?";
        cmd.Parameters.AddWithValue("ID", ID);
        connection.Open();
        dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
        if (dr.Read())
        {
            return (string)dr["title"];
        }
        else
        {
            return null;
        }

}
        
        

    }
Medlem sedan dec. 20025 483 inlägg
#4

Du kan t.o.m. dra det ett par steg längre:

public static string getPageTitle(int ID)
    {
      using(OdbcConnection connection = new OdbcConnection(strConn))
       {
        using (OdbcCommand cmd = new OdbcCommand())
        {            
            cmd.Connection = connection;
            cmd.CommandText = "SELECT title FROM page WHERE id = ?";
            cmd.Parameters.AddWithValue("ID", ID);
            connection.Open();
            using (OdbcDataReader dr = cmd.ExecuteReader())
            {
                if (dr.Read())
                {
                    return (string)dr["title"];
                }
                else
                {
                    return null;
                }
            }
        }
    }
}

...Annars, i.o.m. att du säger 'CommandBehavior.CloseConnection' bör det räcka med att stänga 'dr' för att anslutningen skall stängas.

Medlem sedan dec. 20014 239 inlägg
#5

En följdfråga:
Varför ODBC ? Vad är det för databas du ansluter dig till, finns ingen .NET adapter ? ODBC är ganska slött jämfört med andra anslutningstekniker.

Medlem sedan maj 2003352 inlägg
#6

Peter:

...Annars, i.o.m. att du säger 'CommandBehavior.CloseConnection' bör det räcka med att stänga 'dr' för att anslutningen skall stängas.

Menar du då att mitt exempel borde fungera från start? Eller menar du att jag kan skippa den sista biten?

using (OdbcDataReader dr = cmd.ExecuteReader())
            {
                if (dr.Read())
                {
                    return (string)dr["title"];
                }
                else
                {
                    return null;
                }
            }

Vad gör egentligen "CommandBehavior.CloseConnection", och varför stängs anslutningen om jag använder "CommandBehavior.CloseConnection" OCH dr.Close() men inte annars? Anslutningen ska ju stängas iom

using(OdbcConnection connection = new OdbcConnection(strConn))

?

Zaiman:
DBn är mySQL, varför jag använder ODBC...

Medlem sedan dec. 20014 239 inlägg
#7

Har du inte möjlighet att installera .NET connectorn för MySQL eller har inte ditt webhotell någon?

Medlem sedan dec. 20025 483 inlägg
#8

Ditt exempel bör fungera från start OM du ser till att readern stängs. Detta gäller endast om också anger 'CommandBehavior.CloseConnection'. Använder du inte det sistnämnda måste du explicit stänga även anslutningen.

Jag föredrar att använda 'using'. Det direktivet ser till att objekt båda stängs OCH dispose:as.

Medlem sedan maj 2003352 inlägg
#9

Zaiman: Jag har en egen maskin för DB så jag KAN om jag vill, men varför vill jag göra det?

Peter: OK! Då kör jag på ditt förslag helt enkelt, vad spelar det för roll om det blir lite FÖR bra? :)

Tusen tack!

Medlem sedan maj 20012 812 inlägg
#10

PeterS skrev:

Jag föredrar att använda 'using'. Det direktivet ser till att objekt båda stängs OCH dispose:as.

Framför allt så är man säker på att kopplingen stängs även om ett fel skulle inträffa mellan innanför ditt using-block

Om man inte använd using så skall man använda sig av Try-finally, eller Try-catch-finally. Och stänga sina kopplingar i finally blocket.

- M

Medlem sedan maj 2003352 inlägg
#11

Gladh: OK!

Jag har nu sett över mina connections mot DB:n och fick ner antalet connections / sidladdning från 4 till 1...

Medlem sedan feb. 2005280 inlägg
#12

Gladh skrev:

Om man inte använd using så skall man använda sig av Try-finally, eller Try-catch-finally. Och stänga sina kopplingar i finally blocket.

- M

Måste man ha Finally?

Det går inte lika bra med

objConn.Open();
try
{
	SqlDataAdapter da = new SqlDataAdapter(sql, objConn);
	da.Fill(ds);
}
catch { }
objConn.Close();

?

Medlem sedan juni 20008 205 inlägg
#13

Det dåliga med det sättet är att man sväljer alla exceptions, vilket innebär att alla databasfel brukar yttra sig på något supermystiskt sätt med NullReferenceException någonstans där det inte borde vara så. Bättre att använda finally och låta alla exceptions segla upp i anropshierarkin och ta hand om dem med ordentlig felhantering. Dessutom är det ett bättre sätt att säga "oavsett vad som händer i try/catch-en vill jag göra det här".

Sen är förstås using bättre än try/finally och jag ser egentligen aldrig några skäl att inte använda det om man har en resurs som bara används under ett anrop i en metod. Det är till och med bättre, har man flera resurser som man försöker disposa i finallyn kan en av dem kasta ett exception under disposandet och resultera i att de andra kvarvarande resurserna inte disposas.

Medlem sedan dec. 20014 239 inlägg
#14

k0ffe skrev:

Zaiman: Jag har en egen maskin för DB så jag KAN om jag vill, men varför vill jag göra det?

Ett ord prestanda :)

Medlem sedan feb. 2005280 inlägg
#15

spango skrev:

Det dåliga med det sättet är att man sväljer alla exceptions, vilket innebär att alla databasfel brukar yttra sig på något supermystiskt sätt med NullReferenceException någonstans där det inte borde vara så. Bättre att använda finally och låta alla exceptions segla upp i anropshierarkin och ta hand om dem med ordentlig felhantering. Dessutom är det ett bättre sätt att säga "oavsett vad som händer i try/catch-en vill jag göra det här".

Sen är förstås using bättre än try/finally och jag ser egentligen aldrig några skäl att inte använda det om man har en resurs som bara används under ett anrop i en metod. Det är till och med bättre, har man flera resurser som man försöker disposa i finallyn kan en av dem kasta ett exception under disposandet och resultera i att de andra kvarvarande resurserna inte disposas.

Ok tack för en bra förklaring, jag ska anamma konceptet :bire

Medlem sedan maj 200819 inlägg
#16

Peter S skrev:

Ja, anslutningarna stängs aldrig. I stället kan du använda 'using':

using (OdbcConnection connection = new OdbcConnection(strConn))
{
  // resten av koden
}

Då sköts stängning och uppstädning automagiskt.

Ska inte cmd.ExecuteReader(CommandBehavior.CloseConnection); göra att data readern stängs efter att man har läst klart? Varför finns den annars?

Medlem sedan dec. 20025 483 inlägg
#17

quickhelp skrev:

Ska inte

cmd.ExecuteReader(CommandBehavior.CloseConnection);

leda till att stänga data readern efter att man läst klart?

Nej. Men om readern stängs så stängs även anslutningen.

Medlem sedan maj 200819 inlägg
#18

Peter S skrev:

Nej. Men om readern stängs så stängs även anslutningen.

Och det är det som man slipper om man använder "using"?
Hur vet den att den ska anropa close() på readern då?

Kan tänka mig att allt som är deklarerat inuti "using" kanske garbage collectas, men hur vet den att den ska anropa close() ?

Medlem sedan dec. 20025 483 inlägg
#19

quickhelp skrev:

Och det är det som man slipper om man använder "using"?

Ja. Alternativet är ju att explicit kalla på Close().

quickhelp skrev:

Hur vet den att den ska anropa close() på readern då?

Using definierar ju ett scope, precis som andra statements. Så i slutet på det scopet anropas Dispose() automagiskt för de objekt som skapats. I det här fallet kan man väl anta att readerns Dispose() innehåller en funktion för att stänga.

Medlem sedan maj 200819 inlägg
#20

Peter S skrev:

Ja. Alternativet är ju att explicit kalla på Close().

Using definierar ju ett scope, precis som andra statements. Så i slutet på det scopet anropas Dispose() automagiskt för de objekt som skapats. I det här fallet kan man väl anta att readerns Dispose() innehåller en funktion för att stänga.

Det där är ju riktigt användbart!
Ska börja använda det i min kod också :)

Tack för förklaringen.

141 ms totalt · 3 externa anrop · v20260731065814-full.b746b907
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
137 ms — hämta tråd, inlägg och bilagor (db)