none
VB2008以多緒方式執行資料庫查詢的疑問 RRS feed

  • 問題

  • 各位大大!小弟在使用VB2008建構一個程式!結構如下
    FORM1:執行PLC即時監控!並記錄訊息
    可由FORM1呼叫FORM2
    FORM2:資料庫查詢
    FORM1 中PLC的即時監控方式為:
    在FORM1_LOAD中執行
     ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf PLCtest), myResetEvent)

     Private Sub PLCtest()
          執行PLC連線指令
    End Sub
    收集PLC資料
    Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
            RXD = ""
            Dim i As Integer = 0
            Try
                While Microsoft.VisualBasic.Right(RXD, 1) <> Chr(13)
                    System.Threading.Thread.Sleep(50)
                    RXD &= SerialPort1.ReadExisting
                    i += 1
                    If i > 2 Then
                        Exit While
                    End If
                End While
                If i <= 2 Then
                    RXDtranfer(RXD)
                End If
            Catch ex As Exception
            Finally
                Application.DoEvents()
                AddHandler SerialPort1.DataReceived, AddressOf SerialPort1_DataReceived
                bIsChanged = True
                System.Threading.Thread.Sleep(50)
                myResetEvent.Set()
            End Try
        End Sub
    Public Sub RXDtranfer(ByVal P As String)   '判斷字元長度顯示
            Dim strLen As Integer = Len(P)
            Select Case Len(P)
                Case 15
                    If Mid(P, 8, 4) <> "0000" Then
                        Panel2.BackColor = Color.Red
                    Else
                        Panel2.BackColor = Color.Green
                    End If
                    Label1.Text = P
                    ChooseThreads(1) '執行緒1 將回傳資料經過運算顯示在FORM1的控制項上
                Case 35
                    ChooseThreads(2) '執行緒2 記錄資料
               Case Else
             End Select
        End Sub

    FORM2 中的語法

        Public Sub ChooseThreads(ByVal threadNumber As Integer)
            Select Case threadNumber
                Case 1
                    Me.BeginInvoke(New FactorialThread(AddressOf work1), New Object)
                Case 2
                    FactorialThread11 = New System.Threading.Thread(AddressOf work2)
                    FactorialThread11.Start()
            End Select
        End Sub
      Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            ChooseThreads(1)
       End Sub
    Private Sub work1()

            Dim Sql As String
            Dim SqlConn As New OleDbConnection()

            SqlConn.ConnectionString() = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\PLCALM.mdb;User ID=Admin;Password=;"
            SqlConn.Open()
            Sql = ("select * from REPORT1 where S_SDAY BETWEEN #" & Format(DateTimePicker1.Value, "yyyy/M/d") & "# AND  #" & Format(DateTimePicker2.Value, "yyyy/M/d") & "# ")
            Dim OleDbda As New OleDbDataAdapter()
            OleDbda = New OleDbDataAdapter(Sql, SqlConn)
            Dim ds As DataSet                 '宣告ds 為DataSet物件
            ds = New DataSet()                '初始化ds物件
            OleDbda.Fill(ds, "PLCALM")
            DataGridView1.DataSource = ds.Tables("PLCALM")

            ds = Nothing

            With DataGridView1
                .Columns(0).Name = "NO."
                .Columns(1).Name = "日期"
                .Columns(2).Name = "發生時間"
                .Columns(3).Name = "異常訊息"
                .Columns(4).Name = "復歸時間"
                .Columns(5).Name = "使用者"
                .Columns(0).SortMode = DataGridViewColumnSortMode.NotSortable
                .Columns(1).SortMode = DataGridViewColumnSortMode.NotSortable
                .Columns(2).SortMode = DataGridViewColumnSortMode.NotSortable
                .Columns(3).SortMode = DataGridViewColumnSortMode.NotSortable
                .Columns(4).SortMode = DataGridViewColumnSortMode.NotSortable
                .Columns(5).SortMode = DataGridViewColumnSortMode.NotSortable
                .Columns("NO.").DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
                .Columns("日期").DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
                .Columns("發生時間").DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
                .Columns("異常訊息").DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft
                .Columns("復歸時間").DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
                .Columns("使用者").DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft
                .Columns("NO.").HeaderText = "NO."
                .Columns("日期").HeaderText = "日期"
                .Columns("發生時間").HeaderText = "發生時間"
                .Columns("異常訊息").HeaderText = "異常訊息"
                .Columns("復歸時間").HeaderText = "復歸時間"
                .Columns("使用者").HeaderText = "使用者"
            End With
      SqlConn.Close()
            Dim Lots As Integer = DataGridView1.RowCount
            Label1.Text = " 查詢筆數:  " & Lots
    End Sub

    目前遇到的問題是:
    1.當FORM2做查詢動作時,FORM1中的控制項顯示狀態就會停止更新,利用中斷來檢視執行緒是一直在運作並未中斷,是否在多執行緒的用法下小弟應用錯誤
    2.資料庫查詢時間相當的長!如回傳1000筆資料耗時約20Sec,是否有其他改善的方法

    以上,如有其他資訊小弟說的不清楚的請見諒!避免文章版面過長,小弟就只PO部分
    請各位大大!不吝指教


    新手上路
    2009年7月9日 上午 07:41

