Laden...

Parallele Db-Verbindungen mit Threads?

Erstellt von budi1602 vor 16 Jahren Letzter Beitrag vor 16 Jahren 1.211 Views
B
budi1602 Themenstarter:in
204 Beiträge seit 2006
vor 16 Jahren
Parallele Db-Verbindungen mit Threads?

verwendetes Datenbanksystem: Access

Hallo!

Ich habe die Datenbankanbindung bis jetzt immer über eine eigene Klasse erstellt.
Diese Klasse lest Daten aus und schreibt Daten in die Datenbank:

Hier die 2 Methoden die ich grundsätzlich verwende:

public OleDbDataReader GetInhalt(string strSql)
		{
            try
            {
                verbindung.Close();
                verbindung.Open();

                OleDbCommand cmd = new OleDbCommand(strSql, verbindung);
                return cmd.ExecuteReader(CommandBehavior.CloseConnection);
            }
            catch (OleDbException ex)
            {
                MessageBox.Show(ex.ToString());
                MessageBox.Show(ex.Message.ToString(), "Datenbankfehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return null;
            }
		}


		public void Ausfuehren(string strSql)
		{
            try
            {
                verbindung.Close(); //Falls von einem Teilprogramm noch die Verbindung offen ist
                verbindung.Open();

                OleDbCommand cmd = new OleDbCommand(strSql, verbindung);
                cmd.ExecuteNonQuery();
                
            }
            catch (OleDbException ex)
            {
                MessageBox.Show(ex.Message.ToString(), "Datenbankfehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
		}

Da die verbindung ja nur geöffnet werden darf, wenn sie geschlossen ist, schließe ich die Verbindung bevor ich die Verbindung erneut öffne....

Seit neuem bekomme ich eine Fehlermeldung, dass die Verbindung den Status "Verbindung wird hergestellt hat.", obwohl ich ja die Verbindung zuvor schließe...

Kann ich diesen Vorgang irgendwie über threads steuern? Oder wäre es besser wenn ich die Verbindung immer erst in der Methode instanziere...

mfg
budi1602

F
10.010 Beiträge seit 2004
vor 16 Jahren

Das ist ja auch die komplett falsche herangehensweise, die du benutzt.

Eine Connection sollte immer nur für eine zusammenhängende Aktion geöffnet
werden, und dananch sofort wieder geschlossen.

Wenn Du dich daran hältst, ist die Fehlermeldung auch weg.

B
budi1602 Themenstarter:in
204 Beiträge seit 2006
vor 16 Jahren

Wie würde dann die richtige herangehensweise aussehen?
bin leider etwas ratlos...googlen bzw. forumsuche haben mir leider noch nicht weitergeholfen...

mfg
budi1602

J
3.331 Beiträge seit 2006
vor 16 Jahren

Den Rumpf für ein "richtiges" Vorgehen mit Hilfe eines using-Blocks habe ich unter
C# und dbase (11:29 Uhr)
skizziert. Die eigentlichen Maßnahmen, beginnend beim Erstellen des DbCommand, gehören in den try-Abschnitt dieses Blocks. Jürgen

476 Beiträge seit 2004
vor 16 Jahren

hallo budi1602,

im Artikelforum gibt es auch einen Artikel "Ressourcen schonen - Datenbanken richtig öffnen und schliessen" von .Kai, der könnte ebenso helfen.

-yellow

Selbst ein Weg von tausend Meilen beginnt mit einem Schritt (chinesisches Sprichwort).

Mein Blog: Yellow's Blog auf sqlgut.de

B
budi1602 Themenstarter:in
204 Beiträge seit 2006
vor 16 Jahren

Danke, hab meinen Code jetzt folgendermaßen adaptiert:


		public OleDbDataReader GetInhalt(string strSql)
		{
            using( OleDbConnection conn = new OleDbConnection(cn) ) 
            {
                try 
                {
                    conn.Close();
                    conn.Open();
                    OleDbCommand cmd = new OleDbCommand(strSql, conn);
                    return cmd.ExecuteReader(CommandBehavior.CloseConnection);
                }
                catch (Exception ex) 
                {
                    MessageBox.Show(ex.ToString());
                    MessageBox.Show(ex.Message.ToString(), "Datenbankfehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return null;
                }
                finally 
                {
                 conn.Dispose();   
                }
            }       
		}

und so greife ich dann auf die methode und auf die daten zu:

            dr = db.GetInhalt(strSql);

            if (dr.HasRows == true)
            {
                while (dr.Read())
                {
                }

Hier tut sich ein neues Problem auf...
Bei while(dr.Read()) kommt die Exception "datareader bereits geschlossen".

Hat jemand eine Idee?

mfg
budi1602

J
3.331 Beiträge seit 2006
vor 16 Jahren

Tja, so ist das mit halbem Verständnis.

Zunächst grundsätzlich: Da Du die DbConnection in einen using-Block gesteckt hast, ist das conn.Close() am Anfang Quatsch und das finally{conn.Dispose} überflüssig.

Zusätzlich sorgst Du mit Deinen return-Anweisungen dafür, dass der using-Block sofort verlassen wird, also gar nicht ordnungsgemäß aufgeräumt wird (bzw. auf ungesteuerte Weise). Besser ist es meistens, Rückgabewerte in einer Variablen result zwischenzuspeichern und erst nach vollständiger Ausführung per "return result" zurückzugehen.

Das Problem beim **DbDataReader **liegt darin, dass er nur "zusammen mit der DbConnection" existiert. Durch Dein "return" verlässt Du die DbConnection, also steht diese nicht mehr zur Verfügung und damit auch der DbDataReader. Die Lösung besteht darin, die Ergebnisse in einem "frei zur Verfügung stehenden" Objekt zurückzugeben, z.B. einer **DataTable **oder (bei einfachen Werten) einer List<>:

        public DataTable GetInhalt(string strSql)
        {
            DataTable result = null;
            using( OleDbConnection conn = new OleDbConnection(cn) )
            {
                try
                {
                    conn.Open();
                    OleDbCommand cmd = new OleDbCommand(strSql, conn);
                    result = cmd.ExecuteQuery(CommandBehavior.CloseConnection);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "Datenbankfehler", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            return result;
        }

Gruß Jürgen

PS. Wieso lese ich in den letzten Tagen ständig ToString(), wenn der betreffende Wert wie ex.Message schon ein String ist... 🙄

F
10.010 Beiträge seit 2004
vor 16 Jahren

Nicht nur das ex.Message.ToString() unsinnig ist, es veschluckt bei DB-Exceptions
meist den wahren grund.

ex.ToString liefert auch InnerExceptions mit.