繁体   English   中英

这是处理SQLConnection的正确方法吗?

[英]Is this the right way to dispose the SQLConnection

我想知道在这种情况下我的下面的实现是否是处理SQL连接的最有效方法。

我通常知道如果我直接使用SqlConnection,我可以将连接包装在一个使用块中以自动处理它,但在这种情况下,我想保持连接打开并可用于SQLRespository类中的所有方法。

public class SqlRepository : IRepository
{
    private readonly string connectionString;
    private SqlConnection connection;

    public SqlRepository(string connectionString)
    {
        this.connectionString = connectionString;
        connection = new SqlConnection(connectionString);
        connection.Open();
    }

    public void Method_A()
    {
      // uses the SqlConnection to fetch data
    }     

    public void Method_B()
    {
      // uses the SqlConnection to fetch data
    }     

    public void Dispose()
    {            
        connection.Dispose();
    }
}

用法:

using (IRepository repository = new SqlRepository(connectionString))
{
   var item = repository.items;     
}

更新 IRepository确实实现了IDisposable

不要保持连接打开跨越呼叫。 你正在打败连接池。

如果您正在使用汇集的连接(如sqlserver),它将进行池化和重用。 只需在方法a和b中打开和关闭即可。

您可以争辩说,如果调用者使用一种方法执行您所做的操作就可以调用它。 但是如果你在每个工作方法(1)中使用带有sqlconnection的{},代码将更简单,并且(2)你确保池不会被破坏(意味着当其他请求可以使用它时,你可以将池中的项目排除在池外) 。

编辑:

根据评论添加伪。

该模式存在问题,因为呼叫者可以这样做。

//pseudo code
using (SqlRepository r)
{
    r.MethodA();

    // other code here that takes some time.  your holding a connection
    // out of the pool and being selfish.  other threads could have
    // used your connection before you get a chance to use it again.

    r.MethodB();
}  // freed for others here.

这会破坏服务器的可扩展性 - 相信我。 我已经看到非常大的系统被这种情况所困扰 - 通常是因为它们正在跨越AT侧交易。

更好的模式:

class Repository
{
    void MethodA()
    {
        using (Sqlconnection)
        {
             // db call
        }
    }

    void MethodB()
    {
        using (Sqlconnection)
        {
            // you can even have multiple calls here (roundtrips)
            // and start transactions.  although that can be problematic
            // for other reasons.  
        }
    }

现在,游泳池是最有效的。 我意识到问题在于一次性模式 - 是的,你可以做到。 但......

我不会让连接跨越存储库的生命周期。

如果你想这样做,确保你实现IDisposable(我不能告诉你是否在你的IRepository接口上注意到这一点),我会做类似的事情:


        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    _context.Dispose();
                }
            }
            this.disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

显然这里的_context是你的SqlConnection。

但是 - 您确定每个存储库需要一个连接吗? 那些跨越多个存储库的操作呢?

假设IRepository继承自IDisposable ,那么您的实现就可以了,前提是您没有将SqlRepository类的实例打开的时间超过在数据库上执行“逻辑”查询序列所需的时间。 此序列可能跨越多个方法调用的事实不是问题。

我不同意@bryanmac的回答:

不要保持连接打开跨越呼叫。 你正在打败连接池。

如果您的方法调用序列属于一起,并且您没有保持连接打开的时间超过完成逻辑序列所需的时间,我不会看到这会以任何方式阻止连接池。

但有一条评论。 你应该:

  • 实现标准IDisposable模式(带有protected void Dispose(bool disposing)方法,可以在派生类中重写)

  • 或者让你的课程密封,在这种情况下你现有的IDisposable实现是好的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM