【问题标题】:NHibernate session management?NHibernate 会话管理?
【发布时间】:2009-07-19 16:08:30
【问题描述】:

首先,让我简要介绍一下场景。我正在编写一个简单的游戏,其中几乎所有的工作都在服务器端完成,并带有一个瘦客户端供玩家访问它。玩家登录或创建帐户,然后可以通过在网格中移动来与游戏互动。当他们进入一个单元格时,应该通知他们该单元格中的其他玩家,同样,该单元格中的其他玩家将被告知该玩家进入该单元格。还有许多其他的交互和动作可以发生,但不值得详细介绍它们,因为它们几乎相同。当玩家注销然后重新登录时,或者如果服务器关闭并重新启动,所有游戏状态都应该保持不变,尽管如果服务器崩溃,我失去 10 分钟左右的更改也没关系。

我决定使用 NHibernate 和 SQLite 数据库,所以我阅读了很多关于 NHibernate 的资料,学习了教程并编写了一些示例应用程序,但对于我应该如何做这件事感到非常困惑!

我的问题是:管理会话的最佳方式是什么?仅从我确实了解的少量内容来看,所有这些可能性都在我身上跳出来:

  • 拥有一个始终打开并供所有客户端使用的会话
  • 为每个连接的客户端设置一个会话并定期刷新它
  • 每次我必须使用任何持久化实体时打开一个会话,并在更新、插入、删除或查询完成后立即关闭它
  • 为每个客户端设置一个会话,但保持断开连接,仅在需要使用时重新连接
  • 与上述相同,但保持连接,仅在一段时间不活动后断开连接
  • 保持实体分离,仅每 10 分钟附加一次,例如,提交更改

考虑到每秒可能同时来自数百个客户端的许多更新、插入、删除和查询,并且它们都必须彼此一致,我应该使用哪种策略来获得良好的性能?

另一个小问题:我应该如何有效地使用事务?每个单独的更改都在自己的事务中是否可以,或者当我有数百个客户端都试图更改网格中的单元格时,这是否会表现不佳?我是否应该尝试弄清楚如何将类似的更新集中在一起并将它们放在一个事务中,或者这会不会太复杂?我什至需要大部分交易吗?

【问题讨论】:

    标签: c# database nhibernate transactions session


    【解决方案1】:

    我会为服务器的每个请求使用一个会话,每个会话一个事务。在应用成熟之前,我不会优化性能。

    回答你的解决方案:

    • 拥有一个始终打开且所有客户端都使用的单个会话:您将在此处遇到性能问题,因为该会话不是线程安全的,您必须锁定对该会话的所有调用。
    • 为每个连接并定期刷新它的客户端设置一个会话:您将在此处遇到性能问题,因为客户端使用的所有数据都将被缓存。您还会看到缓存中的陈旧数据存在问题。
    • 每次我必须使用任何持久化实体时打开一个会话,并在更新、插入、删除或查询完成后立即关闭它:这里不会有任何性能问题。缺点是可能存在并发或损坏数据问题,因为相关的 sql 语句不在同一个事务中执行。
    • 为每个客户端设置一个会话,但保持断开连接,仅在我需要使用它时重新连接:NHibernate 已经内置了连接管理,并且已经非常优化。
    • 同上,但保持连接,只有在一段时间不活动后才断开连接:会导致问题,因为 sql 连接数有限,也会限制应用程序的用户数。
    • 保持实体分离,仅每 10 分钟附加一次,例如,提交更改:由于分离实体中的数据过时,会导致问题。您必须自己跟踪更改,这会使您最终得到一段看起来像会话本身的代码。

    现在再详细说明也没用,因为我只会重复手册/教程/书籍。当您为每个请求使用一个会话时,您所描述的 99% 的应用程序可能都不会出现问题(也许根本不会)。 Session 是一个轻量级的非线程安全类,寿命很短。当您想确切了解会话/连接/缓存/事务管理的工作原理时,我建议您先阅读手册,而不是针对不清楚的主题提出一些更详细的问题。

    【讨论】:

    • 我不想优化它;我只是想弄清楚做这件事的不同方法是什么,它们通常有什么好处或坏处,它们的规模和性能如何等等,然后再投入使用。这是为了确保我不会做任何愚蠢的事情并选择一个合理合理的解决方案。不是性能调优。那么,至于您的答案,“请求”是什么意思-什么“请求”?你的意思是每次玩家做某事?
    • 是的,我的意思是“每次玩家做某事”或“从客户端到服务器的每次调用”
    • 阅读了您稍后添加的编辑内容,我对您所说的内容有一个疑问。关于每个客户端有一个会话,我认为 NHibernate 保证像 ISession.Find 这样的方法永远不会返回过时的数据。其次,您似乎不鼓励使用重新连接/断开连接,因为“NHibernate 已经具有内置的连接管理”,但手册在名为“具有自动版本控制的长会话”的并发示例中使用了它。
    • 1.您可以通过多种方式防止返回过时的数据,但此时您无法利用缓存。您不应该在正常情况下使用 ISession.Find。 2.手册中的连接管理不是关于数据库连接,而是通过会话连接来管理具有活动会话的分离对象,方法是不分离它们,而是重新创建它们。 3.我不明白你为什么一开始就在游戏场景中考虑长寿。
    【解决方案2】:

    阅读 NHibernate 文档的 page 上的“ISessionFactory”。 ISessions 是单线程的(即不是线程安全的),这可能意味着您不应该在用户之间共享它。 ISessionFactory 应该由您的应用程序创建一次,ISessions 应该为每个工作单元创建。请记住,创建ISessions 不一定会导致打开数据库连接。这取决于您的 SessionFactory 的连接池策略是如何配置的。

    您可能还想查看 Session and Transaction 上的 Hibernate 文档。

    【讨论】:

    • 链接已失效。
    【解决方案3】:

    我的目标是将所有内容保存在内存中,并且要么更改日志,要么定期进行离线快照。

    【讨论】:

    • 我已经考虑过这个解决方案,它会变得更加复杂,基本上复制了数据库提供给我的许多可靠性功能。这就是为什么我决定首先使用数据库,而不是仅仅将所有数据写入平面文件或其他东西。
    【解决方案4】:

    阅读NHibernate Best Practices with ASP.NET,这里有一些非常好的提示作为开始。如前所述,对 ISession 非常小心,因为它不是线程安全的,所以请记住这一点。

    如果您需要更复杂的东西,请查看NHibernate.Burrow contrib 项目。它指出“Burrow 提供的真正力量是 Burrow 对话可以跨越多个 http 请求”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-15
      • 1970-01-01
      • 2010-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多