管理和关闭.net中动态创建的SQL连接

Yah*_*ufi 4 c# sql sql-server winforms

我有一个ac #windows窗体应用程序,动态连接数据库,每个用户可以连接到不同的数据库.

目前的实施情况如下:

连接存储库,包含动态填充的连接列表(每个用户).

当用户发起需要数据库连接的请求时,将从连接存储库中查找相应的连接,打开,然后在用户请求中使用.

连接存储库中的代码示例

public class RepoItem
{
    public string databasename;
    public SqlConnection sqlcnn;
}

public class ConnectionRepository
{
    private List<RepoItem> connectionrepositroylist;

    public SqlConnection getConnection(String dbname)
    {
        SqlConnection cnn = (from n in connectionrepositroylist
                             where n.databasename == dbname
                             select n.sqlcnn).Single;

        cnn.Open();
        return cnn;
    }
}
Run Code Online (Sandbox Code Playgroud)

对于任何代码错误,我只是为了演示目的即兴创建了一个小版本的实现.

我没有在命令执行后关闭连接,因为它可能同时被另一个命令使用.

问题是:

  • 我应该担心关闭连接吗?

  • 如果在特定时间段内空闲,连接会自动关闭吗?

我有一个方法是在创建的连接存储库中实现一个计时器,并检查通过它的空闲连接Executing ConnectionState Enumeration并手动关闭它们.欢迎任何建议.

当我想要一个特定的连接时,我调用ConnectionRepository类中的getConnection函数并将数据库名称作为参数传递.

PS:我没有发布完整实现的代码,因为它非常大并且包含影响连接列表填充的首选项.

Zoh*_*led 8

我建议不要回到SQLConnection调用方法.相反,创建一个接受a的方法,Action<SqlConnection>using块内创建连接,并在该块内执行操作

这样您就知道连接将始终正确关闭和处理,同时使用代码可以自由地执行所需操作:

public class RepoItem
{
    public string databasename;
    public SqlConnection sqlcnn;
}

public class DatabaseConnector
{
    private List<RepoItem> connectionrepositroylist;

    private SqlConnection GetConnection(String dbname)
    {
        return (from n in connectionrepositroylist
                where n.databasename == dbname
                select n.sqlcnn).SingleOrDefault();
    }

    public void Execute(String dbname, Action<SqlConnection> action)
    {
        using (var cnn = GetConnection(dbname))
        {
            if (cnn != null) // in case dbname is not in the list...
            {
                cnn.Open();
                action(cnn);
            }
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

然后,要执行sql语句,您可以执行以下操作:

public void ExecuteReaderExample(string dbName, string sql)
{
    Execute("dbName",
    connection =>
    {
        using (var cmd = new SqlCommand(sql, connection))
        {
            using (var reader = cmd.ExecuteReader())
            {
                while (reader.Read())
                {
                    // do stuff with data form the database
                }
            }
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

当然,你也可以用这样SqlCommand的方法包装.我一直在使用这种方法已经有一段时间了,据我所知,它运作良好.事实上,它运作良好我基于这种方法在git hub上发布了一个项目.
通过以相同的方式包装连接,命令,阅读器和适配器,它在处理ado.net时为您节省了大量的管道.随意下载并适应您的需求.

PS直接回答您的问题:

我应该担心关闭连接吗?

是的你应该.

如果在特定时间段内空闲,连接会自动关闭吗?

不,它没有.

但是,实现像我建议的方法将为您处理关闭和处理连接对象,因此您不必担心它.

更新

正如Yahfoufi在他的评论中写道,这个设计有一个缺陷,因为多个命令使用相同的实例SqlConnection,你在冒着其他命令运行时关闭连接的风险.但是,解决这个设计缺陷是很容易-而不是抱着SqlConnectionRepoItem你可以简单地保持连接字符串:

public class RepoItem
{
    public string DatabaseName {get; set;}
    public string ConnectionString {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

然后你改变这样的GetConnection方法:

    private SqlConnection GetConnection(String dbname)
    {
        return new SqlConnection(from n in connectionrepositroylist
                where n.databasename == dbname
                select n.sqlcnn).SingleOrDefault());
    }
Run Code Online (Sandbox Code Playgroud)

现在每个Execute方法都在处理它自己的单个实例,SqlConnection因此您不必担心在执行其他命令的过程中关闭.

不过,虽然我们对重构的问题,我建议去掉RepoItem类一起,而不是使用的List<RepoItem>保持连接字符串简单地使用Dictionary<string, string>,其中数据库名称是关键,连接字符串的值.这样,每个数据库名称只能有一个连接字符串,并且您的GetConnection方法简化为:

private Dictionary<string, string> connectionrepositroylist;

    private string GetConnectionString(String dbname)
    {
        return connectionrepositroylist.ContainsKey(dbname) ? connectionrepositroylist[dbname] : "";
    }
Run Code Online (Sandbox Code Playgroud)

因此,完整的DatabaseConnector类将如下所示:

public class DatabaseConnector
{
    private Dictionary<string, string> connectionrepositroylist;

    private string GetConnectionString(String dbname)
    {
        return connectionrepositroylist.ContainsKey(dbname) ? connectionrepositroylist[dbname] : "";
    }

    public void Execute(String dbname, Action<SqlConnection> action)
    {
        var connectionString = GetConnectionString(dbname);
        if(!string.IsNullOrEmpty(connectionString))
        {    
            using (var cnn = new SqlConnection(connectionString))
            {
                cnn.Open();
                action(cnn);
            }
        }
    }

    // Of course, You will need a way to populate your dictionary - 
    // I suggest having a couple of methods like this to add, update and remove items.
    public bool AddOrUpdateDataBaseName(string dbname, string connectionString)
    {
        if(connectionrepositroylist.ContainsKey(dbname))
        {
            connectionrepositroylist[dbname] = connectionString;
        }
        else
        {
            connectionrepositroylist.Add(dbname, connectionString);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)