首页 > 解决方案 > SQL Server 连接在数百次循环后冻结

问题描述

在 C#.NET Core 5 项目中,我使用System.Data.SQLClient4.8.2 连接到 SQL Server 11。

这段代码工作正常。

    public List<Contract> ReadDBView(Contract contract)
    {
        List<Contract> contracts = new List<Contract> { };
        try
        {
            SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();

            builder.DataSource = "server01";
            builder.UserID = "user1";
            builder.Password = "SecretPassword";
            builder.InitialCatalog = "archiv1";
            String sql = "SELECT name, group_name, group_country_code, FROM[dbo].[GROUPS] where number like '%" + contract.Number.ToString() + "'";

            using (SqlConnection connection = new SqlConnection(builder.ConnectionString))
            {
                connection.Open();
                using (SqlCommand command = new SqlCommand(sql, connection))
                {
                    using (SqlDataReader reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            contract.DealerName = reader["name"].ToString();
                            contract.GroupName = reader["group_name"].ToString();
                            contract.Country = reader["group_country_code"].ToString();
                            contracts.Add(contract);
                        }
                    }
                }
                connection.Close();
            }
        }
        catch (SqlException e)
        {
            Console.WriteLine(e.ToString());
        }

        return contracts;
    }

但是过了一会儿它就冻结了——知道如何防止冻结吗?

返回值有时为空。由于我很长时间没有使用 C# 对代码进行任何提示,因此非常感谢。

标签: c#sql-server.net-core

解决方案


考虑返回一个命名的 ValueTuple

下面的示例使用了一个与您的表不匹配的现有表,但演示了一种确定是否有异常抛出的方法。使用 Console.WriteLine 可以很好地进行调试(最好使用 Debug.WriteLine),但为什么不设置用于生产。

  • 考虑按照@jeroen Mostert 推荐的方式添加日志记录
  • 对于类似的情况,表没有设置索引,因此效率不高。关键是要弄清楚是否抛出了异常。
  • 使用 C#9、.NET Core 5 语法,例如using声明而不是语句体。

后端代码

public class SqlOperations
{
    public static string ConnectionString =
        "Data Source=.\\SQLEXPRESS;Initial Catalog=PaginationExample;Integrated Security=True";


    public static (List<Contract>, Exception exception) ReadDBView(string firstNameValue)
    {
        List<Contract> contracts = new();

        var selectStatement = 
            "SELECT Id, FirstName, LastName, Balance " + 
            "FROM dbo.LotsOfData " + 
            "WHERE FirstName LIKE @FirstNameLike;";

        try
        {
            using var cn = new SqlConnection() { ConnectionString = ConnectionString };
            using var cmd = new SqlCommand() { Connection = cn, CommandText = selectStatement };

            cmd.Parameters.Add("@FirstNameLike", SqlDbType.NVarChar).Value = firstNameValue;
            
            cn.Open();

            var reader = cmd.ExecuteReader();

            if (!reader.HasRows) return (contracts, null);
            while (reader.Read())
            {
                contracts.Add(new Contract()
                {
                    Id = reader.GetInt32(0),
                    FirstName = reader.GetString(1),
                    LastName = reader.GetString(2),
                        
                    Balance = reader.IsDBNull("Balance") ? 
                        (decimal?)null : 
                        reader.GetDecimal("Balance")
                            
                });
            }

            return (contracts, null);

        }
        catch (Exception exception)
        {
            return (null, exception);
        }

        
    }
}

// place in own file
public class Contract
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public decimal? Balance { get; set; }

    public override string ToString() => $"{FirstName} {LastName}";

}

使用单元测试方法

[TestMethod]
public void LargeLike()
{
    var (contracts, exception) = SqlOperations.ReadDBView("%nia");

    if (contracts.Count > 0 && exception is null)
    {
        Debug.WriteLine(contracts.Count);
    }
    else
    {
        Debug.WriteLine(exception is not null ? exception.Message : "No matches");
    }
}

语法using

public static void UsingExample()
{
    // C#9, .NET Core 5 syntax
    using var cn1 = new SqlConnection() { ConnectionString = ConnectionString };

    // .NET 4.8 syntax
    using (var cn2 = new SqlConnection() { ConnectionString = ConnectionString })
    {
        
    }
    
}

推荐阅读