Toon posts:

[ASP.NET] DB Connecties blijven open staan.

Pagina: 1
Acties:
  • 512 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Mijn ASP.NET pagina maakt een connectie met de database, maar op een of andere manier blijven mijn connecties open staan. Heel vreemd, omdat ik netjes Close() aanroep en zelfs (nog beter) de connectie in een using ( ... ) { ... } blok heb gezet. Ik gebruik een System.Data.SqlClient.SqlCommand object die ik een scalar laat teruggeven middels ExecuteScalar. In de Help zie ik ook nergens terug dat ik mijn SqlCommand moet opruimen en using blok hieromheen zetten heeft geen effect.

Precies bij het voor de 101ste keer openen van een connectie krijg ik de volgende foutmelding:
Time-out is verstreken. De time-outperiode is verstreken voordat een verbinding werd verkregen uit de groep. Een mogelijke oorzaak is dat alle verbindingen in de groep in gebruik waren en de maximale groepsgrootte werd bereikt.

Aangezien er standaard 100 connecties in de .NET connectionpool zitten kan ik concluderen dat geen enkele connectie wordt gesloten. Hieronder een stuk voorbeeldcode waarin het fout gaat. Ik maak gebruik van de Northwind database van MS SQL Server. De RecordCount() functie opent en sluit een connectie. Dit is het stuk code waarin het dus fout gaat. Daarnaast is de Page_Load() functie gegeven voor het testen. Deze voert de RecordCount net zolang uit, totdat geen connectie meer geopend kan worden (en dit is bij mij dus bij connectie nr. 101).
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
protected HtmlForm Form1;

private void RecordCount() {
    string cmdText = "SELECT COUNT(*) AS C FROM Customers";
    string connString = "server=(local);User ID=sa;Pwd=;database=Northwind";

    using ( SqlConnection conn = new SqlConnection(connString) ) {
        conn.Open();
        SqlCommand cmd = new SqlCommand(cmdText, conn);
        int me = (int)cmd.ExecuteScalar(); 
    }
    // using ends so conn.Dispose is called and connection is closed.
}

private void Page_Load(object sender, System.EventArgs e) {
    int connCounter = 0; // counts the succesfully opened connections
    bool error = false; // indicates if there is an error during opening
    string errorMessage = ""; // the possible error message

    // Count how many times we can Open a connection
    while ( error == false && connCounter < 1000 ) {
        try  {
            RecordCount();
            connCounter++;
        } catch ( Exception ex ) {
            // save error message and break from while
            errorMessage = ex.Message;
            error = true;
        }
    }

    // Show the result on the Clients browser
    Label myLabel = new Label();
    if ( error ) {
        myLabel.Text = "Error while opening connection " +
            (connCounter+1).ToString() + 
            ".<br>" + errorMessage;

    }
    else {
        myLabel.Text = "Successfully opened a 1000 connections.";
    }

    this.Form1.Controls.Add( myLabel );
}


Wat-o-wat doe ik fout? 8)7

  • whoami
  • Registratie: December 2000
  • Laatst online: 05:46
Connection pooling kan enkel gebruikt worden als je:
- iedere keer je connectie sluit
- je altijd exact dezelfde connection-string gebruikt.

