Есть ли способ сохранить соединения с БД открытыми и готовыми к использованию во время выполнения?
Наш сервис WCF должен поддерживать связь таким образом.
Теперь у нас есть код, похожий на этот кусок кода:
// This is the class of objects that has connections within.
[DataContract]
public class SomeObj
{
[DataMember]
public string Name { get; set; }
public OracleConnection Conn { get; set; }
}
// Dictionary of SomeObjs
private static Dictionary<string, SomeObj> myObjs = new Dictionary<string, SomeObj>();
Когда служба запускается, она также соединяет все базы данных из собственных файлов конфигурации со строками подключения внутри. Но, как вы знаете, соединения могут стать поврежденными и непригодными для использования или даже быть недоступными в конце. Поэтому для устранения этой проблемы у нас есть специальный таймер, который проверяет все соединения в конфигурации:
// Setup timer method. Timer will fire every minute.
static private void CreateTimer()
{
Timer Timer1 = new System.Timers.Timer();
Timer1.Enabled = true;
Timer1.Interval = 60000;
Timer1.Elapsed += new System.Timers.ElapsedEventHandler(Timer1_Elapsed);
}
static private void Timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Parallel.ForEach(Program.config.Root.Elements("databases"), el =>
{
try
{
Program.OpenConnection(el.Attribute("name").Value);
}
catch (Exception exc)
{
Console.WriteLine(DateTime.Now.ToString() + " " + exc);
}
});
// This is old way we checks connections consistently
//foreach (XElement element in Program.config.Root.Elements("databases"))
//{
// try
// {
// AServ.OpenConnection(el.Attribute("name").Value);
// }
// catch (Exception exc)
// {
// Console.WriteLine(DateTime.Now.ToString() + " " + exc);
// }
//}
}
public static bool OpenConnection(string name)
{
// if connections exactly doesn't exists
if (!myObjs.ContainsKey(name))
{
XElement el = (from t in config.Root.Elements("databases")
where t.Attribute("name").Value == name
select t).FirstOrDefault();
if (el == null)
{
lock (myObjs)
{
myObjs.Remove(name);
}
return false;
}
lock (myObjs)
{
myObjs.Add(name, new SomeObj { Conn = new OracleConnection { ConnectionString = el.Attribute("connectionString").Value } }, Name = el.Attribute("name").Value);
}
}
// if connection broken
if ((myObjs[name].Conn.State != ConnectionState.Open || !myObjs[name].Conn.Ping()) && myObjs.ContainsKey(name))
{
try
{
// Trying to get it alive
lock (myObjs)
{
myObjs[name].Conn.Close();
myObjs[name].Conn.Open();
}
}
catch (Exception e)
{
if (!myObjs.ContainsKey(name))
return false;
lock (myObjs)
{
myObjs.Remove(name);
}
return false;
}
Console.WriteLine(DateTime.Now.ToString() + " " + myObjs[name].Conn.ConnectionString);
}
return true;
}
И еще одна вещь, которую вы должны знать, ребята, как мы используем хранение соединений в самом методе:
private static int GetParameterValue(string name, int id)
{
// if we don't get parameter value at the moment because broken connection
if (!OpenConnection(name))
return -1;
// assuming connection is OK and getting the parameter value
string parameterQuery = @"select GetInfo(:id) from dual";
OracleCommand parameterCommand = new OracleCommand(parameterQuery, myObjs[name].Conn);
parameterCommand.Parameters.Add("id", id);
return Convert.ToInt32(parameterCommand.ExecuteScalar());
}
Проблема в в том, что иногда первая проверка таймера не может быть выполнена вовремя, а вторая проверка таймера начинается, пока выполняется первая . Это дает некоторые странные ошибки с утечками памяти кучи (я так думаю). Другая проблема заключается в в том, что даже мы разрабатываем шаблон одноэлементного проектирования, чтобы иметь только одну проверку во времени, проверка может зависнуть, а другие проверки никогда не будут запущены (потому что открытие соединения занимает много времени с завышенной ценой для некоторых баз данных. Не знаю, почему это происходит, но мы пытались добавить Connection timeout=30;
, но, честно говоря, я не помню, давал ли он правильный результат или нет. Конечно, нет.)
Тогда этот сервис, запущенный во времени, занимает столько памяти, сколько он работает. Я пробовал много манипуляций с этим кодом, даже однажды столкнулся с мертвыми блокировками где-то в коде (почти 100% загрузка процессора).
Да, я знаю о пуле ADO .NET, но мы не можем его использовать, потому что у нас огромная база унаследованного кода, которая работает, как показано выше, и должна каким-то образом улучшить существующую логику проверки.
Так скажите мне, что вы думаете, как мы можем установить живое соединение во времени без объединения?
Мне нужен какой-то способ, который может использовать как можно меньше памяти (существующий код требует больше памяти, чем работает), и работать быстро с небольшими изменениями кода.
Любая помощь очень ценится! Очень надеюсь на вашу помощь в работе с stackoverflow!
Я думаю об использовании специального потока, который будет проверять соединения в цикле с Thread.Sleep(60000)
в конце. Но я не уверен в этом.
Поставщик ADO .NET Devart dotConnect для Oracle . База данных Oracle 9-11 (зависит от сервера), C # .NET Framework 4.