【问题标题】:SQL Server connections in ASP.NET application [closed]ASP.NET 应用程序中的 SQL Server 连接 [关闭]
【发布时间】:2015-07-31 15:58:58
【问题描述】:

我用asp.net 创建了一个web 应用程序,大致100 users 正在使用它。

但是,人们有时会收到连接仍处于打开状态的错误消息。表示没有正确关闭。

它出现在随机的地方,不是一个特定的地方,也没有其他错误。

我知道,当我在应用程序中出现错误并且它崩溃而我没有优雅地处理错误时,连接也会保持打开状态,基本上每个人都会因此而崩溃。这让我觉得每个人都使用相同的连接对象,是否有可能 2 个用户可能有完美的时机并同时使用 DB connection 调用函数导致错误?有没有办法确保每个人都使用自己的连接对象,比如把它放在他们的会话中或其他什么?

我希望你能理解我的意思,我不认为发布我的任何代码会有帮助,因为它发生在我项目中的随机位置。

它们使用System.Data.SqlClient 连接到SQL Server

在产生错误的函数下方查找。该函数由 Page_Load 调用,它之前没有任何内容。

public static SqlConnection conn = new SqlConnection("Data Source=Server00\\SQLEXPRESS;Initial Catalog=r2;Integrated Security=true;Connect Timeout=0");

private void populateGameDrop()
{
    try
    {
        conn.Open();
        drop_game.Items.Clear();

        SqlCommand cmd = conn.CreateCommand();
        Access ac = (Access)Session["Access"];
        cmd.CommandText = "Select * from dbo.Games where " + ac.GameQuery;

        SqlDataReader r = cmd.ExecuteReader();

        while (r.Read())
        {
            drop_game.Items.Add(new ListItem(r["name"].ToString(), r["Abbr"].ToString()));
        }

        conn.Close();
    }
    catch (Exception exc)
    {
        conn.Close();
        Log.Error(exc.ToString());
        Session["Error"] = exc.ToString();
        Response.Redirect("~/YouBrokeIt.aspx");
    }

    populateServers();
    SetSplitScreen();
}

【问题讨论】:

  • 认为根据每个请求打开和关闭连接是一个好习惯。这个answer 基于实体框架的DbContext,但我认为它也适用于普通 ADO。
  • 抱歉,但无法查明是什么代码 sn-p 导致了这些问题,这个问题实在是太宽泛了。您需要先自己进行更多研究,以便能够告诉我们是什么代码导致了问题
  • 添加一些您如何访问DB 的代码您是否使用using staments?
  • 基本建议是:尽可能晚地创建 SqlConnection 对象 - 最好在创建使用它的 SqlCommand 对象之前立即创建,并将它们都包装在 using 语句中。您应该共享的唯一目标是连接 string.
  • static SqlConnection 不应该是静态的,它应该在 using stement 中创建

标签: c# asp.net sql-server


【解决方案1】:

不要尝试共享 SqlConnection 对象。

试试这个:

private static string connString = "Data Source=Server00\\SQLEXPRESS;Initial Catalog=r2;Integrated Security=true;Connect Timeout=0";
private void populateGameDrop()
{
    try
    {
        using (var conn = new SqlConnection(connString))
        {
            conn.Open();
            drop_game.Items.Clear();
            using (var cmd = conn.CreateCommand())
            {
                Access ac = (Access)Session["Access"];
                //TODO
                //TODO - Introduce parameters to avoid SQL Injection risk
                //TODO
                cmd.CommandText = "Select name,Abbr from dbo.Games where " + ac.GameQuery;
                using(SqlDataReader r = cmd.ExecuteReader())
                {
                    while (r.Read())
                    {
                        drop_game.Items.Add(new ListItem(r["name"].ToString(),
                                            r["Abbr"].ToString()));
                    }
                }
            }
        }
    }
    catch (Exception exc)
    {
        Log.Error(exc.ToString());
        Session["Error"] = exc.ToString();
        Response.Redirect("~/YouBrokeIt.aspx");
    }
    populateServers();
    SetSplitScreen();
}

在幕后,.NET 使用了一个名为connection pooling 的概念,以便最大限度地减少与 SQL Server 的实际真实连接数。但是SqlConnection 对象并不是为多线程共享而设计的。

【讨论】:

  • 您应该将您的SqlDataReader 放入using() { .... } 块中(如果您已经为SqlConnectionSqlCommand 这样做了......) - 你还应该参数化查询以避免SQL注入
  • 我明白了:O 这真的很有启发性。看起来我要对我的项目进行大量编辑。至于参数建议,一直在其他查询上做,但这基本上是一个静态查询。没有用户输入。只是 where 在早期完成的函数中是可变的。
【解决方案2】:

不要将数据库代码直接放在 ASPX 页面中。创建一个额外的层(即 DAL)允许您在不使用页面的情况下测试 DB 方法。

试试这样的。

//Don't embed database logic directly in the aspx files
public class GamesProvider
{        
    //Put the ConnectionString in you configuration file
    private string ConnectionString
    {
        get { return ConfigurationManager.ConnectionStrings["GameDB"].ConnectionString; }
    }

    public IEnumerable<Game> LoadGames(string x, string y)
    {
        var games = new List<Game>();

        const string queryString = "select name, Abbr from dbo.Games where x = @x and y = @y";

        using (var connection = new SqlConnection(ConnectionString))
        using (var command = new SqlCommand(queryString, connection))
        {
            command.Parameters.AddWithValue("@x", x);
            command.Parameters.AddWithValue("@y", y);
            using (var dateReader = command.ExecuteReader())
            {
                while (dateReader.Read())
                {
                    var game = new Game
                    {
                        Name = dateReader["name"].ToString(),
                        Abbr = dateReader["Abbr"].ToString(),
                    };
                    games.Add(game);
                }
            }
        }

        return games;
    }
}

//Use types
public class Game
{
    public string Name { get; set; }
    public string Abbr { get; set; }
}

【讨论】:

    【解决方案3】:

    您的SQL 连接不应是静态的,请使用以下内容创建它们

    var connectionString = "YOUR CONNECTION STRING";
    var queryString = "SQL QUERY";
    
    using (SqlConnection connection = new SqlConnection(connectionString))
    using (SqlCommand command = new SqlCommand(queryString, connection))
    using (SqlDataReader dateReader = command.ExecuteReader()) {
    
    }
    

    非常重要

    您应该使用参数化的SQL,您的代码对SQL 注入攻击是开放的。

    请看Parameterize SQL query

    【讨论】:

    • 你真的应该为SqlConnectionSqlCommandSqlDataReader使用using() { .... }
    • @marc_s 好点我已经更新了我的答案
    猜你喜欢
    • 1970-01-01
    • 2017-12-09
    • 2011-03-18
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-02
    • 1970-01-01
    相关资源
    最近更新 更多