解答

  • eblue:
     1. 在SerialPort1_DataReceived中,你沒有先做RomveHandler 又 AddHandeler ?
     2.   Sql = ("select * from REPORT1 where S_SDAY BETWEEN #" & Format(DateTimePicker1.Value, "yyyy/M/d") & "# AND  #" & Format(DateTimePicker2.Value, "yyyy/M/d") & "# ") , 這種Sql Statement最好改成用 dbParameter的方式來加入參數
    3. 你的DataGridView1的那些設定, 可以放在Form Load中, 否則每執行一次work1 , 它就得來一次
    4. 你在作查詢的時候Form1會停止反應,是不是因為Form1在做更新 畫面時也會去讀Access Table ?

    請關心自己的問題,不要問了就放空;這是對別人與自己的尊重

    HI~~BILL大大很久不見囉!!
    這程式就是上次那個寫1半的!繼續改..所以有沒很眼熟啊!!呵
    依據大大的提示:
    1.RomveHandler這個步驟~~小弟不知怎麼做耶/正在看MSDN
    2.利用dbParameter的方式來加入參數來寫!我有看過大大回復其他人的問題唷!我會導入的
    3.謝謝大大提醒
    4.更新畫面時不會去讀ACCESS TABLE 但會有寫入的動作 讀取&寫入是同一個資料庫檔案

    新手上路
    • 已標示為解答 eblue 2009年7月14日 上午 02:50
    2009年7月9日 上午 08:43

