【问题标题】:How to send SQL query only once and protect for duplicates with Worker service如何仅发送一次 SQL 查询并使用 Worker 服务保护重复项
【发布时间】:2022-01-05 11:11:01
【问题描述】:

我在windows中创建了一个服务Worker服务,它定期连接到数据库并将表中的第一个最新行发送到API

但是如何让服务只发送同一行一次,然后等到下一个新的出现。

ID不能有相同的值,是否可以在已经发送的行!=dbResult[0]dbResult[0](id)可以发送时创建条件?

我的部分代码:

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
     while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                string connectionString = "User=SYSDBA;" +
                                          "Password=masterkey;" +
                                          "Database=test.DTB;" +
                                          "DataSource=localhost;" +
                                          "Port:3050";

                FbConnection mConnection = new FbConnection(connectionString);
                mConnection.Open();

                FbTransaction mTransaction = mConnection.BeginTransaction();

                string SQLCommandText = "select first 1 * from TABLE where NAME = 449 order by DATE desc ";

                FbCommand mCommand = new FbCommand(SQLCommandText, mConnection, mTransaction);

                FbDataReader mReader = mCommand.ExecuteReader();

                if (mReader.Read())
                {
                    var values = new object[mReader.FieldCount];
                    {
                        mReader.GetValues(values);
                        var dbResult = values.Distinct().ToArray();
                        var dbResults = (string.Join("|", dbResult));

                        var result = new
                        {
                            ID = dbResult[0],
                            NAME = dbResult[1],
                            DATE = dbResult[2],
                        };

                        var jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(result);

                    }
                }


            }
            catch (Exception ex)
            {
                Log.Fatal(ex, "Problem reading the database.");
            }

            await Task.Delay(10000, stoppingToken);
        }
    }
}

在得到 Barr J

的好线索后更新
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
     while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                string connectionString = "User=SYSDBA;" +
                                          "Password=masterkey;" +
                                          "Database=test.DTB;" +
                                          "DataSource=localhost;" +
                                          "Port:3050";

                FbConnection mConnection = new FbConnection(connectionString);
                mConnection.Open();

                FbTransaction mTransaction = mConnection.BeginTransaction();

                string SQLCommandText = "select NAME, DATE from TABLE where NAME = 449 and ISSENT = 0";

                FbCommand mCommand = new FbCommand(SQLCommandText, mConnection, mTransaction);

                FbDataReader mReader = mCommand.ExecuteReader();

                while (mReader.Read())
                {
                    var values = new object[mReader.FieldCount];
                    {
                        mReader.GetValues(values);
                        var dbResult = values.Distinct().ToArray();
                        var dbResults = (string.Join("|", dbResult));

                        var result = new
                        {
                            ID = dbResult[0],
                            NAME = dbResult[1],
                            DATE = dbResult[2],
                        };

                        var jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(result);

                        using FbConnection UpdateConnection = new(connectionString);

                        UpdateConnection.Open();

                        FbCommand writeCommand = new("update TABLE set ISSENT = @isSentValue where ID= @idValue", UpdateConnection);
                        writeCommand.Parameters.Add("@isSentValue", 1);
                        writeCommand.Parameters.Add("@idValue", dbResult[0]);
                        writeCommand.ExecuteNonQuery();

                    }
                }


            }
            catch (Exception ex)
            {
                Log.Fatal(ex, "Problem reading the database.");
            }

            await Task.Delay(10000, stoppingToken);
        }
    }
}

【问题讨论】:

  • 你可以记住类字段中的最新id,并在选择中添加id>latestId条件。
  • 插入新记录时为什么不运行任务?
  • 您是否打算向 API 发送任何新行?如果您只发送第一个新行,它可能会丢失一些数据。如果同时添加了 5 个新行会怎样?显然我不完全理解您的项目,但我建议在表中添加一个字段,作为一个标志,如果它已发送到 API,您可以将其设置为 true。当然,您不能使用 SELECT 语句更改标志,但您可能需要一个简单的存储过程来更新标志并同时为您提供数据。
  • 有没有教程如何记住类字段中的最新ID?我认为这是实现我的目标的好方法。当最新的 id 被记住时,不需要只发送第一行。
  • 由于您的代码每 10 秒运行一次,表中可能已插入大量新记录,您需要同步所有这些行[通过调用 API],因此在类级别您可以维护成员 Dictionary<int,int> prevIDset ,那么您可以检查当前获得的 ID 与先前运行的存在,并且只发送那些新的,并清除该 prevIDset,用本次运行中发送的新 ID 填充它们。

标签: c# sql database service-worker


【解决方案1】:

因为您正在使用工作程序并运行异步操作,所以我不建议混合会使已经很麻烦的调试过程复杂化的条件。

我会在您的表中添加一个列作为位并将其用作名为 IsSent 的标志列

然后您的查询将如下所示:

select...... where name = X and IsSent = Y ...."

这样您将只获得未发送的行。 否则,您可以查询代码中的行并检查 ID 是否已发送。

更干净、更好、更容易。

使您的代码可维护。

【讨论】:

  • 听起来很完美,我创建了专栏,我还有一个问题,如何更新标志 isSent ?首先做select ...update ... 同一行之后?我的意思是添加例如列 ```` isSent```` 变量Y
  • 是的,如果没有发送则更新
【解决方案2】:

我建议通过缓存您的新数据,在您的工作服务上实现MemCache 或简单的内存缓存。整个或只是关键标识符字段值。然后,您可以在下次查询 Id > CachedId 或 Id != CachedId order by desc 的 Db 时传递该值。

在任何时候,当您检索数据时,您都会使用该 ID 缓存它/更新您的缓存。

这些是供您了解的一些示例/参考资料

https://qawithexperts.com/article/c-sharp/in-memory-cache-c-explanation-with-example/302

【讨论】:

    猜你喜欢
    • 2018-04-13
    • 2016-03-15
    • 2022-06-11
    • 1970-01-01
    • 2016-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多