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

来源:互联网 发布:mac 体验 编辑:程序博客网 时间:2024/06/01 09:56

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
原创粉丝点击