【问题标题】:Coldfusion: is it better to keep just the user_id in the session, or the whole user object?Coldfusion:在会话中只保留 user_id 还是保留整个用户对象更好?
【发布时间】:2011-03-24 15:43:31
【问题描述】:

我有一个 cfc 来处理用户对象。我的问题是:在会话中只存储 user_id 并在每个请求中重新创建用户对象是否更好?还是将整个用户对象存储在会话中更好?

以下是我的想法:

  • 如果我将整个对象存储在会话中:

    • 可能会减少处理器开销
    • 可能会有更多的内存开销
    • 所有方法/函数都存储在实际对象中,除非用户注销并重新登录,否则我在 cfc 中更新的新函数将不可用,或者如果我设计了某种方法使其自行刷新。李>
    • 如果我通过并发 ajax 调用弄乱对象,则可能存在互斥锁或锁定问题
  • 如果我只在会话中存储 user_id:

    • 我必须为每个页面请求创建用户对象(可能会增加处理器开销)
    • 内存开销可能会减少
    • 不会出现互斥/锁定/竞争条件,因为每个请求都有自己的用户对象副本
    • 对 CFC 模型本身的更新将立即在整个系统中被识别,用户不必注销并重新登录

这种事情有正常的做法吗?我是不是想多了?

【问题讨论】:

  • 这取决于...如果您使用 ORM,请查看用户 cfc 的二级缓存。
  • @sam-farmer 使用继承自 user.cfc 的本土 ORM。我假设你在谈论 CF9 的内置 ORM,对吧?

标签: session coldfusion


【解决方案1】:

我编写的所有 CF 应用程序都针对高流量水平和高可用性,所以我们从来没有考虑过单服务器实践。

因此,根据我的经验,我总是必须 a) 允许多个负载平衡服务器,以及 b) 出于多种原因避免负载平衡器上的粘性会话。因此,我们至少需要让服务器成为运行中的集群的一部分并接收会话中的流量。

因此,我们总是在每次请求时从共享数据存储中提取“会话”数据。

我的建议是实现一个会话外观

这使您可以选择更改持久会话数据(如用户记录)的方式,而无需更改应用的其余部分。

您可以在幕后选择将所有内容存储在会话范围内,为每个请求加载它,进行混合,使用键值存储,等等。

您可以选择是预先加载数据,还是延迟加载数据,或者两者之间的任何混合,应用程序的其余部分不需要知道您做了什么。

关于比赛条件

如果您担心竞争条件,那么我建议您在数据提交和访问周围使用命名锁。这是使用外观的另一个好处 - 您的应用程序代码不需要知道这一点,您可以选择锁定某些对象,而不是锁定整个会话。

【讨论】:

  • +1 Facade 是个好建议;如果他正在运行一个大型应用程序,他肯定需要抽象。这是那些问题的答案之一,它的答案真的可以把你引向兔子洞。孔。但以一种好的方式。
【解决方案2】:

您还没有说明您是否使用 ORM,所以这是一个一般性的答案。

对于典型的应用程序,我建议将用户对象实例化到会话范围内。使用列表中未包含的每个请求重新创建对象有一个很大的缺点:除非您打算将用户对象的状态刷新到持久层(例如数据库)每次点击。这可能是一个比对象实例化更昂贵的操作,而且它并不一定会让你远离你正在考虑的关于 ajax 调用、竞争条件等的各种问题——它只是转移了持久层的这些问题,您的对象的数据可能处于不可预测的状态。

由于每个新请求都是“隐式保存”,因此您还必须设计“临时”对象,使其能够保持自身,无论它是否处于有效状态(想象一下多页表单的情况修改用户对象的某些方面)。

对于会话存储的对象,您可以通过仔细的设计实践来减轻您对内存的担忧。例如,如果您的用户有很多任务,并且每个任务都有很多项目,那么将所有这些对象实例化并组合到您的用户对象中可能是个坏主意(即,延迟加载将是比急切加载更好的方法)。

如果您确实必须能够动态更改 CFC,即使使用会话存储对象也可以实现该目标。一种方法是在应用程序和会话中都存储版本标志。对于每个请求,您的应用程序都会比较这些标志。当它们不同时,应用程序将运行会话重新加载例程,该例程对当前属性进行快照,重建会话存储的对象,最后更新会话标志以匹配应用程序标志。

【讨论】:

  • 到目前为止,您的最后一次编辑(最后一段)确实帮助您证明了这一点。
  • 虽然这里的所有答案都非常有帮助,但您的答案给了我最有用的信息,让我做出正确的决定。非常感谢!
【解决方案3】:

这部分来自 Ken Redler 的回答,但我没有足够的声誉来发表评论。

我们这样做的方式,以及我更喜欢的方式,是将用户数据作为结构存储在 Session 中。然后在请求开始时,我们的 Auth 模型在请求范围内创建用户对象,并使用 Session 数据覆盖任何默认值。这样做有几个优点:

  • 对数据库的访问更少,CPU 更少
  • 始终运行最新代码,无需复杂的自定义系统,以确保
  • 集群环境友好(Session中的复杂对象不能集群)
  • 可以添加或删除属性而不会损坏(假设您的用户对象只更新脏列)

另外,如果您使用的是 CF9,他们真正引以为豪的功能之一是他们对对象实例化的优化程度。如果还没有,请自行测试!

【讨论】:

    【解决方案4】:

    视情况而定

    如果您的流量很大(每分钟有数千个唯一身份访问者),那么在会话中存储 User.cfc 的内存开销最终会使您不堪重负。这可以通过向其投入硬件来轻松克服(一段时间内更多的内存,最终更多的服务器和硬件负载平衡器)。人气当然是个好问题。

    如果您的数据库空间似乎存在 CPU、网络或其他瓶颈,您可能希望将对象缓存在会话内存中,以减少对数据库的访问。

    我为什么要提到这些场景?您可能过早地进行优化 - 不要修复您没有的问题。不要优化您的内存、CPU 和数据库访问,直到这些问题出现或即将出现问题。

    现在来自架构最佳实践 - 而不是来自优化的“最适合我的处理器” - 好吧,我只能说:这取决于

    说实话,这两种方法都没有错。如果您发现自己需要针对每个请求检查数据库的凭据,请不要缓存它。如果您喜欢会话中对象的感觉,请缓存它。因为您知道自己的域,所以您可能整天都在反复讨论为什么应该或不应该在会话中缓存用户对象。如果它会让事情变得更容易,那就去做吧。如果它会让它变得更难,那就不要。

    我只是警告您不要做一些令人难以置信的复杂或任何对于查看您的应用程序的开发人员来说不是立即显而易见的事情 - 您编写的越多,您必须永远维护的越多,您的同事就越会将您的以邪恶命名。

    最后,最后一点,如果这是投票 - 我说你缓存它。调用 session.user.hasRole("xyz") 等是有道理的,而且总是感觉很好。

    【讨论】:

      猜你喜欢
      • 2021-01-30
      • 2018-05-22
      • 2014-08-28
      • 1970-01-01
      • 2017-09-21
      • 2013-05-04
      • 2013-04-21
      • 1970-01-01
      • 2011-11-18
      相关资源
      最近更新 更多