调用数据库类方法后内存不足错误

时间:2021-07-17 08:47:26

标签: c# ado.net

我的项目中有波纹管类可以帮助我直接运行 SQL 命令。在我的电脑上它工作正常。但是当我在页面中调用大约 5 到 6 次后发布到 Web 服务器时,出现内存不足错误。该错误在大约 20 分钟后清除。但它一次又一次地发生。

using System;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Data;
using System.Data.Linq;
using System.Data.SqlClient;
using System.Data.OleDb;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Globalization;

public class FirstClass
{
    SqlConnection con;
    public SqlCommand cmd;
    DataTable dt;
    SqlDataAdapter da;

    public FirstClass()
    {
        con = new SqlConnection(ConfigurationManager.ConnectionStrings["WebSiteConnectionString"].ConnectionString);
        cmd = new SqlCommand();
        dt = new DataTable();
        cmd.Connection = con;
        da = new SqlDataAdapter(cmd);
    }

    public DataTable dbSelect(string sql)
    {
        DataTable dttt = new DataTable();
        try
        {
            cmd.CommandText = sql;
            con.Open();
            da.Fill(dt);
            con.Close();
            return dt;
        }
        catch
        {
            return dttt;
        }

    }

    public void exeSp(string spName)
    {
        con.Open();

        cmd.CommandType = CommandType.StoredProcedure;
        cmd.CommandText = spName;
        cmd.ExecuteNonQuery();
        con.Close();

    }

    public void exeSqlCmd(string sql)
    {
        try
        {
            cmd.CommandText = sql;
            con.Open();
            cmd.ExecuteNonQuery();
        con.Close();
        }
        catch { }

    }
}

这主要发生在我使用第一种方法时。当然,获取的记录数也很重要。获取的记录数越多,发生内存不足错误的速度就越快。但是大约 20 分钟后,所有错误都会自动修复,我可以再次运行代码。但不幸的是,我再次收到相同的错误消息。请帮忙。

1 个答案:

答案 0 :(得分:1)

问题中的代码有几个问题。我只会明确提及 System.Data.SqlClient 中与使用类相关的一些问题,而不会提及一般问题,尽管此处显示的代码解决了许多一般问题,但不是全部。

SqlConnection、SqlCommand、SqlDataAdapter、SqlDataReader 等类是轻量级的,应该在最内层的范围内创建和发布。尝试通过跨查询保留它们来重用它们没有任何好处。它们还需要在内存使用和资源使用方面得到妥善管理,不仅在执行遵循成功路径时,而且在出现错误时也是如此。这可以通过以下方式实现。

using System.Data;
using System.Data.SqlClient;
using System.Configuration;

public static class FirstClass
{
    private static string connectionString =
        ConfigurationManager.ConnectionStrings["WebSiteConnectionString"].ConnectionString;

    private static SqlConnection GetConnection()
    {
        return new SqlConnection(connectionString);
    }

    public static DataTable DbSelect(string sql)
    {
        using (var con = GetConnection())
        {
            using (var cmd = new SqlCommand(sql, con))
            {
                using (var adapter = new SqlDataAdapter(cmd))
                {
                    try
                    {
                        DataTable result = new DataTable();
                        adapter.Fill(result);
                        return result;
                    }
                    catch
                    {
                        return null;
                    }
                }
            }
        }
    }

    public static void ExeSp(string spName)
    {
        using (var con = GetConnection())
        {
            using (var cmd = new SqlCommand())
            {
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.CommandText = spName;
                cmd.ExecuteNonQuery();
            }
        }
    }

    public static void ExeSqlCmd(string sql)
    {
        using (var con = GetConnection())
        {
            using (var cmd = new SqlCommand(sql, con))
            {
                try
                {
                    cmd.ExecuteNonQuery();
                }
                catch
                {
                }
            }
        }
    }
}

该类已成为静态,这确保所有内存和资源管理现在都在每个方法中进行。我们不再依赖于了解类本身如何在其他地方使用来了解事物是如何工作的。在这些方法中,using 的使用现在清楚地告诉我们资源(包括内存)是如何分配和释放的。我们可以看到一切都被正确处理,因此不再有任何方法可以在数据库调用之间存在任何资源,无论调用是成功还是错误。在 DbSelect 方法中,DataTable 被创建在尽可能靠近其使用点的位置,以便我们很容易看到它在做什么。

不清楚在原始代码中拥有一个本地和一个类级别的 DataTable 的意图是什么,它返回一个或另一个 - 可能只是试验时的一个临时故障 - 但在这个新版本中,调用者负责使用后处理返回的结果。另一种选择是让调用者提供一个 DataTable 来填写,如果这对调用者来说更容易的话。如果是这样,请在填写之前清空表格。

说到错误处理,可以改进,但我不会深入讨论。

这段代码可以编译,但我还没有验证它是否真的有效。我的目的是展示如何在一般情况下组织这些类型的数据库调用,您可以修复我可能从那里忽略的任何错误。

相关问题