所有回覆

  • eblue:
     1. 在SerialPort1_DataReceived中,你沒有先做RomveHandler 又 AddHandeler ?
     2.   Sql = ("select * from REPORT1 where S_SDAY BETWEEN #" & Format(DateTimePicker1.Value, "yyyy/M/d") & "# AND  #" & Format(DateTimePicker2.Value, "yyyy/M/d") & "# ") , 這種Sql Statement最好改成用 dbParameter的方式來加入參數
    3. 你的DataGridView1的那些設定, 可以放在Form Load中, 否則每執行一次work1 , 它就得來一次
    4. 你在作查詢的時候Form1會停止反應,是不是因為Form1在做更新 畫面時也會去讀Access Table ?

    請關心自己的問題,不要問了就放空;這是對別人與自己的尊重
    • 已提議為解答 vitoshao 2009年7月10日 上午 03:57
    2009年7月9日 上午 08:06
    版主
  • eblue:
     1. 在SerialPort1_DataReceived中,你沒有先做RomveHandler 又 AddHandeler ?
     2.   Sql = ("select * from REPORT1 where S_SDAY BETWEEN #" & Format(DateTimePicker1.Value, "yyyy/M/d") & "# AND  #" & Format(DateTimePicker2.Value, "yyyy/M/d") & "# ") , 這種Sql Statement最好改成用 dbParameter的方式來加入參數
    3. 你的DataGridView1的那些設定, 可以放在Form Load中, 否則每執行一次work1 , 它就得來一次
    4. 你在作查詢的時候Form1會停止反應,是不是因為Form1在做更新 畫面時也會去讀Access Table ?

    請關心自己的問題,不要問了就放空;這是對別人與自己的尊重

    HI~~BILL大大很久不見囉!!
    這程式就是上次那個寫1半的!繼續改..所以有沒很眼熟啊!!呵
    依據大大的提示:
    1.RomveHandler這個步驟~~小弟不知怎麼做耶/正在看MSDN
    2.利用dbParameter的方式來加入參數來寫!我有看過大大回復其他人的問題唷!我會導入的
    3.謝謝大大提醒
    4.更新畫面時不會去讀ACCESS TABLE 但會有寫入的動作 讀取&寫入是同一個資料庫檔案

    新手上路
    • 已標示為解答 eblue 2009年7月14日 上午 02:50
    2009年7月9日 上午 08:43
  • 4.更新畫面時不會去讀ACCESS TABLE 但會有寫入的動作 讀取&寫入是同一個資料庫檔案
          我猜啦,也許是因為在等待寫入, 所以卡住不更新畫面.你可以在抓取RS232資料後讓它拆成兩個Thread , 一個去更新畫面,一個去更新資料庫.
      
    請關心自己的問題,不要問了就放空;這是對別人與自己的尊重
    2009年7月9日 上午 08:48
    版主
  • 4.更新畫面時不會去讀ACCESS TABLE 但會有寫入的動作 讀取&寫入是同一個資料庫檔案
          我猜啦,也許是因為在等待寫入, 所以卡住不更新畫面.你可以在抓取RS232資料後讓它拆成兩個Thread , 一個去更新畫面,一個去更新資料庫.
      
    請關心自己的問題,不要問了就放空;這是對別人與自己的尊重

    若我用執行緒A去讀ALM資料庫,B執行緒去寫ALM資料庫,同時執行時   mycom.ExecuteNonQuery() 會出現被鎖定的訊息! 看來要找方法解決並行違規了!

    新手上路
    2009年7月9日 上午 10:37
  • bill 大大:
    關於RemoveHandler ..我看不懂他在說什麼?能教我一下嗎?
    新手上路
    2009年7月10日 上午 08:19
  • bill 大大:
    關於RemoveHandler ..我看不懂他在說什麼?能教我一下嗎?
    新手上路

    我終於看懂方式了..我將RemovHandler放在這
    Try
                While Microsoft.VisualBasic.Right(RXD, 1) <> Chr(13)
                    System.Threading.Thread.Sleep(50)
                    RXD &= SerialPort1.ReadExisting
                    i += 1
                    If i > 2 Then
                        Exit While
                    End If
                End While
                If i <= 2 Then
                    RXDtranfer(RXD)
                End If
                RemoveHandler SerialPort1.DataReceived, AddressOf SerialPort1_DataReceived
            Catch ex As Exception
    新手上路
    2009年7月10日 上午 11:17
  • 你應該把它放在 Data_Received的第一行

    請關心自己的問題,不要問了就放空;這是對別人與自己的尊重
    2009年7月10日 下午 03:57
    版主
  • 感謝大大的建議.
    關於資料庫的部份由於我是利用ACCESS所產生的資料庫,是否因為ACCESS本來就是不適合多人存取!所以才會造成目前遇到的狀況!
    請問有辦法克服嗎??

    新手上路
    2009年7月13日 上午 01:34
  • 如果你的 threading 有寫入動作,若一定要用 Access,則要考慮使用 Queue 來做。
    Access 有一個天生的限制,就是寫入動作無法並行,同一時間內只能有一個寫入動作。
    小人物一枚。
    2009年7月13日 上午 02:13
    版主
  • 如果你的 threading 有寫入動作,若一定要用 Access,則要考慮使用 Queue 來做。
    Access 有一個天生的限制,就是寫入動作無法並行,同一時間內只能有一個寫入動作。
    小人物一枚。

    感謝小朱大大的回覆..
    但小弟目前是這麼做..一個執行緒試寫入..一個執行緒是讀出
    這樣也無法同時並行嗎?
    新手上路
    2009年7月13日 上午 02:54
  • 那就要看你讀寫的程度了...
    Access 最大的同時讀取是 255 個,最大同時寫入為 1 個,而且寫入時間如果太長的話本來就會造成鎖定。
    小人物一枚。
    2009年7月13日 上午 03:37
    版主
  • 那就要看你讀寫的程度了...
    Access 最大的同時讀取是 255 個,最大同時寫入為 1 個,而且寫入時間如果太長的話本來就會造成鎖定。
    小人物一枚。

    小弟在知識家有大大建議使用SQL Express 2008 來做!看來這樣就不用在ACCESS中兜圈子了!感謝各位大大的幫忙
    新手上路
    2009年7月14日 上午 02:49