NHibernate: Создание ConnectionProvider, который динамически выбирает, к какой из нескольких баз данных подключаться?
У меня есть проект, который подключается ко многим базам данных SQL Server. Все они имеют одинаковую схему, но разные данные. Данные по существу отделены от клиента. Когда в приложение asp.net поступает запрос, он может сказать, какая база данных необходима, и устанавливает сеанс.
Сейчас мы создаем новую SessionFactory для каждой базы данных клиентов. Некоторое время это работало хорошо, но с большим количеством клиентов мы создаем больше баз данных. Мы начинаем сталкиваться с проблемами памяти, потому что каждая фабрика имеет свой собственный QueryPlanCache. Я написал пост о моей отладке памяти.
Я хочу сделать так, чтобы у нас был один SessionFactory, который использует ConnectionProvider для открытия соединения с нужной базой данных. То, что у меня до сих пор выглядит примерно так:
public class DatabaseSpecificConnectionProvider : DriverConnectionProvider
{
public override IDbConnection GetConnection()
{
if (!ThreadConnectionString.HasValue)
return base.GetConnection();
var connection = Driver.CreateConnection();
try
{
connection.ConnectionString = ThreadConnectionString.Value;
connection.Open();
}
catch(DbException)
{
connection.Dispose();
throw;
}
return connection;
}
}
Это прекрасно работает, если для обработки запроса требуется только одна база данных, поскольку я могу установить строку подключения в локальной переменной потока во время инициализации. Когда я сталкиваюсь с проблемами, когда у меня есть операция уровня администратора, которая должна получить доступ к нескольким базам данных.
Поскольку ConnectionProvider не знает, какой сеанс открывает соединение, он не может решить, какой использовать. Я мог бы установить локальную переменную потока перед открытием сеанса, но это имеет проблемы, так как соединения сеанса открываются лениво.
Мне также понадобится создать CacheProvider, чтобы избежать коллизий кеша. Это столкнется с подобной проблемой.
Так есть идеи? Или это просто просит слишком много от NHibernate?
Изменить: я нашел этот ответ, который предполагает, что я должен полагаться на какое-то глобальное состояние, что я хотел бы избежать. Если у меня активны несколько сеансов, я бы хотел, чтобы ConnectionProvider отвечал соединением с соответствующей базой данных.
Изменить 2: Я склоняюсь к решению, которое создаст ConnectionProvider для сеанса по умолчанию, который всегда используется для каждого сайта. А затем для соединений с дополнительными базами данных я бы открыл соединение и передал его. Недостатки этого я вижу в том, что я не могу использовать кэш второго уровня на вспомогательных сессиях, и мне придется отслеживать и закрывать соединение себя.
1 ответ
Я остановился на обходном пути и перечислю его здесь на случай, если кто-нибудь снова столкнется с этим.
Оказалось, что я не могу найти способ заставить базы данных ConnectionProvider изменять базы данных в зависимости от сеанса. Это может реально зависеть только от контекста текущего запроса.
В моем случае в 95% случаев потребуется только база данных одного клиента. Я создал SessionFactory и ConnectionProvider, который будет обрабатывать это. Для остальных угловых случаев я создал вторую SessionFactory, и когда я открываю Session, я передаю новое соединение.
Недостатком этого является то, что сеанс, который общается со второй базой данных, не может использовать кэш второго уровня, и я должен убедиться, что я закрыл соединение в конце запроса.
Кажется, сейчас это работает достаточно хорошо, но мне любопытно, насколько хорошо оно выдержит в долгосрочной перспективе.