传统的会话管理是用一个session表保存会话信息,每次请求时读取、写入该表。

public function read($sessID) {
$hander = is_array($this->hander)?$this->hander[1]:$this->hander;
$res = mysql_query("SELECT data AS data FROM ".$this->sessionTable." WHERE sid = '$sessID' AND expire >".time(),$hander);
if($res) {
$row = mysql_fetch_assoc($res);
return $row['data'];
}
return "";
} public function write($sessID,$sessData) {
$hander = is_array($this->hander)?$this->hander[0]:$this->hander;
$expire = time() + $this->lifeTime;
mysql_query("REPLACE INTO ".$this->sessionTable." ( sid, expire, data) VALUES( '$sessID', '$expire', '$sessData')",$hander);
if(mysql_affected_rows($hander))
return true;
return false;
}

session表的expire是一个时间戳,每次请求时更新。使用此栏位可以清理会话。

public function gc($sessMaxLifeTime) {
$hander = is_array($this->hander)?$this->hander[0]:$this->hander;
mysql_query("DELETE FROM ".$this->sessionTable." WHERE expire < ".time(),$hander);
return mysql_affected_rows($hander);
}

Redis的处理方式

首先看一个JAVA方法:

public void updateToken(Jedis conn, String token, String user, String item) {
long timestamp = System.currentTimeMillis() / 1000;
conn.hset("login:", token, user);
conn.zadd("recent:", timestamp, token);
if (item != null) {
conn.zadd("viewed:" + token, timestamp, item);
}
}

login是一个哈希表,它的目的是记录所有在线用户,等同session表的记录。

recent是一个有序集合,目的是记录会话的最新访问时间,类似session表的expire字段。使用这个集合,可以对长时间没有请求的会话做清理。

viewed也是一个有序集合,存放访问历史,与session表的data字段作用相同。

如果viewed集合不清理,随着用户浏览的商品越多,集合会不断的增大,必须做清理处理。这里的处理方式是保持viewed集合只有25笔,其它的都删除,按照浏览时间排序,保存最新的25笔。看看修改后的updateToken()方法:

public void updateToken(Jedis conn, String token, String user, String item) {
long timestamp = System.currentTimeMillis() / 1000;
conn.hset("login:", token, user);
conn.zadd("recent:", timestamp, token);
if (item != null) {
conn.zadd("viewed:" + token, timestamp, item);
conn.zremrangeByRank("viewed:" + token, 0, -26); //只保留最后25笔
}
}

随着时间的推移,会话越来越多,为了限制会话数量,我们决定只保留最新的1000万个会话。rencent集合记录了每个会话的最后访问时间,可以以此为清理条件。

public class CleanSessionsThread
extends Thread
{
private Jedis conn;
private int limit;
private boolean quit; public CleanSessionsThread(int limit) {
this.conn = new Jedis("localhost");
this.conn.select(15);
this.limit = limit;
} public void quit() {
quit = true;
} public void run() {
while (!quit) {
long size = conn.zcard("recent:");
if (size <= limit){
try {
sleep(1000);
}catch(InterruptedException ie){
Thread.currentThread().interrupt();
}
continue;
} // 每次最多清理100个会话
long endIndex = Math.min(size - limit, 100); // recent是按照访问时间从小到大排列的
Set<String> tokenSet = conn.zrange("recent:", 0, endIndex - 1); String[] tokens = tokenSet.toArray(new String[tokenSet.size()]); ArrayList<String> sessionKeys = new ArrayList<String>();
for (String token : tokens) {
sessionKeys.add("viewed:" + token);
} conn.del(sessionKeys.toArray(new String[sessionKeys.size()]));
conn.hdel("login:", tokens);
conn.zrem("recent:", tokens);
}
}
}

有时候我们会统计访问最多的商品,每次访问商品时做一个计数。使用有序集合的特性,将所有商品加入到有序集合,访问一次该商品将就该商品的权值-1,访问越多,权值就越小。有序集合会按照权值从小到大排序,访问最多的商品就会排在最前面。

public void updateToken(Jedis conn, String token, String user, String item) {
long timestamp = System.currentTimeMillis() / 1000;
conn.hset("login:", token, user);
conn.zadd("recent:", timestamp, token);
if (item != null) {
conn.zadd("viewed:" + token, timestamp, item);
conn.zremrangeByRank("viewed:" + token, 0, -26); //只保留最后25笔
conn.zincrby("viewed:", -1, item); // 商品访问有序集合,访问越多,权值越小,在集合中月靠前
}
}

同理,viewed集合也需要定时的清理,不然该集合会不断的增大,最后将把所有的商品都包含在里面。我们单独开一个进程来清理viewed集合。

public class CleanViewedThread
extends Thread
{
private Jedis conn;
private int limit;
private boolean quit; public CleanViewedThread(int limit) {
this.conn = new Jedis("localhost");
this.conn.select(15);
this.limit = limit;
} public void quit() {
quit = true;
} public void run() {
while (!quit) {
long size = conn.zcard("viewed:");
if (size <= limit){
try {
sleep(1000);
}catch(InterruptedException ie){
Thread.currentThread().interrupt();
}
continue;
} // 每次最多清理100笔
long endIndex = Math.min(limit + 100, size); Set<String> viewedSet = conn.zrange("viewed:", limit, endIndex - 1);
conn.zrem("viewed:", viewedSet.toArray(new String[viewedSet.size()]));
}
}
}

