2

我有一个实现我的数据库连接的基类。我有第二个类继承了这个基础数据库类。第二类内部有一些递归,在评估它的值时,它可能会实例化第二类的另一个实例。递归只有几个层次。我正在单线程运行所有内容。

我的代码将正确运行大约 1 或 2 分钟,然后我开始收到一致的错误:“超时已过期。在从池中获取连接之前超时时间已过”。

我的基类有一个析构函数,它调用数据库对象的 .Dispose() 方法。我的第二个类有一个析构函数,它关闭基类中的连接对象。

我到数据库的连接字符串指定连接超时 = 0。

关于为什么代码会在几分钟内正常工作然后开始超时尝试连接到数据库的任何想法?我很困惑。

namespace BaseLib2
{
public class TSBase
{
    protected StreamWriter logFile;

    protected OleDbCommand queryCmd;
    protected OleDbCommand exeCmd;
    protected OleDbConnection connection;
    protected OleDbDataReader reader;
    public SqlConnection sqlconn;//used for BCP

    public TSBase()
    {

    }

    ~TSBase()
    {
        try
        {
            queryCmd.Dispose();
            exeCmd.Dispose();
            reader.Dispose();
            connection.Dispose();
            sqlconn.Dispose();
        }
        catch (Exception ex)
        {
            Console.WriteLine("BaseLib2 destrutor:" + ex.Message);
        }
    }


