servicestack,C#,Mysql,Nhibernate,Fluent Nhibernate,servicestack" /> servicestack,C#,Mysql,Nhibernate,Fluent Nhibernate,servicestack" />

C# ServiceStack/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

我们似乎遇到了一个奇怪的问题,对我们服务的两个并发请求实际上使用了相同的数据库连接

我们的设置是ServiceStack+NHibernate+FluentNHibernate+MySQL。我已经设置了一个小测试来重现问题:

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
});
}
结果是一致的:

  • 打开的连接数<10
  • 并非所有记录都已更新
  • 如果我删除记录,有时会抛出一个
    StaleObjectStateException
  • 这背后的原因是连接被两个并发请求重用,而最后一个_INSERT_ID()给出了错误行的ID,因此两个请求正在更新同一行

    简言之:这是一个完全混乱的局面,它显然在请求之间共享数据库连接


    问题是:为什么?我应该如何配置,使每个请求都能从连接池获得自己的连接?

    最终解决了这个问题,真是浪费时间

    问题的根源是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"));
    
    从这里开始,即使没有事务,连接也会绑定到会话


  • 终于解决了,真是浪费时间

    问题的根源是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"));