Spring in action - 会话管理的更多相关文章

  1. 使用Spring Session做分布式会话管理

    在Web项目开发中,会话管理是一个很重要的部分,用于存储与用户相关的数据.通常是由符合session规范的容器来负责存储管理,也就是一旦容器关闭,重启会导致会话失效.因此打造一个高可用性的系统,必须将 ...

  2. Spring in action记录

    最近一段时间重新学习了一遍SPRING,现在对这些笔记整理一下,一来算是对之前的学习有一个交代,二来当是重新学习一次,三来可以留下备份 这次学习中以SPRING IN ACTION 4这学习资料,整书 ...

  3. 十、 Spring Boot Shiro 权限管理

    使用Shiro之前用在spring MVC中,是通过XML文件进行配置. 将Shiro应用到Spring Boot中,本地已经完成了SpringBoot使用Shiro的实例,将配置方法共享一下. 先简 ...

  4. Spring Boot Shiro 权限管理 【转】

    http://blog.csdn.net/catoop/article/details/50520958 主要用于备忘 本来是打算接着写关于数据库方面,集成MyBatis的,刚好赶上朋友问到Shiro ...

  5. (39.1) Spring Boot Shiro权限管理【从零开始学Spring Boot】

    (本节提供源代码,在最下面可以下载)距上一个章节过了二个星期了,最近时间也是比较紧,一直没有时间可以写博客,今天难得有点时间,就说说Spring Boot如何集成Shiro吧.这个章节会比较复杂,牵涉 ...

  6. Spring Boot Shiro 权限管理

    Spring Boot Shiro 权限管理 标签: springshiro 2016-01-14 23:44 94587人阅读 评论(60) 收藏 举报 .embody{ padding:10px ...

  7. SpringMVC整合Shiro,Shiro是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理等功能

    SpringMVC整合Shiro,Shiro是一个强大易用的Java安全框架,提供了认证.授权.加密和会话管理等功能. 第一步:配置web.xml <!-- 配置Shiro过滤器,先让Shiro ...

  8. java的会话管理:Cookie和Session

    java的会话管理:Cookie和Session 1.什么是会话 此处的是指客户端(浏览器)和服务端之间的数据传输.例如用户登录,购物车等 会话管理就是管理浏览器客户端和服务端之间会话过程产生的会话数 ...

  9. spring in action 4th --- quick start

    读spring in action. 环境搭建 quick-start依赖注入 面向切面 1.环境搭建 jdk1.8 gradle 2.12 Intelij idea 2016.2.1 1.1创建一个 ...

随机推荐

  1. Python 基礎 - 集合的使用

    集合是一個無序的,不重複的數據組合,主要的作用如下 去重,把一個列表變成集合,就會自動去重了. 關係測試,測試二組數據之前的交集.差集.聯集等關係. 接下來我們來實作看看什麼是去重 #!/usr/bi ...

  2. Java笔记7-多态父类静态

    多态的应用-面向父类编程 1.对象的编译时类型写成父类 2.方法的返回类型写成父类 3.方法的参数类型写成父类 编译时类型:对象的声明时类型,在于编译期间 运行时类型:new运算符后面的类型 编译时类 ...

  3. ready和onload的区别

    $(document).ready()和window.onload在表面上看都是页面加载时我们就去执行一个函数或动作,但是在具体的细节上$(document) ready()和window onloa ...

  4. jQuery中的Ajax几种请求方法

    在网上查的几种Ajax的请求的方法: jQuery 确实是一个挺好的轻量级的JS框架,能帮助我们快速的开发JS应用,并在一定程度上改变了我们写JavaScript代码的习惯.废话少说,直接进入正题,我 ...

  5. Android驱动开发前的准备(四)

    源代码的下载和编译 4.1 下载.编译和测试Android源代码 4.2下载和编译linux内核源代码 4.1.1 配置Android源代码下载环境 (1) 创建一个用于存放下载脚本文件的目录 # m ...

  6. uart启示2_异步操作的bug

    发现代码中的隐藏bug真的是一件令人振奋的事情,当然也会疲倦那么一下午! 这个bug只有在一种在一个2604计数周期的一种情况下发生,所以即使是大量的仿真,未必也会发现的了,只有在以后的设计过程中,遇 ...

  7. Angular2 CLI 快速开发

    Angular2 CLI 快速开发 http://www.tuicool.com/articles/z6V3Ubz 解决npm 的 shasum check failed for错误(npm注册国内镜 ...

  8. 为什么js加事件时不要写括号

    function al(){alert("我擦")}此时,al代表这个函数的对象,al()就是直接运行了.var nfun=al;就是让nfun也指向了al,此时nfun()就相当 ...

  9. CRT 和mysql 中文乱码解决方式

    mysql 安装mysql 1. 使用root用户: su root 2. 安装 yum install mysql yum install mysql-server yum install mysq ...

  10. hiho一下18周 RMQ问题再临

    RMQ问题再临 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 终于,小Hi和小Ho踏上了回国的旅程.在飞机上,望着采购来的特产--小Hi陷入了沉思:还记得在上上周他们去 ...