我有一个连接到许多SQL Server数据库的项目。它们都具有相同的模式,但数据不同。数据基本上由客户分开。当请求进入asp.net应用程序时,它可以告诉需要哪个数据库并设置会话。
我们现在正在做的是为每个客户数据库创建一个新的SessionFactory。这已经好了一段时间,但随着更多的客户,我们正在创建更多的数据库。我们开始遇到内存问题,因为每个工厂都有自己的QueryPlanCache。 I wrote a post about my debugging of the memory
我想这样做,以便我们有一个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那里要求太多了?
编辑:我发现this answer that suggests I'd have to rely on some global state这是我想避免的。如果我有多个活动会话,我希望ConnectionProvider通过与相应数据库的连接进行响应。
编辑2:我倾向于为每个网站始终使用的默认会话创建ConnectionProvider的解决方案。然后,为了连接到其他数据库,我打开连接并传入它。我可以看到的缺点是我不能在辅助会话上使用二级缓存,我将不得不跟踪和关闭连接自己。
答案 0 :(得分:1)
我已经确定了一种解决方法,我将其列在此处,以防有人再次遇到此问题。
事实证明,无论如何我无法根据会话使ConnectionProvider更改数据库。它实际上只能取决于当前请求的上下文。
就我而言,95%的时间只需要一个客户的数据库。我创建了一个SessionFactory和一个可以处理它的ConnectionProvider。对于剩下的极端情况,我创建了第二个SessionFactory,当我打开Session时,我传入一个新的Connection。
缺点是与第二个数据库通信的会话不能使用二级缓存,我必须确保在请求结束时关闭连接。
现在似乎运作良好,但我很好奇它从长远来看会有多好。