2

データベース接続を実装する基本クラスがあります。この基本データベース クラスを継承する 2 番目のクラスがあります。2 番目のクラスには内部に再帰があり、その値を評価するときに、2 番目のクラスの別のインスタンスをインスタンス化する場合があります。再帰の深さはわずか数レベルです。すべてをシングルスレッドで実行しています。

私のコードは約 1 ~ 2 分間正しく実行されますが、その後、「タイムアウトが期限切れになりました。プールから接続を取得する前にタイムアウト期間が経過しました」という一貫したエラーが発生し始めます。

私の基本クラスには、データベース オブジェクトで .Dispose() メソッドを呼び出すデストラクタがあります。私の 2 番目のクラスには、基本クラスの接続オブジェクトを閉じるデストラクタがあります。

データベースへの接続文字列で、接続タイムアウト = 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

解析するすべての Expression および Sub-Expression に対してデータベースへの接続を作成しているため、使用可能な接続のプールを使い果たしています。

解決策: 接続を再帰的に、または反復的に作成しないでください。1つの目的のために1つを作成し、それを使用してください。また、接続を再利用するために時間内に接続を解放する必要がある場合は、必要なときに実行されないため、クラス デストラクタに依存しないでください

一般に、限られた外部リソース (接続など) を初期化子で暗黙的に割り当てようとするクラスは、かなり静的なオブジェクトである必要があり、通常、パーサーのように動的にオブジェクトを作成することを目的としたクラスでそれらを継承したくないことは確かです。

于 2013-06-14T18:41:32.980 に答える
0

データベースの最大接続設定を確認してください。また、新しい接続の試行がタイムアウトし始めたときに、開いているアクティブな接続の数も確認してください。

ms sql server 2005 で開いている/アクティブな接続の総数を確認する方法

于 2013-06-14T18:41:38.717 に答える