如何在c#中正确连接和查询SQL Server异步

时间:2018-06-14 21:08:54

标签: c# sql-server database

作为具有PHP背景的开发人员我总是在两个独立的函数中将连接分离到DB和Query。逻辑是为什么我应该调用Connect();每次我想查询到DB?这不是很贵吗?

现在我正在开发一个使用C#和SQL Server 2016的项目,并遇到了以下sample from MSDN

我注意到他们在一个方法中同时进行连接和查询。这对我来说很奇怪,因为我说我是一名PHP开发人员,所以有几个问题:

  1. 即使该方法是异步的,每次我需要查询某些内容时都不会调用,因为它调用了SqlConnection.OpenAsync();
  2. 为什么他们完成后才关闭连接?
  3. 在C#中分离数据库连接和查询是一个好习惯吗?如果是这样,你会如何建议我这样做?如果没有,为什么,以及连接和管理数据库的有效方法是什么?
  4. 以下是我尝试分离连接和查询的尝试(未经测试):

    private SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
    private Task<SqlConnection> connection;
    
    private async Task<SqlConnection> ConnectDB()
    {
        // Build connection string
        builder.DataSource = "localhost";
        builder.UserID = "user";
        builder.Password = "pass";
        builder.InitialCatalog = "test";
    
        // Connect to SQL
        SqlConnection connection = new SqlConnection(builder.ConnectionString);
        await connection.OpenAsync();
        return connection;
    }
    
    private async void Query(string cmd)
    {
        if (cmd == string.Empty || cmd == null)
        {
            throw new ArgumentException("Query string is empty or null.");
        }
    
        SqlCommand command = new SqlCommand(cmd, connection.Result);
        await command.ExecuteNonQueryAsync();
    }
    
    // Main Form Constructor
    public MainForm()
    {
        connection = ConnectDB();
    }
    
    // Example usage?
    private void GetAll()
    {
        Query("SELECT * FROM `test`");
    }
    

2 个答案:

答案 0 :(得分:1)

1)仅针对你的第一个问题。 ADO.NET保留了一个连接池,因此只要连接字符串没有变化,打开新连接的性能就不会那么差。

ADO.NET Connection Pooling

2)阅读完样本后,使用“using”关键字作为using语句。当以这种方式使用时,包含在using关键字中的对象一旦超出范围就将被处理(关闭)。注意,using关键字在C#中有两个用途。它们现在都在下面链接,只是注意到你对第二个链接感兴趣。

C# Using Directive

C# Using Statement

3)我更喜欢将连接和查询保持在一起。我认为这被认为是最佳做法。我不一定会说这是不好的做法,但我个人会避免它。

保持数据库连接打开更长时间然后它需要活着的原因令人不悦。

假设您有一个具有SqlConnection,SqlCommand和SqlDataReader属性/字段实例的类。如果出于某种原因需要在另一个命令已经运行时触发命令,则必须打开一个新的SqlDataReader来执行另一个查询,因为底层类组件不能同时处理多个查询。这里唯一真正的问题是SqlDataReader。理论上你可以通过在需要时创建该类型的实例并在类中保留一个SqlCommand和SqlConnection实例来解决这个问题,但我建议来做到这一点。

最后,如果你保留了类范围的实例,你的类需要实现IDisposable并处理所有这些对象。然而,如果在每种方法中都适当地处理了所有对象,则没有必要。

只是更容易避免在类中保留这些类型的属性/字段实例。

(对不起,我开始说#3很差)

答案 1 :(得分:0)

1)如上所述,.NET保留了一个连接池,并将重新使用幕后连接,以减少每次重新连接到数据库的开销。 Connection Pooling

2)在示例代码中,当代码退出using块时,将在连接对象上调用Dispose,它会自动关闭它。有关详细信息,请参阅this问题。

3)就个人而言,我更喜欢将连接和查询保持在一起;将它们分开几乎没有性能优势,并且当你完成连接时,更难以确保连接关闭并妥善处理。