ITOO---“秒杀”选课之Redis序列化

xiaoxiao2021-02-28  65

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"; //1.接受数据volist List<ChooseCourseModel> chooseCourseModelList = new ArrayList<>(); //2.实例化redis //创建一个spring容器 ApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:redis.xml"); //从容器中获得JedisClient对象 JedisClientCluster jedisClientCluster=(JedisClientCluster)applicationContext.getBean("jedisClientCluster"); //3.获取查询条件 //4.从redis查询数据 String key = "tm:ChooseCourseServiceImpl:publicchoosecourse"; byte[] in= jedisClientCluster.get(key.getBytes());//拿到数据 chooseCourseModelList = SerializeUtil.unserializeForList(in);//反序列化,赋值volist //4.1 if yes 判断拿出的数据 if (chooseCourseModelList.isEmpty() || "".equals(chooseCourseModelList)) { //4.2 if no 查数据库 chooseCourseModelList = chooseCourseDao.queryAllCoursePage(coursetype); //4.2.1 判断是否为空 //4.2.2 放入redis中 jedisClientCluster.set(key.getBytes(), SerializeUtil.serialize(chooseCourseModelList)); } return chooseCourseModelList; }

调用工具类:

序列化:

jedisClientCluster.set(key.getBytes(), SerializeUtil.serialize(chooseCourseModelList));

反序列化:

chooseCourseModelList = SerializeUtil.unserializeForList(in);//反序列化,赋值volist
转载请注明原文地址: https://www.6miu.com/read-64107.html

最新回复(0)