服务热线
153 8323 9821
随着网站访问量的增加,在线用户实体信息的存储方式变得重要起来。存储在线用户的信息一般有这三种方案:
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> ///