我有一个cfc来处理用户对象。我的问题是:在会话中只存储user_id并在每次请求时重新创建用户对象更好吗?或者最好将整个用户对象存储在会话中?
以下是我的想法:
如果我将整个对象存储在会话中:
如果我只在会话中存储user_id:
这种事情是否有正常做法?我是在过度思考吗?
答案 0 :(得分:5)
我编写的所有CF应用都针对高流量和高可用性,因此我们从未考虑过单一服务器实践。
因此,根据我的经验,我总是需要a)允许多个负载均衡的服务器,以及b)出于多种原因避免负载均衡器上的粘性会话。因此,我们至少需要让服务器成为集群中的一部分,并获取会话中的流量。
因此,我们总是在每次请求时从共享数据存储中提取“会话”数据。
我的建议是实施会话门面。
这使您可以选择更改会话数据(如用户记录)的持久性,而无需更改应用程序的其余部分。
您可以在幕后选择将所有内容存储在会话范围内,为每个请求加载,执行混合,使用键值存储,等等。
您可以选择是否加载数据,延迟加载数据或其间的任何混合,并且应用程序的其余部分无需了解您已完成的操作。
如果您担心竞争条件,那么我建议在数据提交和访问时使用命名锁。这是使用外观的另一个好处 - 您的应用程序代码不需要知道这一点,您可以选择将锁定放在某些对象周围,而不是锁定整个会话。
答案 1 :(得分:2)
您尚未表明您是否使用了ORM,因此这是一般答案。
对于典型应用程序,我建议将用户对象实例化为会话范围。使用未包含在列表中的每个请求重新创建对象有一个很大的缺点:对用户对象的属性和状态的更改将不会在请求之间保持不变,除非您打算将用户对象的状态刷新到持久层(例如,数据库)每次点击。这可能是一个比对象实例化更昂贵的操作,它并不一定能让你免受你在ajax调用,竞争条件等方面所考虑的各种问题 - 它只是转移了你的表现形式。持久层的那些问题,你的对象的数据可能处于不可预测的状态。
由于每个新请求都是“隐式保存”,您还必须设计“短暂”对象,以便能够持久保存,无论它是否处于有效状态(想象多页表单的情况)修改了用户对象的某些方面。)
对于会话存储的对象,可以通过仔细的设计实践来减轻您对内存的担忧。例如,如果您的用户有很多任务,并且每个任务都有很多项,那么将所有这些对象实例化并组合到您的用户对象中可能是一个坏主意(即,延迟加载比预先加载更好)。< / p>
如果您真的必须能够动态更改CFC,即使使用会话存储的对象,您也可以实现这一目标。一种方法是在应用程序和会话中存储版本标志。对于每个请求,您的应用都会比较这些标记。当它们不同时,应用程序将运行会话重新加载例程,该例程快照当前属性,重建会话存储的对象,最后更新会话标志以匹配应用程序标志。
答案 2 :(得分:2)
这部分取决于Ken Redler的回答,但我没有足够的声誉来评论。
我们这样做以及我喜欢的方式是将Session中的用户数据存储为结构。然后在请求启动时,我们的Auth Model在Request范围内创建用户对象,并使用Session数据覆盖任何默认值。这有一些好处:
此外,如果您使用的是CF9,他们真正引以为傲的功能之一是它们对对象实例化的优化程度。如果还没有,请自己测试一下!
答案 3 :(得分:1)
取决于。
如果你有很多流量 - 在每分钟数千个独立访问者范围内 - 将User.cfc存储在会话中的内存开销最终会让你失望。这可以通过向其投入硬件(一段时间内更多内存,最终更多服务器和硬件负载平衡器)轻松克服。当然,人气是一个很好的问题。
如果您的数据库空间中似乎有CPU,网络或其他瓶颈,您可能希望将对象缓存在会话内存中,以便减少对数据库的命中。
为什么我会提到这些情景?您可能过早地进行了优化 - 不要修复您没有的问题。不要优化内存,CPU和数据库访问,直到问题出现或即将发生。
现在来自建筑最佳实践 - 而不是来自优化的“对我的处理器最好的东西” - 嗯,我只能说:取决于。
说实话,两种方式都不对。如果您发现自己需要在每个请求中检查数据库的凭据,请不要缓存它。如果您喜欢会话中对象的感觉,请将其缓存。因为您知道自己的域,所以您可以整天来回查看为什么应该或不应该在会话中缓存用户对象。如果它会让它变得更容易,那就去做吧。如果它会变得更难,那就不要。
我会警告你不要做一些令人难以置信的事情,或者对于看着你的应用程序的开发人员来说并不是很明显的事情 - 你写的越多,你必须永远维护的越多,你的同事关联的就越多以邪恶命名。
最后,最后一点,如果这是投票 - 我说你要缓存它。调用session.user.hasRole(“xyz”)之类的内容总是很有意义。