1.我的选课
在进行选课活动中了为了尽量减少客户端和数据库的连接次数,在实现的思路是这样设计的:客户端的请求优先访问Redis缓存空间,如果Redis中没有则从数据库中加载,并添加到Redis中。这样多个客户端会优先从Redis中加载所需的资源,减少了数据库的压力。
ps:选课中的课程比较多,数据库量较大。
在Redis的存储遇到了个问题,因为Redis的存储方式是(Key,Value)形式的,在设计中Key采用自定义+课程ID的方式,而Value是String类型的,但是从数据库中查询出来的数据是List形式的。Redis本身是不支持这种数据库类型的存储的。
2.Redis五种存储类型
Redis常用五种数据类型:string,hash,list,set,zset(sorted set).
1.String类型
String是最简单的类型,一个key对应一个value
String类型的数据最大1G。 String类型的值可以被视作integer,从而可以让“INCR”命令族操作(incrby、decr、decrby),这种情况下,该integer的值限制在64位有符号数。 在list、set和zset中包含的独立的元素类型都是redis String类型。
2.List类型
链表类型,主要功能是push、pop、获取一个范围的所有值等。其中的key可以理解为链表的名字。
在Redis中,list就是Redis String的列表,按照插入顺序排序。比如使用LPUSH命令在list头插入一个元素,使用RPUSH命令在list的尾插入一个元素。当这两个命令之一作用于一个空的key时,一个新的list就创建出来了。
List的最大长度是2^32-1个元素。
3.Set类型
集合,和数学中的集合概念相似。操作中的key理解为集合的名字。
在Redis中,set就是Redis String的无序集合,不允许有重复元素。
Set的最大元素数是2^32-1。
Redis中对set的操作还有交集、并集、差集等。
4.ZSet(Sorted Set)类型
Zset是set的一个升级版本,在set的基础上增加了一个顺序属性,这一属性在添加修改元素时可以指定,每次指定后zset会自动安装指定值重新调整顺序。可以理解为一张表,一列存value,一列存顺序。操作中的key理解为zset的名字。
Zset的最大元素数是2^32-1。
对于已经有序的zset,仍然可以使用SORT命令,通过指定ASC|DESC参数对其进行排序。
5.hash类型
hash是最接近关系数据库结构的数据类型,可以将数据库一条记录或程序中一个对象转换成hashmap存放在redis中。
3.序列化类
如果要满足需求进行List的存储,则需要进行序列化,既将List序列化成字符进行存储。这里就需要借助序列化的工具类了。序列化工具类SerializeUtil如下:
package com.dmsdbj.itoo.teachingManagement.service.impl;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 序列化对象工具类,用于保存和读取redis数据使用
* Created by F-mdh on 2017/7/9.
*/
public class SerializeUtil {
private static Logger log = LoggerFactory.getLogger(SerializeUtil.class);
/**
* 序列化对象
* @param object
* @return
*/
public static byte[]
serialize(Object object) {
ObjectOutputStream oos =
null;
ByteArrayOutputStream baos =
null;
byte[] bytes =
null;
try {
baos =
new ByteArrayOutputStream();
oos =
new ObjectOutputStream(baos);
oos.writeObject(object);
bytes = baos.toByteArray();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if (oos !=
null) {
oos.close();
}
if (baos !=
null) {
baos.close();
}
}
catch (Exception e2) {
e2.printStackTrace();
}
}
return bytes;
}
/**
* 反序列化对象
* @param bytes
* @return
*/
public static Object
unserialize(
byte[] bytes) {
Object obj =
null;
ByteArrayInputStream bais =
null;
try {
bais =
new ByteArrayInputStream(bytes);
ObjectInputStream ois =
new ObjectInputStream(bais);
obj = ois.readObject();
ois.close();
bais.close();
}
catch (Exception e) {
e.printStackTrace();
}
return obj;
}
/**
* 关闭的数据源或目标。调用 close()方法可释放对象保存的资源(如打开文件)
* 关闭此流并释放与此流关联的所有系统资源。如果已经关闭该流,则调用此方法无效。
* @param closeable
*/
public static void close(Closeable closeable) {
if (closeable !=
null) {
try {
closeable.close();
}
catch (Exception e) {
log.info(
"Unable to close %s", closeable, e);
}
}
}
/**
* 列表序列化(用于Redis整存整取)
* @param value
* @return
*/
public static <T>
byte[]
serialize(List<T> value) {
if (value ==
null) {
throw new NullPointerException(
"Can't serialize null");
}
byte[] rv=
null;
ByteArrayOutputStream bos =
null;
ObjectOutputStream os =
null;
try {
bos =
new ByteArrayOutputStream();
os =
new ObjectOutputStream(bos);
for(T obj : value){
os.writeObject(obj);
}
os.writeObject(
null);
os.close();
bos.close();
rv = bos.toByteArray();
}
catch (IOException e) {
throw new IllegalArgumentException(
"Non-serializable object", e);
}
finally {
close(os);
close(bos);
}
return rv;
}
/**
* 反序列化列表(用于Redis整存整取)
* @param in
* @return
*/
public static <T> List<T>
unserializeForList(
byte[] in) {
List<T> list =
new ArrayList<T>();
ByteArrayInputStream bis =
null;
ObjectInputStream is =
null;
try {
if(in !=
null) {
bis=
new ByteArrayInputStream(in);
is=
new ObjectInputStream(bis);
while (
true) {
T obj = (T) is.readObject();
if(obj ==
null){
break;
}
else{
list.add(obj);
}
}
is.close();
bis.close();
}
}
catch (IOException e) {
log.warn(
"Caught IOException decoding %d bytes of data",
in ==
null ?
0 : in.length, e);
}
catch (ClassNotFoundException e) {
log.warn(
"Caught CNFE decoding %d bytes of data",
in ==
null ?
0 : in.length, e);
}
finally {
close(is);
close(bis);
}
return list;
}
}
4.代码
/**
*从redis中 查询所有的公选数据:
* @param :
* @return
*/
@Override
public List<ChooseCourseModel>
queryAllCoursePage() {
String coursetype=
"3B6FE3BAB12E3BA8AFE36D";
List<ChooseCourseModel> chooseCourseModelList =
new ArrayList<>();
ApplicationContext applicationContext=
new ClassPathXmlApplicationContext(
"classpath:redis.xml");
JedisClientCluster jedisClientCluster=(JedisClientCluster)applicationContext.getBean(
"jedisClientCluster");
String key =
"tm:ChooseCourseServiceImpl:publicchoosecourse";
byte[] in= jedisClientCluster.get(key.getBytes());
chooseCourseModelList = SerializeUtil.unserializeForList(in);
if (chooseCourseModelList.isEmpty() ||
"".equals(chooseCourseModelList)) {
chooseCourseModelList = chooseCourseDao.queryAllCoursePage(coursetype);
jedisClientCluster.set(key.getBytes(), SerializeUtil.serialize(chooseCourseModelList));
}
return chooseCourseModelList;
}
调用工具类:
序列化:
jedisClientCluster.
set(key.getBytes(), SerializeUtil.serialize(chooseCourseModelList));
反序列化:
chooseCourseModelList = SerializeUtil.unserializeForList(
in);