Ik zie dat je jouw connection-string hard-coded in je code staan hebt; het kan dus gebeuren dat er iedere keer een klein verschil in je connection-string is (een spatie kan la voldoende zijn).
Wat je dus beter kunt doen is je connection-string in je web.config zetten, en deze dan ophalen als dat nodig is. Op die manier heb je dus altijd zeker exact dezelfde conn. string. (Alhoewel je die nu dus maar 1x hebt staan, en verder in een loopje werkt...

Wat ik ook zou doen, is er toch voor zorgen dat m'n connectie altijd gesloten wordt. Je gebruikt nu wel een using, maar ik zou toch m'n conn.Close() er altijd expliciet bijzetten, en ik zou dat zelfs in een finally{} block zetten, zodanig dat ze altijd zeker gesloten wordt, ook als er een exception optreedt.

https://fgheysels.github.io/


  • EfBe
  • Registratie: Januari 2000
  • Niet online
whoami schreef op vrijdag 18 maart 2005 @ 08:52:
Wat ik ook zou doen, is er toch voor zorgen dat m'n connectie altijd gesloten wordt. Je gebruikt nu wel een using, maar ik zou toch m'n conn.Close() er altijd expliciet bijzetten, en ik zou dat zelfs in een finally{} block zetten, zodanig dat ze altijd zeker gesloten wordt, ook als er een exception optreedt.
Dit hoeft niet,
using(type foo = new type)
{
// code
}

genereert:

type foo =new type();
try
{
// code
}
finally
{
foo.Dispose();
}

TS: Als objectpooling uit staat (wat me sterk lijkt, dat doe je IMHO via de connection string), loopt je programma inderdaad vast met een max amount of connections. Maar het blijft een vaag iets, je code zou gewoon moeten werken.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • OZ-Gump
  • Registratie: November 2002
  • Laatst online: 14-05-2024

OZ-Gump

terug van weggeweest

En toch ben ik het met whoami eens: zorg voor een eigen aanroep van de conn.Close() en de connection zal gerecycled worden in de connectionpool.

Heeft de TS dat al geprobeerd?

My personal website


  • whoami
  • Registratie: December 2000
  • Laatst online: 05:46
EfBe schreef op vrijdag 18 maart 2005 @ 09:27:
TS: Als objectpooling uit staat (wat me sterk lijkt, dat doe je IMHO via de connection string), loopt je programma inderdaad vast met een max amount of connections. Maar het blijft een vaag iets, je code zou gewoon moeten werken.
Dan zou dat, imho, toch niet mogen. (als connection pooling uitstaat).
Als connection-pooling uitstaat, en je sluit iedere keer je connectie, dan zou die connectie gewoon gesloten moeten worden, en niet in een pool gezet worden.
Als je dan een (nieuwe) connectie opent, dan zou er een nieuwe connectie moeten gecrëerd worden, ipv dat er een uit de pool gehaald wordt.
Als je geen gebruik maakt van connection pooling, dan mag je programma niet vast lopen met een max. amount of connections (vooropgesteld dat je iedere keer je connectie sluit). Je sluit dan nl altijd je connectie, en je creeërt telkens een nieuwe.

https://fgheysels.github.io/


Verwijderd

Topicstarter
Nee, EfBe heeft gelijk. Het gebruik van Using is equivalent met het gebruik van het try finally blok. Dit zorgt dat er altijd Dispose aangeroepen wordt. Bij de SqlDataReader en SqlConnection roept de Dispose() daarbij Close() aan.

Het aanroepen van Close() expliciet had ik ook al gebrobeerd en de volgende code geeft dan ook hetzelfde resultaat.
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void RecordCount() {
    string cmdText = "SELECT COUNT(*) AS C FROM Customers";
    string connString = "server=(local);User ID=sa;Pwd=;database=Northwind";

    SqlConnection conn = new SqlConnection(connString); // ) {
    conn.Open();
    try {
        SqlCommand cmd = new SqlCommand(cmdText, conn);
        int me = (int)cmd.ExecuteScalar(); 
    }
    finally {
        conn.Close();
    }
}
Ik zie dat je jouw connection-string hard-coded in je code staan hebt; het kan dus gebeuren dat er iedere keer een klein verschil in je connection-string is (een spatie kan la voldoende zijn).
Nee, dat lijk me niet. Zolang het programma het draait (in mijn geval) geven de C# compiler én de JIT-compiler mij de zekerheid dat die string hetzelfde is. De string wordt telkens bij het uitvoeren van RecordCount functie vanuit het code geheugen (statisch) gekopieerd naar de heap en zolang de constante string uit het code geheugen hetzelfde blijft (en dat is zeker zolang ik het programma niet hercompileer) is de kopie ook hetzelfde. (mogelijk wordt de string niet eens gekopieerd als je code geoptimaliseerd laat compileren).
Als objectpooling uit staat (wat me sterk lijkt, dat doe je IMHO via de connection string), loopt je programma inderdaad vast met een max amount of connections.
Lijkt mij ook sterk, ik heb andere code waar ik gebruik maak van DataReaders. Deze code werkt uitstekend. Maar als die pooling uit mocht staan, hoe zet ik hem dan aan?

Kunnen jullie die code eens code-pasten in een VS-projectje en kijken wat jullie op het scherm krijgen? Als je de gehele code over de Load_Page() functie heen paste van een leeg project dan zou het meteen moeten werken (wel ff de connection string aanpassen). Dan kan ik zien of het mijn instellingen zijn, of dat er iets speciaals aan de hand is met die SqlCommand.

  • OZ-Gump
  • Registratie: November 2002
  • Laatst online: 14-05-2024

OZ-Gump

terug van weggeweest

Misschien dat dit artikel iets toevoegt....
En dit artikel voegt volgens mij zeker iets toe. En deze ook...

Overigens zou het natuurlijk in dit geval veel mooier zijn om voor je while eenmalig de connection te openen, deze mee te geven aan de methode RecordCount en vervolgens weer te sluiten. Wanneer er namelijk ergens iets misgaat in een connection, wordt deze standaard pas na 15 seconden gerecycled in de connection pool. En die while is sneller bij de 1000 dan 15 seconden ;)

[ Voor 32% gewijzigd door OZ-Gump op 18-03-2005 10:35 ]

My personal website


Verwijderd