    public void ConnectToDB()
    {
        string connString = "Provider=SQLNCLI11;Server=myserver;Database=mydb;Uid=myid;pwd=password;connection timeout=0";
        queryCmd = new OleDbCommand();
        exeCmd = new OleDbCommand();
        connection = new OleDbConnection(connString);            
        queryCmd.CommandTimeout = 60000;
        exeCmd.CommandTimeout = 60000;
        connection.Open();
        queryCmd.Connection = connection;
        exeCmd.Connection = connection;
        string sqlConnString = "server=dc2k8housql;database=mydb;Uid=myid;pwd=password;connection timeout=0";
        sqlconn = new SqlConnection(sqlConnString);
        sqlconn.Open();
    }

public class Expression : BaseLib2.TSBase 
{
private string ExpName;
private string ExpressionTxt;
private string sql;
private DateTime Contract_dt;
private DateTime Quote_dt;
private bool SaveToDB;
private string BaseSymbol;

public Expression(string expNameIn, DateTime contract_dtIn, DateTime quote_dtIn)
{
    ExpName = expNameIn;
    Contract_dt = contract_dtIn;
    Quote_dt = quote_dtIn;

    try
    {
        try
        {
            ConnectToDB();
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error in EXP constructor connecting to database." + ex.Message );
            throw new Exception("Error in EXP constructor connecting to database.");
        }
        //get expression text from database
        sql = "select expression, save_to_db, coalesce(base_symbol, '') as base_symbol from expressions where exp_name = " + DBI(ExpName);
        reader = ReadData(sql);
        if (reader.Read())//should only return 1 row
        {
            ExpressionTxt = reader[0].ToString();
            SaveToDB = bool.Parse(reader[1].ToString());
            BaseSymbol = reader[2].ToString();
        }
        reader.Close();
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception in Expression constructor:" + ex.Message);
    }
}

~Expression()
{
    try
    {
        connection.Close();
        sqlconn.Close();
        connection.Dispose();
        sqlconn.Dispose();
    }
    catch (Exception ex)
    {
        Console.WriteLine("Error in destructor:" + ex.Message);
    }
}

public double Eval()
{
    try
    {
        //check to see if there are any $RV in the expression
        if (ExpressionTxt.Contains("$RV("))
        {
            //parse and evaluate the $RV's                
            String[] split = ExpressionTxt.Split(("$".ToCharArray()));
            foreach (string s in split){
                Console.WriteLine("s=" + s);
                if (s.Length > 3)//make sure we have a string with a symbol in it
                {
                    //for each rv we find, create a new expression and evaluate it                                                
                    if (s.Substring(0, 3).Contains("RV"))
                    {
                        int pStart = s.IndexOf("(");
                        int pEnd = s.IndexOf(")");
                        string rvSymb = s.Substring(pStart + 1, pEnd - pStart - 1);
                        System.Console.WriteLine(rvSymb);
                        Expression oExp = new Expression(rvSymb, Contract_dt, Quote_dt);
                        double rVal = oExp.Eval();//recursive call
                        oExp = null;
                        ExpressionTxt = ExpressionTxt.Replace("$RV(" + rvSymb + ")", rVal.ToString());
                    }
                }
            }
        }
        //replace SV values in formula
        if (ExpressionTxt.Contains("$SV("))
        {
            //find symbols in $SV brackets and collect contract dates
            String[] split = ExpressionTxt.Split (("$".ToCharArray()));
            foreach (string s in split)
            {
                if (s.Length > 3)
                {//make sure we have a symbol
                    if (s.Substring(0, 3).Contains("SV"))
                    {
                        int pStart = s.IndexOf("(");
                        int pEnd = s.IndexOf(")");
                        string svSymb = s.Substring(pStart + 1, pEnd - pStart - 1);
                        System.Console.WriteLine("sv=" + svSymb);
                        //replace $SV with numerical values
                        double sVal = GetQuoteValue(svSymb);
                        ExpressionTxt = ExpressionTxt.Replace("$SV(" + svSymb + ")", sVal.ToString());
                    }
                }
            }
        }           
        //evaluate 
        double ret = Evaluate(ExpressionTxt);
        Console.WriteLine(ExpName + "=" + ret.ToString());
        if (SaveToDB)
        {
            Console.WriteLine(ExpName + " cd:" + Contract_dt.ToShortDateString() + " qd:" + Quote_dt.ToShortDateString() + ": saving to db...");
            sql = "delete from exp_quotes where exp_name = " + DBI(ExpName ) ;
            sql = sql + " and contract_dt = " + DBI(Contract_dt.ToShortDateString());
            sql = sql + " and quote_dt = " + DBI(Quote_dt.ToShortDateString());
            WriteData(sql);
            sql = "insert into exp_quotes(exp_name, contract_dt, quote_dt, calculated_dt, price) values(";
            sql = sql + DBI(ExpName ) + "," + DBI(Contract_dt.ToShortDateString()) + "," + DBI(Quote_dt.ToShortDateString());
            sql = sql + ", getdate(), " + ret + ")";
            WriteData(sql);
        }
        connection.Close();//after we evaluate, close down the connection
        connection.Dispose();
        return ret;
        //return value
    }
    catch (Exception ex)
    {
        Console.WriteLine("exp:" + ExpName + " cd:" + Contract_dt.ToShortDateString() + " qd:" + Quote_dt.ToShortDateString() + " = " + ex.Message);
    }        
    return 0;
}

private double GetQuoteValue(string symbIn)
{
    double ret = 0;
    sql = "select close_val from prices_union_all_vw where symbol = " + DBI(symbIn) + " and contract_dt = " + DBI(Contract_dt.ToShortDateString()) + " and quote_dt = " + DBI(Quote_dt.ToShortDateString());
    reader = ReadData(sql);
    if (reader.Read())
    {
        ret = Double.Parse(reader[0].ToString());
        reader.Close();
    }
    else
    {//we didn't get a record for the specific quote date, try again using the mostrecent view
        sql = "select close_val from prices_union_all_mostrecent_vw where symbol = " + DBI(symbIn) + " and contract_dt = " + DBI(Contract_dt.ToShortDateString());
        reader = ReadData(sql);
        if (reader.Read())
        {
            ret = Double.Parse(reader[0].ToString());                
        }
        reader.Close();
    }
    return ret;
}

private static double Evaluate(string expression)
{
    var loDataTable = new DataTable();
    var loDataColumn = new DataColumn("Eval", typeof(double), expression);
    loDataTable.Columns.Add(loDataColumn);
    loDataTable.Rows.Add(0);
    return (double)(loDataTable.Rows[0]["Eval"]);
}
4

3 回答 3

6

您正在耗尽可用的连接池,因为您正在为您解析的每个表达式和子表达式创建到数据库的连接,并且它们没有被及时清理以重新使用。

解决方案: 不要以递归方式或迭代方式或其他方式建立连接。为一个目的制作一个,然后使用它。如果您需要及时释放连接以重新使用它,请不要依赖类析构函数,因为它们不会在您希望它们运行时运行。

通常,尝试在其初始化程序中隐式分配有限外部资源(如连接)的类应该是非常静态的对象,并且您通常不希望在旨在像解析器一样动态创建对象的类中继承它们。

于 2013-06-14T18:41:32.980 回答
0

您是否尝试过延长超时时间?向连接字符串添加一个大超时,例如“Connect Timeout=1800”。当我收到此类消息时,这通常会对我有所帮助。

您可以看到的另一件事是您是否可以进一步改进查询。

于 2013-06-14T17:22:46.587 回答
0

您可以检查数据库的最大连接设置。还要检查当新连接尝试开始超时时打开了多少活动连接。

如何确定 ms sql server 2005 中打开/活动连接的总数

于 2013-06-14T18:41:38.717 回答