C# ServiceStack/FluentNHibernate/MySQL-两个并发请求使用的相同连接
我们似乎遇到了一个奇怪的问题,对我们服务的两个并发请求实际上使用了相同的数据库连接 我们的设置是ServiceStack+NHibernate+FluentNHibernate+MySQL。我已经设置了一个小测试来重现问题:C# ServiceStack/FluentNHibernate/MySQL-两个并发请求使用的相同连接,c#,mysql,nhibernate,fluent-nhibernate,
servicestack,C#,Mysql,Nhibernate,Fluent Nhibernate,
servicestack,我们似乎遇到了一个奇怪的问题,对我们服务的两个并发请求实际上使用了相同的数据库连接 我们的设置是ServiceStack+NHibernate+FluentNHibernate+MySQL。我已经设置了一个小测试来重现问题: public class AppHost : AppHostBase { private ISessionFactory _sessionFactory; public AppHost() : base("Lala Service", typeof(App
public class AppHost : AppHostBase
{
private ISessionFactory _sessionFactory;
public AppHost() : base("Lala Service", typeof(AppHost).Assembly)
{
}
public override void Configure(Container container)
{
_sessionFactory = Fluently.Configure()
.Database(MySQLConfiguration.Standard.ConnectionString(conn =>
conn.Server("localhost").Username("lala").Password("lala").Database("lala")))
.Mappings(mappings => mappings.AutoMappings.Add(
AutoMap.Assembly(GetType().Assembly).Where(t => t == typeof(Lala))
.Conventions.Add(DefaultLazy.Never(), DefaultCascade.All())))
.BuildSessionFactory();
container.Register(c => _sessionFactory.OpenSession()).ReusedWithin(ReuseScope.Request);
}
}
我通过Ajax同时点击了该服务10次,如下所示:
<script type="text/javascript">
for (i = 0; i < 10; i++) {
console.log("aa");
$.ajax({
url: '/lala',
dataType: 'json',
cache: false
});
}
</script>
对于(i=0;i<10;i++){
控制台日志(“aa”);
$.ajax({
url:“/lala”,
数据类型:“json”,
缓存:false
});
}
结果是一致的:
StaleObjectStateException
问题是:为什么?我应该如何配置,使每个请求都能从连接池获得自己的连接?最终解决了这个问题,真是浪费时间 问题的根源是NHibernate的: 11.7. 连接释放模式 NHibernate关于ADO.NET的遗留(1.0.x)行为 连接管理是指ISession将获得连接 当它第一次被需要的时候,然后保持连接直到 会议闭幕。NHibernate引入了连接的概念 释放模式,告诉会话如何处理其ADO.NET连接。 ... 不同的释放模式由 NHibernate.ConnectionReleaseMode:
- OnClose-本质上是上述遗留行为。这个 NHibernate会话在第一次需要执行时获得连接 某些数据库访问并保持该连接,直到会话结束 关门了
- 后传输-表示在传输结束后释放连接 NHibernate.ITransaction已完成
- 交易后-表示使用 ConnectionReleaseMode.AfterTransaction注意 ConnectionReleaseMode.AfterTransaction,如果会话被认为是 处于自动提交模式(即未启动任何事务)连接 将在每次操作后释放
LAST\u INSERT\u ID()
是一个bug。它应该在同一“操作”中调用LAST\u INSERT\u ID()
无论如何,解决方案:
使用我们通常使用的事务,或者
如果出于某种原因,您不能或不想在特定上下文中使用事务(这就是今天使用的情况),请将连接释放模式设置为“on close”。使用FluentNHibernate,即:
.ExposeConfiguration(cfg =>
cfg.SetProperty("connection.release_mode", "on_close"));
从这里开始,即使没有事务,连接也会绑定到会话
终于解决了,真是浪费时间
问题的根源是NHibernate的:
11.7. 连接释放模式
NHibernate关于ADO.NET的遗留(1.0.x)行为
连接管理是指ISession将获得连接
当它第一次被需要的时候,然后保持连接直到
会议闭幕。NHibernate引入了连接的概念
释放模式,告诉会话如何处理其ADO.NET连接。
...
不同的释放模式由
NHibernate.ConnectionReleaseMode:
- OnClose-本质上是上述遗留行为。这个
NHibernate会话在第一次需要执行时获得连接
某些数据库访问并保持该连接,直到会话结束
关门了
- 后传输-表示在传输结束后释放连接
NHibernate.ITransaction已完成
使用配置参数hibernate.connection.release\u mode
指定要使用的发布模式
- 交易后-表示使用
ConnectionReleaseMode.AfterTransaction注意
ConnectionReleaseMode.AfterTransaction,如果会话被认为是
处于自动提交模式(即未启动任何事务)连接
将在每次操作后释放
这与MySQL.NET/Connector的默认连接池纠缠在一起,实际上意味着连接在并发请求之间交换,因为一个请求将连接释放回池,而另一个请求获取了连接
但是,我认为NHibernate在释放并重新获取连接后调用LAST\u INSERT\u ID()
是一个bug。它应该在同一“操作”中调用LAST\u INSERT\u ID()
无论如何,解决方案:
使用我们通常使用的事务,或者
如果出于某种原因,您不能或不想在特定上下文中使用事务(这就是今天使用的情况),请将连接释放模式设置为“on close”。使用FluentNHibernate,即:
.ExposeConfiguration(cfg =>
cfg.SetProperty("connection.release_mode", "on_close"));
从她那里
.ExposeConfiguration(cfg =>
cfg.SetProperty("connection.release_mode", "on_close"));