在线用户实体缓存解决方案
来源:互联网 发布:淘宝c店年末计划 编辑:程序博客网 时间:2024/06/10 13:46
文章来源:IT工程技术网 http://www.systhinker.com/html/61/n-11661.html
随着网站访问量的增加,在线用户实体信息的存储方式变得重要起来。存储在线用户的信息一般有这三种方案:
1、用户的实体信息保存在Session里,简单方便,随着Session的过期用户信息自动过期。
2、用户信息保存在数据库中,用一个表存储在线的用户信息。
3、用户信息保存在内存。
当前项目用的是第一种方法,把用户的实体信息保存在Session中,虽然使用方便,但总感觉很别扭。Discuz!NT使用的是第二种方法,把在线用户标识保存在一个表中,从cookie跟读取用户的ID,并从用户信息表查询该用户的信息,组装到实体中。如果有大量的用户在线同时操作时,这也不是一个很好的解决办法。
这里选择第三种解决方案,把用户信息保存到内存。
我们使用Dictionary来存储用户信息,由于Dictionary不是线程安全的,因此需要注意只能单线程更新字典。
先定义一个保存用户信息的实体:
internal class UserEntity<T>{ /// <summary> /// 用户信息 /// </summary> internal T UserInfo { get; set; } /// <summary> /// 添加到列表的时间戳 /// </summary> internal DateTime Timestamp { get; set; }}
使用泛型包装用户实体,并增加一个时间戳,表示该用户信息添加到内存的时间,过期是根据这个时间来判断的。
再增加一个在线用户信息管理类:
/// <summary>/// 在线用户缓存管理/// </summary>/// <typeparam name="T"></typeparam>public class UserCacheManager<T>{ #region 静态属性 /// <summary> /// 静态用户缓存表 /// </summary> private static Dictionary<long, UserEntity<T>> _UserList = new Dictionary<long, UserEntity<T>>(); /// <summary> /// 过期时间 /// </summary> private static int _ExpiredMinutes = 30; /// <summary> /// 定时器 /// </summary> private static Timer _Timer = null; #endregion #region 静态构造函数 /// <summary> /// 静态构造函数 /// 初始化计时器 /// </summary> static UserCacheManager() { _Timer = new Timer(new TimerCallback(TimerClear), null, 60000, _ExpiredMinutes * 60000); } #endregion #region 私有方法 /// <summary> /// 清除在线用户 /// </summary> /// <param name="sender"></param> private static void TimerClear(object sender) { ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncClear)); } /// <summary> /// 异步清除过期的在线用户 /// </summary> /// <param name="sender"></param> private static void AsyncClear(object sender) { //当前时间 DateTime timestamp = DateTime.Now.AddMinutes(0 - _ExpiredMinutes); //过期的用户列表 var expiredUserList = (from userEntity in _UserList where userEntity.Value.Timestamp <= timestamp select userEntity); if (expiredUserList != null && expiredUserList.Count() > 0) { List<long> expiredUserIdentities = expiredUserList.Select(o => o.Key).ToList(); lock (_UserList) { foreach (long userId in expiredUserIdentities) _UserList.Remove(userId); } } } #endregion #region 公共方法 /// <summary> /// 增加在线用户 /// </summary> /// <param name="userIdentity">用户身份标识</param> /// <param name="userInfo">用户实体</param> public static void Add(long userIdentity, T userInfo) { lock (_UserList) { #region 创建用户实体 UserEntity<T> userEntity = new UserEntity<T> { Timestamp = DateTime.Now, UserInfo = userInfo }; #endregion if (_UserList.Keys.Contains(userIdentity)) { _UserList[userIdentity] = userEntity; } else { _UserList.Add(userIdentity, userEntity); } } } /// <summary> /// 获取用户信息 /// </summary> /// <param name="userIdentity"></param> /// <returns></returns> public static T Get(long userIdentity) { lock (_UserList) { if (_UserList.Keys.Contains(userIdentity)) { _UserList[userIdentity].Timestamp = DateTime.Now; return _UserList[userIdentity].UserInfo; } else { return default(T); } } } /// <summary> /// 移除用户缓存信息 /// </summary> /// <param name="userIdentity"></param> public static void Remove(long userIdentity) { if (_UserList.Keys.Contains(userIdentity)) { lock (_UserList) { _UserList[userIdentity].Timestamp = DateTime.Now.AddDays(-1); } } } #endregion}
Dictionary<long, UserEntity<T>> _UserList用来保存在线的用户列表。
在静态构造函数中声明了一个定时器,定时器负责清理过期的用户信息。并把清理用户信息的方法装入线程池执行。
MSDN:只要不修改Dictionary,Dictionary就可以同时支持多个阅读器。即便如此,从头到尾对一个集合进行枚举本质上并不是一个线程安全的过程。当出现枚举与写访问互相争用这种极少发生的情况时,必须在整个枚举过程中锁定集合。若允许多个线程对集合执行读写操作,您必须实现自己的同步。
所以在更新Dictionary中,都锁定了字典,防止多线程冲突。
文章来源:IT工程技术网 http://www.systhinker.com/html/61/n-11661.html
- 在线用户实体缓存解决方案
- 在线用户实体缓存解决方案(转)
- [ASP.NET]在线用户解决方案
- 一个统计当前在线用户的解决方案
- 基于Redis的在线用户列表解决方案
- 基于Redis的在线用户列表解决方案
- DropdownList用户使用缓存的解决方案
- asp.net中用户唯一在线的经典解决方案
- [项目回顾]基于Redis的在线用户列表解决方案
- 基于Redis的在线用户列表解决方案 (12)
- 实体类缓存
- 一个统计当前在线用户的解决方案,可以在聊天室、论坛、网站中使用
- 一个统计当前在线用户的解决方案,可以在聊天室、论坛、网站中使用
- 一个统计当前在线用户的解决方案,可以在聊天室、论坛、网站中使用
- .net C# 利用session控制用户重复登录及统计在线用户数解决方案
- session 缓存和实体对象
- 在线Office文档解决方案
- 缓存雪崩,缓存穿透解决方案
- hdu 1466 计算直线的交点数
- STL copy函数
- [转载]软件企业如何制定软件质量工作方针
- 准备搬家了
- hdu 1465 不容易系列之一
- 在线用户实体缓存解决方案
- CO CASE STUDY
- 8086 汇编指令速查手册
- discuz的安装
- 工作邮件的使用建议与说明
- 利用 DataGridView 绘制图片列表(从Access读取图片)
- 8086寄存器分类
- 利用 DataGridView 绘制图片列表(从Access读取图片)
- 【小阅读^大脑袋】0521 NO.366