Topicstarter
Misschien dat dit artikel iets toevoegt....
Helaas, geen nieuwe informatie. De msdn artikelen had ik overigens al eens gelezen. De artikelen zeggen allemaal hetzelfde.
Overigens zou het natuurlijk in dit geval veel mooier zijn om voor je while eenmalig de connection te openen, deze mee te geven aan de methode RecordCount en vervolgens weer te sluiten [...] En die while is sneller bij de 1000 dan 15 seconden ;)
Goh, je meent het! :D
Natuurlijk heb je gelijk. De while lus in de Page_Load is ook puur om te controleren of the RecordCount functie de connectie goed sloot. Het is ook redelijk zinloos om 100x aan de DB te vragen hoeveel records er nou ook al weer in de Customers tabel zitten. :)

Overigens merk in in de Windows Performance monitor, dat er geen connecties open blijven staan bij de SQL Server. Bij het uitvoeren van de pagina zie ik hooguit 1x dat er een connectie wordt geopend, en vervolgens meteen weer gesloten wordt. De connection counter piekt dus niet naar 100, wat ik erg vreemd vind.

  • EfBe
  • Registratie: Januari 2000
  • Niet online
whoami schreef op vrijdag 18 maart 2005 @ 09:38:
Dan zou dat, imho, toch niet mogen. (als connection pooling uitstaat).
Als connection-pooling uitstaat, en je sluit iedere keer je connectie, dan zou die connectie gewoon gesloten moeten worden, en niet in een pool gezet worden.
Als je dan een (nieuwe) connectie opent, dan zou er een nieuwe connectie moeten gecrëerd worden, ipv dat er een uit de pool gehaald wordt.
Als je geen gebruik maakt van connection pooling, dan mag je programma niet vast lopen met een max. amount of connections (vooropgesteld dat je iedere keer je connectie sluit). Je sluit dan nl altijd je connectie, en je creeërt telkens een nieuwe.
Je hebt gelijk, ik haalde wat dingen door elkaar.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Verwijderd

Topicstarter
Okee, nou breekt mijn klomp. Na wat testen met wat alternatieve aanroepen (retourneren van bijv. DataReader etc) waarvan ik zeker wist dat ze goed waren, bleef het probleem bestaan. Ik begon opeens te vermoeden dat het wel eens helemaal niet aan mijn code of instelling hoefde te liggen.

Ik heb mijn systeem eens opnieuw opgestart en tata.... 1000 connecties in nog geen 10de van een seconde geopend. Wat hier mis is gegaan is me nog een raadsel :? maar je wilt dit iig niet meemaken in een live omgeving.

  • whoami
  • Registratie: December 2000
  • Laatst online: 05:46
Hmm, en van waar komen die connecties ?

https://fgheysels.github.io/


  • pling
  • Registratie: Maart 2001
  • Laatst online: 30-03 21:07

pling

Lekker Kepjoeteren

Ik denk dat je je sqlcommand ook moet disposen (met using), deze houd een referentie naar het connectie object waardoor deze niet naar de pool teruggaat.

  • whoami
  • Registratie: December 2000
  • Laatst online: 05:46
Ik denk dat dat niet waar is, want de connectie is gesloten; en daardoor gaat ie terug naar de pool.

TS: die 1000 connecties, wanneer worden die precies aangemaakt ? Is dat tijdens het runnen van je programma ?

https://fgheysels.github.io/


  • OZ-Gump
  • Registratie: November 2002
  • Laatst online: 14-05-2024

OZ-Gump

terug van weggeweest

Met 1000 connecties bedoelt de TS dat zijn loopje van 1000 keer de connection openen, de count uitvoeren en de connection weer sluiten is doorlopen.

Hij krijgt nu dus geen fouten over te weinig available connections meer, als ik het goed begrijp.

offtopic:
Dit is inderdaad iets wat je ontzettend niet wilt tegenkomen in productieomgevingen

My personal website


Verwijderd

Topicstarter
Hij krijgt nu dus geen fouten over te weinig available connections meer, als ik het goed begrijp.
Precies. Dank je OZ-Gump! :)

zie sourcecode.

  • pling
  • Registratie: Maart 2001
  • Laatst online: 30-03 21:07

pling

Lekker Kepjoeteren

Wellicht had je probleem met het volgende te maken:
http://blogs.msdn.com/angelsb/archive/2004/08/25/220333.aspx

Verwijderd

Topicstarter
Wellicht had je probleem met het volgende te maken:
http://blogs.msdn.com/angelsb/archive/2004/08/25/220333.aspx
In de hierbovengenoemde blog wordt verwezen naar het volgende MSDN artikel dat idd mijn probleem oplost.

http://support.microsoft....aspx?scid=kb;en-us;830118

Dit artikel beschrijft een BUG in Visual Studio 2003, waarbij gebruik wordt gemaakt van SQL Debugging via de MS SQL Server. Het uitschakelen van de SQL Debugging loste al mijn problemen op.

Thanx guys!!
Pagina: 1