【问题标题】:PostgreSQL: command is already in progressPostgreSQL:命令已经在进行中
【发布时间】:2019-04-05 07:22:15
【问题描述】:

我的异步函数尝试从表中选择一条记录。这个函数接受一些从另一个函数传递过来的参数。

因此,某些进程(至少 6 个)可以同时使用它。我经常收到错误消息“命令已在进行中”

我知道问题隐藏在阅读器中,因为阅读器正忙于另一个进程试图访问它。

让我在下面发布完整的代码:

async private void InsertToLog(List<Printer> APrinter, List<PrinterToGridBinds> AGridBind, int index)
        {
            if (!String.IsNullOrEmpty(APrinter[index].Type.Trim()) && !String.IsNullOrEmpty(AGridBind[index].extBatchNumber.Trim()) && !String.IsNullOrEmpty(AGridBind[index].extBatchCounter.Trim()) && !String.IsNullOrEmpty(AGridBind[index].extDIOCounter.Trim()))
            {
                string dio_count = "0";
                string GetDIOCounter = string.Format(@"SELECT dio_counter FROM {0} WHERE device_type = '{1}' AND batch_number = '{2}' ORDER BY id DESC
  LIMIT 1;", log_table_name, lst_PrinterStruct[index].Type, AGridBind[index].extBatchNumber);

                try
                {
                    NpgsqlCommand db_getCounter = new NpgsqlCommand(GetDIOCounter, conn);
                    if (conn.State != ConnectionState.Open)
                        conn.Open();
                    using (DbDataReader reader = await db_getCounter.ExecuteReaderAsync())
                    {
                        while (await reader.ReadAsync())
                            dio_count = reader[0].ToString().Trim();
                    }

                    AGridBind[index].extDIOCounter = (Int32.Parse(dio_count) + Int32.Parse(AGridBind[index].extDIOCounter.Trim())).ToString();
                    string Insert_SQL = String.Format(@"INSERT INTO {0} (device_type, batch_number, start_date, batch_counter, dio_counter) VALUES ('{1}', '{2}', '{3}', '{4}', '{5}') ON CONFLICT ON CONSTRAINT unique_log_key DO UPDATE SET batch_counter='{4}', dio_counter='{5}';", log_table_name, APrinter[index].Type.Trim(),
               AGridBind[index].extBatchNumber.Trim(), DateTime.Now.ToString(), AGridBind[index].extBatchCounter.Trim(), AGridBind[index].extDIOCounter.Trim());

                    var db_cmd = new NpgsqlCommand(Insert_SQL, conn);
                    int res = await db_cmd.ExecuteNonQueryAsync();
                }
                catch (Exception e)
                {
                    string FMessage = String.Format("Printer {0} \r\n Can not write to table\r\n Error: {1}",
                        lst_PrinterStruct[index].Name, e.Message);
                    MessageBox.Show(FMessage);
                }

                finally
                {
                    conn.Close();
                }
            }
        }

如你所见,阅读器在这里被using包裹。

无论如何,我有我所拥有的(一个错误)。那么,我的问题是如何避免此错误消息(我是关于“命令已在进行中”)?

我对可能的决定有一些想法。也许:

  1. DbDataReader 设置为参数。并且读者的名字可以通过Random函数生成。但我不知道该怎么做。

  2. 等到当前进程完成并关闭阅读器,然后运行第二个等。但我不知道如何告诉新进程等到前一个进程完成。

    李>

所以,我需要你们的帮助,伙计们。

【问题讨论】:

  • 作为一个附带问题,我建议阅读 SQL 注入。
  • 要考虑的一个选项可能是为每个命令声明和实例化一个单独的连接。
  • 分离连接是个好主意。但在这种情况下,我没有得到优化的代码。执行相同操作的许多功能。我想要更优雅的决定。无论如何,谢谢!
  • 应用程序是实时应用程序,每秒向数据库写入数次数据。并用很少的过程做到这一点。每个进程每秒打开和关闭连接......我想,如果我在启动应用程序时打开连接一次并在应用程序关闭时关闭它会更好。不幸的是,我是 PostgreSQL 的新手。所以,我对经常打开/关闭连接的性能一无所知。
  • 我已经做到了。我是关于你的建议。

标签: c# database postgresql async-await npgsql


【解决方案1】:

如果多个线程共享一个数据库连接,您必须同步它们,以便它们中只有一个同时使用该连接。在 PostgreSQL 数据库会话中一次只能运行一条语句。

由于同步很麻烦并且可能会损害您的并发性,因此您最好使用连接池,并且每个线程都在需要时从池中请求一个连接。

【讨论】:

    【解决方案2】:

    在将OleDB 程序迁移到PNGSQL 时,我在VB.Net 中遇到了同样的问题。

    我的程序只执行了一个循环来读取由简单的SQL SELECT 返回的一些记录。

    '*******************************************************************
    '* SelectMouvements()
    '*******************************************************************
    
    Private Function SelectMouvements() As Integer
    
        SQL = _
    <sql-select>
    
    SELECT *
      FROM mouvements
      INNER JOIN comptes
        ON comptes.no_compte = mouvements.personnal_account
      LEFT OUTER JOIN cartes
        ON cartes.no_carte = mouvements.no_carte
            
    </sql-select>
    
        Dim cmd As New NpgsqlCommand(SQL, cn)
        Dim dr As NpgsqlDataReader
    
        dr = cmd.ExecuteReader()
        While dr.Read()
            grid.Rows.Add()
            With grid.Rows(iRow)
                .Cells(0).Value = dr("communication")
            ... 
            End With
            call NormalizeSomeFields(dr("name"))
        End While
    End Sub
    

    使用OleDb 时我的代码不存在的问题是NormalizeSomeFields() 函数正在打开第二个DataReader

    Private Sub NormalizeSomeFields(ByRef sNom as String)
    
        SQL = 
    <sql-select>
    
    SELECT NewNom
      FROM aliasnom
      WHERE Nom = <%= AddQuote(sNom) %>
    
    <sql-select>
    
        Dim cmdNom As New NpgSqlCOmmand(SQL, cn)
        Dim drNom As NpgsqlDataReader
    
        drNom = cmdNom.ExecuteReader()
        If drNom.Read() Then
            sNom = drNom(0)
        End If
        drNom.Close()
    End Sub
    

    此程序在cmdNom.ExecuteReader() 行返回NpgsqlOperationInProgresException


    解决方案


    为了解决这个问题,我在定义 cn 连接的代码之后定义了另一个名为 cn2NpgsqlConnection,如下几行所示

        cn = New NpgsqlConnection(cs)
        Try
            cn.Open()
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    
        cn2 = New NpgsqlConnection(cs)
        Try
            cn2.Open()
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    

    我现在在定义第二个 DataReader 时使用它

        Dim cmdNom As New NpgSqlCOmmand(SQL, cn2)
    

    NPGSQL 似乎拒绝多个集合...但接受多个连接!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-17
      • 2020-07-18
      • 1970-01-01
      • 1970-01-01
      • 2011-05-31
      • 2012-08-31
      • 1970-01-01
      • 2023-03-28
      相关资源
      最近更新 更多