【问题标题】:Need help managing MySql connections需要帮助管理 MySql 连接
【发布时间】:2010-05-13 18:20:52
【问题描述】:

我很难找到关于连接池的清晰解释。我正在使用从 mysql.com 下载的 .NET 连接器构建应用程序。该应用程序只需要一个数据库连接,但将在我的网络上大约 6 台机器上同时运行。通常,我会在启动时创建连接并离开它。但是我看到很多人说这是不好的做法。我也担心超时。我的应用程序将 24/7 全天候运行,并且可能会在很长一段时间内没有数据库活动。

我倾向于以下:

using (MySqlConnection conn = new MySqlConnection(connStr))
{
    conn.Open();
    // use connection
}

但我不确定我是否理解后台发生的事情。这实际上是关闭连接并允许 gc 杀死对象,还是有一个内置的池行为来保留对象并在我下次尝试创建对象时重新传递它?

我当然不希望应用在每次访问数据库时都通过网络重新进行身份验证。

谁能给我一些建议?

【问题讨论】:

  • 如果您使用过 Entity Framework,您现在可能正在喝啤酒!
  • 非常感谢所有回复的人!

标签: c# mysql connection pooling


【解决方案1】:

.net 提供商习惯于在这种情况下使用连接池。

连接应该只是在您使用结束时返回到池中。

我没有使用 mysql 分析器查看问题,但我有依赖于它的代码 - 没有遇到任何问题。

更新:我刚刚查看了在 dispose 期间完成的调用,它肯定会进行连接池,即它最终会调用:

internal void CloseFully()
{
    if (this.settings.Pooling && this.driver.IsOpen)
    {
        if ((this.driver.ServerStatus & ServerStatusFlags.InTransaction) != 0)
        {
            new MySqlTransaction(this, IsolationLevel.Unspecified).Rollback();
        }
        MySqlPoolManager.ReleaseConnection(this.driver);
    }
    else
    {
        this.driver.Close();
    }
    this.driver = null;
}

更新 2/回答评论: MySqlConnection 实例是一个不同的实例,因为 using statement 只处理处置(释放资源)。因此,您无需检查它是否已关闭。 MySqlConnection 在内部使用其他类/实例,即它获取适当的实例。这对您的代码是透明的,因此您可以像使用新的+不同的连接一样使用它/就像在您发布的代码中一样。

如你所说,为了能够重用较低级别的连接(在mysql连接器代码中称为Driver),每个池都是由连接字符串决定的。

【讨论】:

  • 好吧,你在我头上只有几英尺。这是否意味着当我再次使用 new 时,该对象将被重新交付?如果是这样,它如何知道哪个对象(可能通过比较连接字符串?)我应该检查 state 属性以确保在调用 open 之前连接没有关闭?非常感谢您的宝贵时间。
  • 感谢您抽出宝贵的时间。这很有帮助。
【解决方案2】:

根据this post,默认情况下连接会在关闭前保持活动状态并池化 60 秒。

【讨论】:

    【解决方案3】:

    断开连接模型是全世界使用最多的模型,但不会一遍又一遍地滥用身份验证。

    断线模式

    以下是您希望大部分时间不联网工作的一些原因:

    1. 为您的数据库服务器购买的 CLA(客户端许可协议)数量(好吧,这里并不适用,因为它是 MySQL);
    2. 如果同时连接的人太多,这会降低 DBE(数据库引擎)的速度;
    3. 保持连接打开会导致网络繁忙,网络太忙更容易出现故障;
    4. 当用户在编辑时,比方说客户的详细信息,他不需要保留与数据库服务器的连接,也不需要锁定行或数据表,这会导致并发锁定问题。李>

    这段代码:

    using(MySqlConnection conn = new MySqlConnection(connStr)) {
        if (conn.State == ConnectionState.Closed)
            try {
                conn.Open();
            } catch (MySqlException ex) {
                // Exception handling here...
            }
        // Use of connection here...
    }
    

    using 关键字用于自动处置在其中实例化的对象,如文章引用所述:

    定义一个范围,一个或多个对象将在该范围之外被释放。

    这样,您可以确保一旦不再需要连接,您就可以将其丢弃。所以是的,一旦再次实例化此连接,将需要新的身份验证,因为它不再存在。这里有一小段时间进行了一些民意调查,但您无需担心。

    连接模式

    为了确保在整个应用程序中只使用一个这样的连接,您应该将其用作singleton。但是,一旦您的连接字符串更改,总有一天,您必须确保所有应用程序都关闭并重新打开,以便此连接获得刷新的连接字符串。这是不可行的,但我不知道你的上下文。

    使用企业库数据访问应用程序块

    为了使您的连接池易于管理,您可能需要使用Enterprise Library Data Access Application Block

    DAAB 是一个易于使用、完全可配置的数据访问层,由 Microsoft 工程师和其他参与公司设计。然后,管理连接池可以像 1-2-3 一样简单!

    我认为您可以使用 DAAB 获得很多好处,它可以在 XML 文件中完全配置并且需要非常低的维护。

    编辑如果我可以更进一步,我可能会考虑使用带有工厂的外观设计模式。

    有效地使用外观和工厂设计模式

    拥有“智能”外观,正是它为您提供所需的连接。因此,这是一个简单的示例(假设您有一个名为“DefaultConnectionString”的项目设置):

    public static class ApplicationFacade {
        private static readonly ApplicationFactory _applicationFactory = new ApplicationFactory();
    
        public static DefaultConnectionString {
            get {
                return Properties.Settings.Default.DefaultConnectionString;
            }
        }
    
        public static IList<ICustomer> GetCustomers() {
            using(var connection = OpenConnection())
               _applicationFactory.GetCustomers(connection);
        }
    
        public MySqlConnection OpenConnection() {
            var newConnection = new MySqlConnection(DefaultConnectionString);
            try {
                newConnection.Open();
            } catch (Exception ex) {
                // Exception handling...
            }
            return newConnection;
        }
    }
    
    internal sealed class ApplicationFactory {
        internal ApplicationFactory() {
        }
    
        internal IList<ICustomer> GetCustomers(MySqlConnection connection) {
            if (connection.State != ConnectionState.Open)
                throw new InvalidOperationException()
    
            IList<ICustomer> customers = new List<ICustomer>();
    
            var command = new MySqlCommand(connection, @"select * from Customers");
            // Place code to get customers here...
    
            return customers;
        }
    }
    
    // So you'll be able to use share the same connection throught your factory whenever needed, preventing the overkill of authentication over and over again. Here's how this would be used:
    
    public partial class MainForm : Form {
        private void PopulateGrid() {
            dataGridView1.DataSource = ApplicationFacade.GetCustomers();
            // And you never care about the connection! All you want is the list of customers, that's all!
        }
    }
    

    这是我在开发项目中经常使用的模式。它允许我的类库有一个入口点,而且它们非常易于使用。

    嗯,这可能比您要求的要多,但我希望它有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-07
      • 1970-01-01
      • 2016-01-13
      • 2018-11-06
      相关资源
      最近更新 更多