Benutzer mit den meisten Antworten
Datenbank

Frage
-
Hallo
Ich habe eine VB.NET-Anwendung, die auf zwei Mysql-Datenbanken zugreift. Zugriff, Auslesen und Eintragen in die Datenbank klappt.
Die Methoden zum Auslesen und eintragen in die Datenbank, werden von einem Timer, alle 1s aufgerufen. Die Anwendung soll als Hintergrund - Prozess laufen. Die Anwendung dient dazu daten von einem Microcontroller über SerialPort auszulesen und sie dann selbständig (m.H. des Timers) in die Datenbank eintragen. Soweit so gut!
Problem ist jetzt nur, das es immer wieder Fehlermeldung gibt, wie z.B. Datenbank must be solid and open, oder Objektverweis nicht korrekt usw...
Das Eintragen und so funktioniert aber weiterhin.... nur die Fehlermeldungen nerven!
Bin deswegen hingegangen und habe den Timer von 1s auf 7s hochgesetzt und siehe da die Fehlermeldung waren nach 4 Std eintragen nur auf eine geschrumpft...
Meine Frage ist jetzt:
Wie schnell kann ein Datenbankzugriff sein? Es muss ja ein Datenbankobjekt ins Leben rufen, die Verbindung jeweils 2mal aufgebaut und wieder beendet werden usw...! Wie schnell geht so etwas? Oder ist generell meine Vorgehensweise mit einem Timer falsch? In meinen Fall kann nicht einer den ganzen Tag am PC sitzen und immer einen Button drücken um den Messwerte einzutragen...
Gruß
Antworten
-
Ohne die Details zu kennen, würde ich erst einmal asynchrone Ereignisseverantwortlich machen, die dazu führen, dass die Datenbank gleichzeitig von2 parallelen (asynchronen) threads angesprochen wird. Versuche mal die zuspeichernden Daten in eine Queue einzureihen und die Elemente der Queue innur einem threads sequentiell abzuarbeiten.--Viele GrüßePeter
- Als Antwort markiert Robert BreitenhoferModerator Montag, 16. Mai 2011 07:44
-
Die Idee ist ganz einfach.Es gibt eine Queue in der Klasse. Die Ereignisroutine, die die Daten empfängt, ist so aufgebaut, dass sie außer der Variablen für die Queue keine weiteren außerhalb der Routine deklarierten Variablen nutzt. Damit wird die Routine parallel verwendbar. Wenn die Ereignisse sehr kurz hintereinander kommen, dann wird die Routine mehrmals parallel abgearbeitet. Die Routine baut aus jedem Ereignis ein Objekte, welches in die Queue eingereiht. Zusätzlich wird gleichzeitig ein Ereignis an die Verarbeitungsroutine gesendet.Die Verarbeitungsroutine wartet auf das Ereignis. Wenn das eintrifft, dann wird aus der Queue ein Objekt entnommen und verarbeitet. Am Ende der Verarbeitung eines Objekt wird das nächste Objekt aus der Queue entnommen und verarbeitet. Wenn die Queue leer ist, wird wieder auf das Ereignis gewartet.--Viele GrüßePeter
- Als Antwort markiert Robert BreitenhoferModerator Montag, 16. Mai 2011 07:45
-
Hallo,
Du hast generell ein Problem mit threadübergreifenden Zugriffen.
Das SerialPort.DataReceived Ereignis wird auf einem sekundären (ThreadPool) Thread aufgerufen.
Das dürfte Dir auch aufgefallen sein, denn damit sind auch direkte Zugriffe Steuerelemente tabu,
siehe Gewusst wie: Threadsicheres Aufrufen von Windows Forms-SteuerelementenDeine Lösung CheckForIllegalCrossThreadCalls einfach abzuwürgen rächt sich dann nur an anderer Stelle:
Denn Deine Funktionen wie getZustandBox1 können so parallel von zwei Threads aufgerufen werden,
einmal vom Windows Timer (der läuft auf dem UI-Thread) und noch mal via DataReceived auf einem
Hintergrundthread.
Neben den Ausnahmen kannst Du musst mit fehlerhaften Rückgaben/Setzen rechnen,
denn Deine Zustand(n) Variablen können so auch mal "lügen".
Und Datenbank-Klassen (MySqlConnection und Co.) sollte man niemals über mehrere Threads hinweg verwenden.Eine simple Lösung ohne größeren Umbau gibt es, soweit ich das bisher sehe nicht.
Denn würdest Du die Zugriffe via SyncLock kapseln, was minimal notwendig wäre,
wird Dir durch unverhersagbare Überschneidungen von Timer/DataReceived Thread
über kurz oder lang eine Blockierung oder Race Condition um die Ohren fliegen.Peter Fleischers Vorschlag ist insofern der richtige Ansatz, ohne einen größeren Umbau wird
es dabei aber nicht abgehen. (Und zuvor solltest Du Hannes Vorschlag folgen und Deinen
Code für Option Strict On tauglich machen).Ein Beispiel wie eine solche Queue aussehen kann, hatte ich mal in den VB-Newsgroups gegeben:
http://www.ms-news.net/f827/event-aus-einer-klasse-soll-auf-form-etwas-ausfuehren-9268354.html
(das dortige Terminal wäre Deinem SerialPort sehr ähnlich).Gruß Elmar
- Als Antwort markiert Robert BreitenhoferModerator Montag, 16. Mai 2011 07:45
-
Noch ein kleines Beispiel, wie Du Deinen Code besser kapselst und lesbarer machst:
'Visual Basic 2008 - .net 3.5 - Any CPU 'Zustand je nach Datenbank auslesen und zurückgeben Private Function getZustand(ByVal Databasename As String) As Integer Dim ReturnValue As Integer Try Using myConnection As New MySql.Data.MySqlClient.MySqlConnection(String.Concat(TheConnectionString, Databasename, ";")) myConnection.Open() Using mycommand As New MySql.Data.MySqlClient.MySqlCommand("SELECT zustand FROM boxzustand WHERE id=1;", myConnection) Try ReturnValue = Convert.ToInt32(mycommand.ExecuteScalar()) Catch ex As Exception Throw ex Finally myConnection.Close() End Try End Using End Using Catch ex As Exception Throw ex End Try Return ReturnValue End Function 'Box je nach Datenbank und Zustand updaten ( also ein oder ausschalten ) Private Sub UpdateBox(ByVal Databasename As String, ByVal Value As Integer) Try Using myConnection As New MySql.Data.MySqlClient.MySqlConnection(String.Concat(TheConnectionString, Databasename, ";")) myConnection.Open() Using mycommand As New MySql.Data.MySqlClient.MySqlCommand("UPDATE boxzustand SET zustand=@zustand WHERE id=1;", myConnection) mycommand.Parameters.AddWithValue("@zustand", Value) Try mycommand.ExecuteNonQuery() Catch ex As Exception Throw ex Finally myConnection.Close() End Try End Using End Using Catch ex As Exception Throw ex End Try End Sub
Noch ein paar erklärende Links:Using keyword, Finally, String.Concat()
Hannes
If you have got questions about this, just ask.
In a perfect world,
users would never enter data in the wrong form,
files they choose to open would always exist
and code would never have bugs.
C# to VB.NET: http://www.developerfusion.com/tools/convert/csharp-to-vb/
- Als Antwort markiert Robert BreitenhoferModerator Montag, 16. Mai 2011 07:45
Alle Antworten
-
Hallo _Tim,
am Besten wäre es wenn Du Deinen Code zum Auslesen und Eintragen inklusive Connect zur Datenbank einmal zeigst. Ebenso nützlich wäre es zu wissen, welche MySQL Version Du benutzt, sowohl als DB als auch als connector.
Gruß
Hannes
If you have got questions about this, just ask.
In a perfect world,
users would never enter data in the wrong form,
files they choose to open would always exist
and code would never have bugs.
C# to VB.NET: http://www.developerfusion.com/tools/convert/csharp-to-vb/ -
hier der code:
Imports System.IO.Ports.SerialPort
Imports MySql.Data.MySqlClient
Public Class Form1
'Attribute
Private MyConnectionBox1, MyConnectionBox2 As MySqlConnection
Private MyCommandBox1, MyCommandBox2 As MySqlCommand
Private eintrag As String
Private WertListBox1 As String
Private WertListBox2 As String
Private SchaltenBox1 As String
Private SchaltenBox2 As String
'SerialPort öffnen
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Try
SerialPort1.PortName = "COM6"
SerialPort1.Open()
Catch ex As Exception
lbl_FehlermeldungenAllgemein.Text = "1.Fehler: " & ex.Message
End Try
Timer1.Enabled = True
End Sub
'SerialPort Werte einlesen
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Dim in_string As String
Dim in_string2 As String
Dim in_string3 As String
Try
Control.CheckForIllegalCrossThreadCalls = False
in_string = SerialPort1.ReadLine
If (in_string.IndexOf("1", 0, 1) <> -1) Then
'ID "1" wird abgeschnitten
in_string2 = in_string.Remove(0, 1)
'.Replace(alter Wert der ersetzt wird,neuer Wert der eingetragen wird)
in_string3 = in_string2.Replace(Chr(13), Nothing)
WertListBox1 = in_string3
If (Me.getZustandBox1 = 1) Then
lst_AusgabeWerteBox1.Items.Insert(0, in_string3)
End If
End If
If (in_string.IndexOf("2", 0, 1) <> -1) Then
in_string2 = in_string.Remove(0, 1)
'.Replace(alter Wert der ersetzt wird,neuer Wert der eingetragen wird)
in_string3 = in_string2.Replace(Chr(13), Nothing)
WertListBox2 = in_string3
If (Me.getZustandBox2 = 1) Then
lst_AusgabeWerteBox2.Items.Insert(0, in_string3)
End If
End If
Catch ex As Exception
lbl_FehlermeldungenAllgemein.Text = "2.Fehler: " & ex.Message
End Try
End Sub
'Timer
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
If Me.getZustandBox1 = 1 Then
'Box1 eingeschaltet
Me.WerteInDBEintragenBox1()
lbl_StatusBox1.Text = "Status: EINGESCHALTET"
Else
'Box1 ausgeschaltet
Me.lst_AusgabeWerteBox1.Items.Clear()
lbl_FehlermeldungBox1.Text = ""
lbl_FehlermeldungenAllgemein.Text = ""
lbl_StatusBox1.Text = "Status: AUSGESCHALTET"
End If
If Me.getZustandBox2 = 1 Then
'Box2 eingeschaltet
Me.WerteInDBEintragenBox2()
lbl_StatusBox2.Text = "Status: EINGESCHALTET"
Else
'Box2 ausgeschaltet
Me.lst_AusgabeWerteBox2.Items.Clear()
lbl_FehlermeldungBox2.Text = ""
lbl_FehlermeldungenAllgemein.Text = ""
lbl_StatusBox2.Text = "Status: AUSGESCHALTET"
End If
Me.ZustandBox1Box2() 'Überwachung falls über Homepage geschaltet wird
End Sub
'Werte von BOX 1 in DB eintragen
Private Sub WerteInDBEintragenBox1()
Dim KW As Integer
Dim EffektivWert As Double
Dim Spannung As Double
Dim Leistung As Double
'DatePart gibt die KW-Woche zurück
KW = DatePart(DateInterval.WeekOfYear, Date.Today(), FirstDayOfWeek.Monday, FirstWeekOfYear.FirstFourDays)
Try
Me.MitDBVerbindenBox1()
If WertListBox1 > 0 Then
'Wert in Datenbank schreiben
EffektivWert = Convert.ToDouble(WertListBox1.Replace(".", ","))
Spannung = "230"
Leistung = EffektivWert * Spannung
'EffektivWert.ToString.Replace(",", ".")weil Mysql akzeptiert nur Punkte(z.B.12.345) und VB nur Kommas(z.B. 12,345)
MyCommandBox1 = New MySqlCommand("INSERT INTO boxwerte (strom,spannung,leistung,tag,monat,jahr,KW) VALUES ('" & _
EffektivWert.ToString.Replace(",", ".") & "','" & Spannung & "','" & Leistung.ToString.Replace(",", ".") & "','" & _
Date.Now.Day & "','" & Date.Now.Month & "','" & Date.Now.Year & "','" & KW & "');", MyConnectionBox1)
MyCommandBox1.ExecuteNonQuery()
End If
Me.DBVerbindungTrennenBox1()
Catch ex As Exception
lbl_FehlermeldungBox1.Text = "3. Fehler: " & ex.Message
End Try
End Sub
'Werte von BOX 2 in DB eintragen
Private Sub WerteInDBEintragenBox2()
Dim KW As Integer
Dim EffektivWert As Double
Dim Spannung As Double
Dim Leistung As Double
'DatePart gibt die KW-Woche zurück
KW = DatePart(DateInterval.WeekOfYear, Date.Today(), FirstDayOfWeek.Monday, FirstWeekOfYear.FirstFourDays)
Try
Me.MitDBVerbindenBox2()
If WertListBox2 > 0 Then
'Wert in Datenbank schreiben
EffektivWert = Convert.ToDouble(WertListBox2.Replace(".", ","))
Spannung = 230
Leistung = EffektivWert * Spannung
'EffektivWert.ToString.Replace(",", ".")weil Mysql akzeptiert nur Punkte(z.B.12.345) und VB nur Kommas(z.B. 12,345)
MyCommandBox2 = New MySqlCommand("INSERT INTO boxwerte (strom,spannung,leistung,tag,monat,jahr,KW) VALUES ('" & _
EffektivWert.ToString.Replace(",", ".") & "','" & Spannung & "','" & Leistung.ToString.Replace(",", ".") & "','" & _
Date.Now.Day & "','" & Date.Now.Month & "','" & Date.Now.Year & "','" & KW & "');", MyConnectionBox2)
MyCommandBox2.ExecuteNonQuery()
End If
Me.DBVerbindungTrennenBox2()
Catch ex As Exception
lbl_FehlermeldungBox2.Text = "4. Fehler: " & ex.Message
End Try
End Sub
'Datenbank Verbindung aufbauen Box1
Public Sub MitDBVerbindenBox1()
Try
MyConnectionBox1 = New MySqlConnection
MyConnectionBox1.ConnectionString = "server=127.0.0.1;" & _
"UID=root;" & _
"pwd=test;" & _
"database=Box1;"
MyConnectionBox1.Open()
Catch ex As Exception
lbl_FehlermeldungenAllgemein.Text = "5.Fehler: " & ex.Message
End Try
End Sub
'Datenbank Verbindung aufbauen Box2
Public Sub MitDBVerbindenBox2()
Try
MyConnectionBox2 = New MySqlConnection
MyConnectionBox2.ConnectionString = "server=127.0.0.1;" & _
"UID=root;" & _
"pwd=test;" & _
"database=Box2;"
MyConnectionBox2.Open()
Catch ex As Exception
lbl_FehlermeldungenAllgemein.Text = "5.Fehler: " & ex.Message
End Try
End Sub
'Datenbank Verbindung trennen
Public Sub DBVerbindungTrennenBox1()
Try
MyConnectionBox1.Close()
Catch ex As Exception
lbl_FehlermeldungenAllgemein.Text = "6.Fehler: " & ex.Message
End Try
End Sub
'Datenbank Verbindung trennen
Public Sub DBVerbindungTrennenBox2()
Try
MyConnectionBox2.Close()
Catch ex As Exception
lbl_FehlermeldungenAllgemein.Text = "6.Fehler: " & ex.Message
End Try
End Sub
'Box 1 einschalten
Private Sub bt_Box1Einschalten_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_Box1Einschalten.Click
Try
Me.MitDBVerbindenBox1()
If SerialPort1.IsOpen Then
SerialPort1.Write(ChrW(32))
End If
MyCommandBox1 = New MySqlCommand("UPDATE boxzustand SET zustand=1 WHERE id=1;", MyConnectionBox1)
'ExecuteNonQuery führt Befehl aus ohne Rückgabewert
MyCommandBox1.ExecuteNonQuery()
Me.DBVerbindungTrennenBox1()
Catch ex As Exception
lbl_FehlermeldungBox1.Text = "7. Fehler: " & ex.Message
End Try
End Sub
'Box 1 auschalten
Private Sub bt_Box1Ausschalten_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_Box1Ausschalten.Click
Try
Me.MitDBVerbindenBox1()
If SerialPort1.IsOpen Then
SerialPort1.Write(ChrW(33))
End If
MyCommandBox1 = New MySqlCommand("UPDATE boxzustand SET zustand=0 WHERE id=1;", MyConnectionBox1)
MyCommandBox1.ExecuteNonQuery()
Me.DBVerbindungTrennenBox1()
Catch ex As Exception
lbl_FehlermeldungBox1.Text = "8. Fehler: " & ex.Message
End Try
End Sub
'Box 2 einschalten
Private Sub bt_Box2Ein_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_Box2Ein.Click
Try
Me.MitDBVerbindenBox2()
If SerialPort1.IsOpen Then
SerialPort1.Write(ChrW(34))
End If
MyCommandBox2 = New MySqlCommand("UPDATE boxzustand SET zustand=1 WHERE id=1;", MyConnectionBox2)
MyCommandBox2.ExecuteNonQuery()
Me.DBVerbindungTrennenBox2()
Catch ex As Exception
lbl_FehlermeldungBox2.Text = "9. Fehler: " & ex.Message
End Try
End Sub
'Box 2 auschalten
Private Sub bt_Box2Aus_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_Box2Aus.Click
Try
Me.MitDBVerbindenBox2()
If SerialPort1.IsOpen Then
SerialPort1.Write(ChrW(35))
End If
MyCommandBox2 = New MySqlCommand("UPDATE boxzustand SET zustand=0 WHERE id=1;", MyConnectionBox2)
MyCommandBox2.ExecuteNonQuery()
Me.DBVerbindungTrennenBox2()
Catch ex As Exception
lbl_FehlermeldungBox2.Text = "10. Fehler: " & ex.Message
End Try
End Sub
'Zustand Box 1 einlesen und RadioButtons dementsprechend schalten
Private Function getZustandBox1() As Integer
Static Zustand1 As Integer
Try
Me.MitDBVerbindenBox1()
MyCommandBox1 = New MySqlCommand("SELECT zustand FROM boxzustand WHERE id=1;", MyConnectionBox1)
'ExecuteScalar führt den Befehl aus mit einem Rückgabewert
Zustand1 = System.Convert.ToInt16(MyCommandBox1.ExecuteScalar())
Me.DBVerbindungTrennenBox1()
If Zustand1 = 1 Then
Return 1
End If
Catch ex As Exception
lbl_FehlermeldungBox1.Text = "11. Fehler: " & ex.Message
End Try
Return 0
End Function
'Zustand Box 2 einlesen
Private Function getZustandBox2() As Integer
Static Zustand2 As Integer
Try
Me.MitDBVerbindenBox2()
MyCommandBox2 = New MySqlCommand("SELECT zustand FROM boxzustand WHERE id=1;", MyConnectionBox2)
'ExecuteScalar führt den Befehl aus mit einem Rückgabewert
Zustand2 = Convert.ToInt16(MyCommandBox2.ExecuteScalar())
Me.DBVerbindungTrennenBox2()
If Zustand2 = 1 Then
Return 1
End If
Catch ex As Exception
lbl_FehlermeldungBox2.Text = "12. Fehler: " & ex.Message
End Try
Return 0
End Function
'Zustände schalten mit Button von der Homepage über Datenbank
Private Sub ZustandBox1Box2()
If Me.getZustandBox1 = 1 Then
'Box 1 einschalten
If SerialPort1.IsOpen Then
SerialPort1.Write(ChrW(32))
End If
Else
'Box 1 ausschalten
If SerialPort1.IsOpen Then
SerialPort1.Write(ChrW(33))
End If
End If
If Me.getZustandBox2 = 1 Then
'Box 2 einschalten
If SerialPort1.IsOpen Then
SerialPort1.Write(ChrW(34))
End If
Else
'Box 2 ausschalten
If SerialPort1.IsOpen Then
SerialPort1.Write(ChrW(35))
End If
End If
End Sub
End ClassVerwende MySQL Server 5.0 und MySQL Connector Net 6.2.4
-
Hallo _Tim,
ich habe Deinen Thread nicht vergessen, habe aber leider meinen Rechnre mit VB gerade am updaten. Melde mich nachher nochmal. Du solltest Dir aber auf jeden Fall einmal über eine parameterisierte Datenbankabfrage nachdenken ( link: http://www.vbmysql.com/articles/vbnet-mysql-tutorials/the-vbnet-mysql-tutorial-part-4 ). Du sicherst damit Deinen Code gegen SQL injection ( link: http://de.wikipedia.org/wiki/SQL-Injection ) ab und musst Dich nicht mehr um die Kommas ('EffektivWert.ToString.Replace(",", ".")) kümmern.
Gruß
Hannes
If you have got questions about this, just ask.
In a perfect world,
users would never enter data in the wrong form,
files they choose to open would always exist
and code would never have bugs.
C# to VB.NET: http://www.developerfusion.com/tools/convert/csharp-to-vb/ -
Bin wieder da ;-)
Ich habe mir Deinen Code mal angeschaut und für mich und meine DB mal getestet, ob das Problem an der DB liegt. Ich habe in einer Schleife ( mit 500 Durchläufen ) jeweils 2 MySQLConnections geöffnet und jeweils ( pro connection ) eine SELECT Anweisung durchgeschickt in der gleichen Art wie Du, also Connection.Open(), Command.ExecuteScalar(), Connection.Close() und dabei sind keine Probleme aufgetreten. Lass Dir doch mal den Stacktrace der exception evetl. mit innerexception mit ausgeben um genau zu sehen, wo/was die Exception ausgelöst hat.
Ich habe das mit MySQL 5 und Connector 6.3.2 getestet.
Gruß
Hannes
If you have got questions about this, just ask.
In a perfect world,
users would never enter data in the wrong form,
files they choose to open would always exist
and code would never have bugs.
C# to VB.NET: http://www.developerfusion.com/tools/convert/csharp-to-vb/ -
Noch etwas, setze mal ganz oben in Deinem code Fenster Option Strict On:
Option Strict On Public Class ...
dann werden Dir noch ein paar Probleme offenbart.
Hannes
If you have got questions about this, just ask.
In a perfect world,
users would never enter data in the wrong form,
files they choose to open would always exist
and code would never have bugs.
C# to VB.NET: http://www.developerfusion.com/tools/convert/csharp-to-vb/ -
Ohne die Details zu kennen, würde ich erst einmal asynchrone Ereignisseverantwortlich machen, die dazu führen, dass die Datenbank gleichzeitig von2 parallelen (asynchronen) threads angesprochen wird. Versuche mal die zuspeichernden Daten in eine Queue einzureihen und die Elemente der Queue innur einem threads sequentiell abzuarbeiten.--Viele GrüßePeter
- Als Antwort markiert Robert BreitenhoferModerator Montag, 16. Mai 2011 07:44
-
@Peter
Danke für deinen Tipp, aber ich habe leider noch nicht die nötige Programmierkenntnisse um deinen Tipp umsetzen zu können
@Heslacher
So habe jetzt nochmal getestet mit ausgabe folgender Fehlermeldung an den Problemstellen im Programm:
z.B.
lbl_FehlermeldungBox2.Text = "13. Fehler: " & ex.Source & vbNewLine & ex.Message & "Fehlerzeit " & Now
Fehlerbericht:
Fehler: nach ca. 295 Messwerten in Function getZustandBox2
Connenction must be valid and open (ex.source=MySql.Data)
Ausnahme des Typs "System.InvalidOperationException" ist in MySql.Data.dll aufgetreten
Fehler: nach ca. 560 Messwerten in Sub WerteInDBEintragenBox1()
Connenction must be valid and open (ex.source=MySql.Data)
Ausnahme des Typs "System.InvalidOperationException" ist in MySql.Data.dll aufgetreten
Fehler: nach ca. 1092 Messwerten in Function getZustandBox1
Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt
Ausnahme des Typs "System.NullReferenceException" ist in MySql.Data.dll aufgetreten
Beendung des Tests bei ca 1300 Messwerten
Trotz Fehlermeldungen wurde weiter eingetragen und ausgelesen. Werde die Fehlermeldungen halt so hin nehmen, bis ich die Lösungen für die Fehler habe.
Werde jetzt mal testen wie es läuft wenn jetzt auch noch zusätzlich die ASP.NET homepage auf die Datenbank zugreift und die Werte ausliest, die das VB.NET Programm eingetragen hat.
Gibt es eigentlich eine zeitliche Begrenzung in bezug auf zugriffe auf eine MySql-Datenbank?? Das man sagt Verbindungsaufbau- und beenden nimmt mind. so und so viel Zeit in Anspruch.
Gruß -
Hallo Tim,
gib doch mal Deine Fehler so aus:
lbl_FehlermeldungBox2.Text = "13. Fehler: " & ex.Source & vbNewLine & ex.StackTrace & "Fehlerzeit " & Now
dann sieht man wo genau der Fehler aufgetreten ist ( in welcher Zeile ).
Hannes
If you have got questions about this, just ask.
In a perfect world,
users would never enter data in the wrong form,
files they choose to open would always exist
and code would never have bugs.
C# to VB.NET: http://www.developerfusion.com/tools/convert/csharp-to-vb/ -
ein paar Tests weiter...
13.Fehler: Fehlerquelle MySql.Data
Zeile: bei MySql.Data.MySqlClient.MySqlCommand.CheckState()
bei MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
bei MySql.Data.MySqlClient.MySqlCommand.ExecuteScalar()
bei BackEndProzess.Form1.getZustandBox2() in F:\BackEndProzess_V2\BackEndProzess\Form1.vb:Zeile 330.
INFO: Zeile 330 --> getZustandBox2 = Convert.ToInt16(MyCommandBox2.ExecuteScalar())
12.Fehler: Fehlerquelle MySql.Data
Zeile: bei MySql.Data.MySqlClient.MySqlCommand.CheckState()
bei MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
bei MySql.Data.MySqlClient.MySqlCommand.ExecuteScalar()
bei BackEndProzess.Form1.getZustandBox1() in F:\BackEndProzess_V2\BackEndProzess\Form1.vb:Zeile 311.
INFO: Zeile 311 --> getZustandBox1 = System.Convert.ToInt16(MyCommandBox1.ExecuteScalar())
6.Fehler: Fehlerquelle MySql.Data
Zeile: bei MySql.Data.MySqlClient.MySqlDataReader.Close()
bei MySql.Data.MySqlClient.MySqlConnection.Close()
bei BackEndProzess.Form1.DBVerbindungTrennenBox1() in F:\BackEndProzess_V2\BackEndProzess\Form1.vb:Zeile 210.
Fehlermeldung: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
Fehlerzeit 21.04.2011 14:03:19
INFO: Zeile 210 --> MyConnectionBox1.Close()
Das einzig positive an der Sache ist, dass die Fehler immer die gleichen sind und immmer an der gleichen Stelle auftreten...
Ist es ein problem vom Code her oder von den Datentypen??
Vielleicht sollte ich das auslesen mal mit MyCommandBox1.ExecuteReader versuche? Ist aber eigentlich nicht sinnvoll, da ich an dieser Stelle ja nur einen Wert auslesen will - nämlich den Zustand, der nur zwei Werte an nehmen kann 0 oder 1.
Gruß
-
Sehe ich es richtig, dass Du bei der Methode bt_Box1Einschalten_Click() an Deinen SerialPort ein Kommando sendest, so dass wieder Daten vom SerialPort kommen sollen ?
Hannes
If you have got questions about this, just ask.
In a perfect world,
users would never enter data in the wrong form,
files they choose to open would always exist
and code would never have bugs.
C# to VB.NET: http://www.developerfusion.com/tools/convert/csharp-to-vb/ -
Die Idee ist ganz einfach.Es gibt eine Queue in der Klasse. Die Ereignisroutine, die die Daten empfängt, ist so aufgebaut, dass sie außer der Variablen für die Queue keine weiteren außerhalb der Routine deklarierten Variablen nutzt. Damit wird die Routine parallel verwendbar. Wenn die Ereignisse sehr kurz hintereinander kommen, dann wird die Routine mehrmals parallel abgearbeitet. Die Routine baut aus jedem Ereignis ein Objekte, welches in die Queue eingereiht. Zusätzlich wird gleichzeitig ein Ereignis an die Verarbeitungsroutine gesendet.Die Verarbeitungsroutine wartet auf das Ereignis. Wenn das eintrifft, dann wird aus der Queue ein Objekt entnommen und verarbeitet. Am Ende der Verarbeitung eines Objekt wird das nächste Objekt aus der Queue entnommen und verarbeitet. Wenn die Queue leer ist, wird wieder auf das Ereignis gewartet.--Viele GrüßePeter
- Als Antwort markiert Robert BreitenhoferModerator Montag, 16. Mai 2011 07:45
-
Hallo,
Du hast generell ein Problem mit threadübergreifenden Zugriffen.
Das SerialPort.DataReceived Ereignis wird auf einem sekundären (ThreadPool) Thread aufgerufen.
Das dürfte Dir auch aufgefallen sein, denn damit sind auch direkte Zugriffe Steuerelemente tabu,
siehe Gewusst wie: Threadsicheres Aufrufen von Windows Forms-SteuerelementenDeine Lösung CheckForIllegalCrossThreadCalls einfach abzuwürgen rächt sich dann nur an anderer Stelle:
Denn Deine Funktionen wie getZustandBox1 können so parallel von zwei Threads aufgerufen werden,
einmal vom Windows Timer (der läuft auf dem UI-Thread) und noch mal via DataReceived auf einem
Hintergrundthread.
Neben den Ausnahmen kannst Du musst mit fehlerhaften Rückgaben/Setzen rechnen,
denn Deine Zustand(n) Variablen können so auch mal "lügen".
Und Datenbank-Klassen (MySqlConnection und Co.) sollte man niemals über mehrere Threads hinweg verwenden.Eine simple Lösung ohne größeren Umbau gibt es, soweit ich das bisher sehe nicht.
Denn würdest Du die Zugriffe via SyncLock kapseln, was minimal notwendig wäre,
wird Dir durch unverhersagbare Überschneidungen von Timer/DataReceived Thread
über kurz oder lang eine Blockierung oder Race Condition um die Ohren fliegen.Peter Fleischers Vorschlag ist insofern der richtige Ansatz, ohne einen größeren Umbau wird
es dabei aber nicht abgehen. (Und zuvor solltest Du Hannes Vorschlag folgen und Deinen
Code für Option Strict On tauglich machen).Ein Beispiel wie eine solche Queue aussehen kann, hatte ich mal in den VB-Newsgroups gegeben:
http://www.ms-news.net/f827/event-aus-einer-klasse-soll-auf-form-etwas-ausfuehren-9268354.html
(das dortige Terminal wäre Deinem SerialPort sehr ähnlich).Gruß Elmar
- Als Antwort markiert Robert BreitenhoferModerator Montag, 16. Mai 2011 07:45
-
Noch ein kleines Beispiel, wie Du Deinen Code besser kapselst und lesbarer machst:
'Visual Basic 2008 - .net 3.5 - Any CPU 'Zustand je nach Datenbank auslesen und zurückgeben Private Function getZustand(ByVal Databasename As String) As Integer Dim ReturnValue As Integer Try Using myConnection As New MySql.Data.MySqlClient.MySqlConnection(String.Concat(TheConnectionString, Databasename, ";")) myConnection.Open() Using mycommand As New MySql.Data.MySqlClient.MySqlCommand("SELECT zustand FROM boxzustand WHERE id=1;", myConnection) Try ReturnValue = Convert.ToInt32(mycommand.ExecuteScalar()) Catch ex As Exception Throw ex Finally myConnection.Close() End Try End Using End Using Catch ex As Exception Throw ex End Try Return ReturnValue End Function 'Box je nach Datenbank und Zustand updaten ( also ein oder ausschalten ) Private Sub UpdateBox(ByVal Databasename As String, ByVal Value As Integer) Try Using myConnection As New MySql.Data.MySqlClient.MySqlConnection(String.Concat(TheConnectionString, Databasename, ";")) myConnection.Open() Using mycommand As New MySql.Data.MySqlClient.MySqlCommand("UPDATE boxzustand SET zustand=@zustand WHERE id=1;", myConnection) mycommand.Parameters.AddWithValue("@zustand", Value) Try mycommand.ExecuteNonQuery() Catch ex As Exception Throw ex Finally myConnection.Close() End Try End Using End Using Catch ex As Exception Throw ex End Try End Sub
Noch ein paar erklärende Links:Using keyword, Finally, String.Concat()
Hannes
If you have got questions about this, just ask.
In a perfect world,
users would never enter data in the wrong form,
files they choose to open would always exist
and code would never have bugs.
C# to VB.NET: http://www.developerfusion.com/tools/convert/csharp-to-vb/
- Als Antwort markiert Robert BreitenhoferModerator Montag, 16. Mai 2011 07:45
-
Sorry für die formatierung, aber der Code Editor macht mal wieder was er will.
Hannes
If you have got questions about this, just ask.
In a perfect world,
users would never enter data in the wrong form,
files they choose to open would always exist
and code would never have bugs.
C# to VB.NET: http://www.developerfusion.com/tools/convert/csharp-to-vb/ -
Vielen dank für die Hilfe!
Werde mir das alles mal genauer anschauen und versuchen zu verstehen um es in zukunft besser zu machen :-).
Die vielen nützlichen Links werden mir dabei ja helfen... :-)
@Heslacher
Finde ich, für mich als Anfänger, sehr sehr hilfreich, dass du auch mal code mit einbringst. Das hilft ungemein zu den zusätzlichen Links!
Gruß