zurück
Autor: Klaas Wedemeyer
Erstellt am: 06 Dez 2006 09:04

Schnellere Datenbankzugriffe mit einem ConnectionPool

Wenn mehrere Programmteile unabhängig von einander auf die Datenbank zugreifen, müssen alle eine eigene Verbindung verwenden. Das Öffen und Schließen verbraucht dabei sehr viel Zeit. Das tritt beonders an zwei Stellen deutlich auf:
- In einer Web-Anwendung macht jeder Request seine Zugriffe auf die DB
- In einer komponentenorientierten Anwendung greift jede Komponente selber auf die DB zu (das fällt besonders beim Start auf, wenn sich alle Komponenten intitalisieren).
Die Lösung: Eine zentrale Stelle, die die Verbindungen öffnet, verwaltet und, wenn nicht mehr gebraucht, wieder schließt. Beim Multithreading können gleichzeitig auch mehrere Verbindungen offen sein.
Das ist gar nicht so schwer: Die Anwendung öffnet und schließt die Verbindungen nicht mehr, sondern fordert sie an und gibt sie wieder frei.

IDbConnection Connection = ConnectionPool.Instance.GetConnection(_ConnectionName);
...
ConnectionPool.Instance.ReleaseConnection(Connection)

Der ConnectionPool gibt entweder eine nicht mehr benutzte Verbindung zurück, oder legt eine neue an.

foreach (ConnectionInfo Info in ConnectionInfos)
{
    if (!Info.IsUsed)
    {
        Info.IsUsed = true;
        return Info.GetConnection();
    }
}
ConnectionInfo NewInfo = new ConnectionInfo(IDbConnectionType, ConnectionString);
ConnectionInfos.Add(NewInfo);
return NewInfo.GetConnection();

Bei der Freigabe wird die Verbindung als nicht mehr benutzt gekennzeichnet.

foreach (ConnectionInfo Info in ConnectionInfos)
{
    if (Info.Connection == Connection))
    {
        Info.IsUsed = false;
        Info.LastUsed = DateTime.Now;
        return;
    }
}

Ein Timer überprüft alle Verbindungen regelmäßig, ob sie eine bestimmte Zeit nicht mehr verwendet wurden und schließt sie gegebenenfalls.

for (int i = ConnectionInfos.Count - 1; i >= 0; i-- )
{
    ConnectionInfo Info = ConnectionInfos[i];
    if (!Info.IsUsed)
    {
        TimeSpan s = DateTime.Now.Subtract(Info.LastUsed);
        if (s.TotalSeconds > IdleTime)
        {
            Info.Connection.Close();
            ConnectionInfos.Remove(Info);
        }
    }
}

Um den Zugriff einfacher zu machen, kann man ein neues Verbindungsobjekt erstellen, das im Open die Verbindung anfordert, im Close diese wieder freigibt und alle anderen Aufrufe weiterleitet.

public class SharedConnection : IdbConnection
{
    public void Open()
    {
        Connection = ConnectionPool.Instance.GetConnection(_ConnectionName);
    }

  public void Close()
  {
    ConnectionPool.Instance.ReleaseConnection(Connection);
    Connection = null;
  }

  public IDbTransaction BeginTransaction(IsolationLevel il)
  {
    return Connection.BeginTransaction(il);
  }
  ...
}

So fällt es fast gar nicht auf, das hinter der Verbindung ein ConnectionPool steht.

Den ganzen Code und ein Beispiel findet Ihr auf meiner Homepage www.KlaasWedemeyer.de. Viel Spaß.


© Copyright 2008 ppedv AG