会话 vs 单例模式

7

我有一个Web应用程序,希望从数据库中提取用户设置并存储以供全局访问。将数据存储在Singleton对象还是Session对象中更合适?这两者之间有什么区别?

将数据存储为对象引用还是将其拆分为值类型对象(int和string)更好?

5个回答

14

会话(Session)就是为了这个目的。会话存储在全局缓存中(基本上是一个单例),由会话ID作为键。这样,您只获取所需会话的数据。如果使用单例模式,就基本上是复制全局缓存,您将不得不重新发明机制来独立地检索每个会话的数据。

可以放心地存储对象。让会话负责将其序列化为可恢复的形式。但是,要小心放入会话中的内容。如果存储太多的数据,您将消耗大量内存(假设是一个基于内存的缓存)。


5

会话对象,毫无疑问。

单例存在于进程级别。这意味着,如果在任何给定时刻有20个用户访问您的站点,则它们使用相同的单例对象。如果您不经常进行Web开发,很难习惯这个概念。

会话存在于用户级别。这意味着您可以按用户而不是按进程存储数据。


应用程序状态是在ASP .Net进程级别上的单例模式的一个很好的例子。任何面向网站所有用户的轻量级键值对都可以存储在其中。这些键值对将在Web调用之间保持可访问性。对于重量级或资源密集型对象,应考虑使用缓存。 - RBT

4
如果这些设置将用于站点的所有用户,请将它们放在单例或应用程序缓存中。如果它们是每个用户特定的,请将它们放在会话中。
在添加到应用程序或会话缓存时使用对象引用 - 我相信值类型将被装箱,因此它们看起来像缓存中的对象。如果您使用单例,则可能会有不同的情况。

2
这是从一份旧文档中摘取的内容,但仍然非常有效且实用...我会把链接内容放在这里,特别是因为它是一个可能会消失的旧链接。从这里获取。 背景
ASP.Net中的Session对象可用于存储特定于站点每个用户的信息。Session按键名索引,当直接使用时,会导致大量单独的会话名称。相反的方法是创建一个单例对象来分组相关项目,并将该对象与给定的键名一起存储。"Singleton"是一种常见的设计模式,指定如何确保在任何时间只存在一个类的实例。
单例会话对象的优点
- 分组会话项以进行组织 - 对于像站点注册这样的短暂过程中的一系列页面特别有用。完成该过程后,可以清除对象以使内存得到回收(更好地利用服务器资源) - 更容易影响会话信息的变化分析 - 识别滥用信息的站点区域(比仅使用变量名称确定是否适合使用要清晰得多) - 访问对象后属性名称和类型的Intellisense 单例会话对象的缺点
- 更难看到会话中单独项目的数量 - ASP.Net跟踪结果不显示对象内部的值 - 在使用进程外会话状态存储时性能下降(影响序列化)
实施
第一步是创建一个表示应一起存储的项的逻辑分组的类文件。以下是演示该技术的示例类:
public class singleton
{
  //Name that will be used as key for Session object
  private const string SESSION_SINGLETON = "SINGLETON";

  //Variables to store the data (used to be individual
  // session key/value pairs)
  string lastName = "";
  string firstName = "";

  public string LastName
  {
    get
    {
      return lastName;
    }
    set
    {
      lastName = value;
    }
  }

  public string FirstName
  {
    get
    {
      return firstName;
    }
    set
    {
      firstName = value;
    }
  }

  //Private constructor so cannot create an instance
  // without using the correct method.  This is 
  // this is critical to properly implementing
  // as a singleton object, objects of this
  // class cannot be created from outside this
  // class
  private singleton()
  {
  }

  // Create as a static method so this can be called using
  // just the class name (no object instance is required).
  // It simplifies other code because it will always return
  // the single instance of this class, either newly created
  // or from the session
  public static singleton GetCurrentSingleton()
  {
    singleton oSingleton;

    if (null == System.Web.HttpContext.Current.Session[SESSION_SINGLETON])
    {
      //No current session object exists, use private constructor to 
      // create an instance, place it into the session
      oSingleton = new singleton();
      System.Web.HttpContext.Current.Session[SESSION_SINGLETON] = oSingleton;
    }
    else
    {
      //Retrieve the already instance that was already created
      oSingleton = (singleton)System.Web.HttpContext.Current.Session[SESSION_SINGLETON];
    }

    //Return the single instance of this class that was stored in the session
    return oSingleton;
  }
}

想要使用这个对象的页面只需要执行以下操作:

singleton oSingleton = singleton.GetCurrentSingleton();
oSingleton.FirstName = "Robert";
oSingleton.LastName = "Boedigheimer";

通常,这种技术将在给定类中存储更多的变量,或用于执行流程的一系列网页。在网站上使用此技术进行过程操作的另一个优点是,通过简单地删除对单例对象的引用,可以清除会话变量所需的所有内存。该类可以实现一个方法,使客户端可以使用它来清除引用,可以将其命名为Dispose(),以遵循典型的.NET模式,当一个类提供清理方式时。
public static void Dispose()
{
    //Cleanup this object so that GC can reclaim space
    System.Web.HttpContext.Current.Session.Remove(SESSION_SINGLETON);
}

结论

使用存储在Session对象中的单例对象比使用单独的会话键来存储信息有许多优点。这对于那些需要在整个会话期间存在的对象非常有用(分组逻辑项、影响分析、智能感知等),尤其是对于那些只需要在网站上的某个时间段内使用,直到用户完成特定流程的对象而言(这样可以更容易地识别变量的误用,并在流程完成但会话仍在继续时节省资源)。


1
有时我喜欢下面这种方法。它解决了魔法字符串和未设置会话变量的问题。它也在会话级别而不是应用程序级别运行单例模式。
public static SessionHandler GetInstance()
    {
        if (HttpContext.Current.Session["SessionHandler"] == null)
        {
            HttpContext.Current.Session["SessionHandler"] = new SessionHandler();
        }
        return (SessionHandler)HttpContext.Current.Session["SessionHandler"];
    }

然后将其用作普通的单例。放入你需要的变量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接