这是处理 SQLConnection 的正确方法吗

发布于 2024-12-12 01:39:55 字数 998 浏览 1 评论 0原文

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

我知道通常如果我直接使用 SqlConnection,我可以将连接包装在 using 块中以自动将其释放,但在这种情况下,我想保持连接打开并可用于 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

I was wondering if my below implementation is the most efficient way to dispose the SQLconnection in this case.

I know normally if i'm using the SqlConnection directly I can just wrap the connection inside a using block to dispose it off automatically, but in this case i wanted to keep the connection open and available to All methods in the SQLRespository class.

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();
    }
}

Usage:

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

Update
IRepository does implement IDisposable

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

泪之魂 2024-12-19 01:39:55

不要在呼叫期间保持连接打开。您正在击败连接池。

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

您可能会争辩说,如果调用者执行您使用一种方法调用所做的操作,那就没问题。但是,如果您在每个工作方法中使用带有 sqlconnection 的 {} (1) 代码会更简单,并且 (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.  
        }
    }

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

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

Don't keep the connection open spanning calls. You're defeating connection pooling.

If you're working with a connection that's pooled (like sqlserver), it will pool and reuse. Just open and close within method a & b.

You could argue that if the caller does what you did with using with one method call it's fine. But if you do using {} with sqlconnection inside each worker method (1) the code will be simpler and (2) you're ensured the pooling wont be defeated (meaning your holding items out of the pooling when other requests could use it).

EDIT:

Adding pseudo based on comments.

The pattern is problematic because a caller can do.

//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.

That will kill the scalability of the server - trust me. I've seen very large systems get choked by this - usually because they're spanning AT side transactions.

A better pattern:

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.  
        }
    }

Now, the pool is most effective. I realize the question was on the disposable pattern - and yes you can do it. But ...

I would not let the connection span the lifetime of the repository.

豆芽 2024-12-19 01:39:55

如果你想这样做,请确保你实现了 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。

但是 - 您确定要为每个存储库建立一个连接吗?跨越多个存储库的操作怎么样?

If you want to do it like that, ensure you implement IDisposable (I cant tell if you note this on your IRepository interface or not) and I'll do something like:


        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);
        }

Obviously the _context here is your SqlConnection.

however - are you sure you want one connection per repository? What about operations spanning more than one repository?

渔村楼浪 2024-12-19 01:39:55

假设 IRepository 继承自 IDisposable,只要您没有将 SqlRepository 类的实例保持打开状态的时间超过其执行时间,那么您的实现就可以了。对数据库的“逻辑”查询序列。事实上,这个序列可能跨越多个方法调用,这不是问题。

我不同意@bryanmac的回答:

不要在跨呼叫期间保持连接打开。您正在击败连接池。

假设您的方法调用序列属于在一起,并且您保持连接打开的时间不超过完成逻辑序列所需的时间,我看不出这会以任何方式破坏连接池。

不过有一条评论。您应该:

  • 要么实现标准的IDisposable模式(使用可以在派生类中重写的protected void Dispose(bool dispose)方法

  • 或者使您的类密封,在这种情况下您现有的IDisposable 实现没问题。

Assuming IRepository inherits from IDisposable, your implementation is fine provided you are not keeping an instance of your SqlRepository class open for longer than it takes to perform a 'logical' sequence of queries on the database. The fact that this sequence might span several method calls is not a problem.

I disagree with @bryanmac's answer:

Don't keep the connection open spanning calls. You're defeating connection pooling.

Provided your sequence of method calls belong together, and you don't keep the connection open for longer than it takes to complete the logical sequence, I don't see how this in any way defeats connection pooling.

One comment though. You should:

  • Either implement the standard IDisposable pattern (with a protected void Dispose(bool disposing) method that can be overridden in derived classes

  • Or make your class sealed, in which case your existing IDisposable implementation is fine.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文