在使用 SqlBulkCopy 的 class 上实施 Dispose

Implementing Dispose on a class that uses SqlBulkCopy

我有一个记录 API 调用的 c# 网站,它将日志作为单行插入到 SQL 服务器数据库中。当站点变得非常繁忙时,这就是夹点,日志 table 锁定,我们看到等待连接到数据库的超时。我正在尝试使用 SqlBulkCopy 来解决这个问题。原来的日志方法被替换为新的 BulkLogger class 并且当包含日志的 DataTable 达到限制(目前为 100)时调用 Flush() 方法并记录日志全部写入数据库。

原始日志方法是从所有代码中调用的,它是没有 DI 的旧代码,所以我必须在几个地方创建 new BulkLogger。我担心某些日志不会被写入,因为异常没有得到很好的处理并且 BulkLogger 可能会丢失,或者如果某些日志仍在内存中等待被批量复制,则只是在页面请求完成时写入。

我的BulkLoggerclass可以封印了,我没有任何资源可以清理或处置。因此,如果 BulkLogger 实现了 IDisposable 而我如下实现了 Dispose,这是否意味着在大多数情况下所有日志都写入了数据库?

public sealed class BulkLogger : IDisposable
{
    DataSet _logSet;
    DataTable _logTable;

    public BulkLogger() {
        // set up the dataset and datatable 
    }

    public void Log(string message, DateTime logTime) {
        // add message and time to _logTable
        // if _logTable.count > 100 call Flush()
    }

    public void Flush() {
        // Use SqlBulkCopy to insert logs
    }

    public void Dispose()
    {
        Flush();
    }
}

使用 SQLBulkCopy 之类的东西只允许您根据 MSDN 文档 (https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlbulkcopy?view=netframework-4.8) 将大量数据插入 db/table。因此,采用这种方法很可能意味着您首先必须将要记录到数据库的调用存储在内存中,一旦它们达到某个阈值,就将它们写入数据库。

我也不认为这是一个很好的方法,因为您很可能会看到所用资源的增加。

考虑创建一个单独的线程来将您的日志行写入数据库。 不需要更改任何代码,只需从将自己的连接实例实例化到 DB 的线程进行调用即可。

Thread t1 = new Thread(()=>{
SQLConnection con = new SQLConnection("yourConnection");
SqlCommand command = new SqlCommand("INSERT INTO LOG TABLE", con );
command.ExecuteNonQuery();
});
t1.Start();

查看如何创建线程:https://docs.microsoft.com/en-us/dotnet/api/system.threading.thread.start?view=netframework-4.8

这是另一个 link,其中包含一个关于如何实现数据库日志记录的示例项目。 https://code.msdn.microsoft.com/How-to-implement-logging-4cbcfc64

如果您用太多线程关闭任务使数据库不堪重负而无法插入数据库,那么您可能需要缩小直接管道到数据库的范围。不要启动线程来执行插入,而是使用 1 个线程或线程池来消耗请求以插入到数据库中。您可以使用 ConcurrentQueue<T> 在主应用程序线程上对请求进行排队(生产者),同时专用线程监视此队列并使用请求。这样,插入将被同步处理,而不是对所有人免费。

这是一个 link 到 Producer/Consumer 的例子:

https://docs.microsoft.com/en-us/dotnet/standard/collections/thread-safe/blockingcollection-overview?redirectedfrom=MSDN

C# producer/consumer