学习JavaWeb(十)——Redis、Jedis和案例

前言

时隔半年,续期篇章。

我们来学习Redis、Jedis,并且做一个小案例

 

 

 

 

 


Redis

概念

Redis是一款高性能的NoSQL系列的非关系型数据库。

关系型数据库与NoSQL型数据库并非对立而是互补的关系,即通常情况下使用关系型数据库,在适合使用NoSQL的时候使用NoSQL数据库,让NoSQL数据库对关系型数据库的不足进行弥补。

REmote DIctionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的 key-value 存储系统,是跨平台的非关系型数据库。

Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的 API。

Redis 通常被称为数据结构服务器,因为值(value)可以是字符串(String)、哈希(Hash)、列表(list)、集合(sets)和有序集合(sorted sets)等类型。

下载安装

我们可以在其github上进行下载安装

下载之后,解压就直接可以使用,下面有几个文件你应该了解一下:

  1. redis.windows.conf:配置文件
  2. redis-cli.exe:redis的客户端
  3. redis-server.exe:redis的服务器端

我们直接双击redis-server.exe就可以启动服务器端了,它会自动监听一个端口。

然后我们再启动redis-cli.exe,就可以连接服务器端,我们可以敲命令来进行数据的存储。

Redis数据结构

Redis存储的是Key、value格式的数据,其中key是字符串,value则有五种不同的数据类型:

  • 字符串类型 string
  • 哈希类型 hash:可以理解为map的格式
  • 列表类型 list:允许重复
  • 集合类型 set:不允许重复
  • 有序集合类型 sortedset:不允许重复,会进行排序

命令操作

经常参考的文档——https://www.redis.net.cn/tutorial/3501.html

基本常用命令操作如下:

字符串类型 string

  1. 存储:set  key  value(key如果已经存在则会覆盖)
  2. 获取:get  key
  3. 删除:del  key

哈希类型 hash

  1. 存储:hset  key  field  value
  2. 获取指定:hget  key  field
  3. 获取所有:hgetall  key
  4. 删除:hdel  key  field

列表类型 list

Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)

一个列表最多可以包含 232 – 1 个元素 (4294967295, 每个列表超过40亿个元素)。

  1. 在头部添加:lpush  key  value
  2. 在尾部添加:rpush  key  value
  3. 范围获取:lrange  key  start  end
  4. 头部删除(弹出):lpop  key
  5. 尾部删除(弹出):rpop  key

lrange  key  start  end 中,start取0、end取-1则会获取所有。

集合类型 set

set集合中是不允许重复元素的

  1. 存储:sadd  key  value
  2. 获取集合中全部元素:smembers  key
  3. 删除某个元素:srem  key   value

有序集合类型 sortedset

Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数(权重)。redis正是通过分数来为集合中的成员进行从小到大的排序。

有序集合的成员是唯一的,但分数(score)却可以重复。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 232 – 1 (4294967295, 每个集合可存储40多亿个成员)。

  1. 存储:zadd  key  score  value
  2. 获取所有(是否显示分数):zrange  key  start  end  (withscores)
  3. 删除:zrem  key   value

通用命令操作

下面来介绍一些通用的命令操作

  1. 查看所有键:keys  *
  2. 获取某键对应的类型:type  key
  3. 删除指定的键和值:del  key

 

redis 持久化

redis是一个内存数据库,当redis服务器重启,或者电脑重启,数据会丢失,我们可以将redis内存中的数据持久化保存到硬盘的文件中。

redis持久化机制:

  1. RDB:在一定时间间隔中,检测key的变化情况,然后持久化数据(默认方式,不需要进行配置,默认就使用这种机制)
  2. AOF:日志记录的方式,可以记录每一条命令的操作。可以每一次命令操作后,持久化数据。

RDB

我们打开配置文件redis.windows.conf,找到如下内容:

//每900秒,当至少有1个key改变,则会持久化一次
save 900 1
//每300秒,当至少有10个key改变,则会持久化一次
save 300 10
//每60秒,当至少有10000个key改变,则会持久化一次
save 60 10000

我们可以根据需要修改配置,来更快的进行本地持久化:

save 15 3

然后我们来重新启动Redis服务器并在redis目录打开cmd窗口指定配置文件名称:

redis-server.exe  redis.windows.conf

持久化数据将会保存在新生成的dump.rdb文件中

AOF

下面是AOF的持久化数据方法:

  1. 编辑redis.windows.conf
  2. 然后设置appendonly   no 为 appendonly   yes,即开启AOF
  3. 找到下面的代码,根据需求注释与取消注释:
    # appendfsync always  //每条命令进行持久化
    appendfsync everysec   //每隔一秒进行持久化
    # appendfsync no   //不进行持久化
  4. 指定配置文件开启服务端
    redis-server.exe  redis.windows.conf

 


Jedis

概念

Jedis是一款Java操作redis数据库的工具

下载

和很多工具一样,我们去下载它的jar包

  • commons-pool:常用在java开发内的进行java数据库连接池的框架常用包
  • jedis:是 Redis 官方首选的 Java 客户端开发包

我这里下载的是jedis-3.5.1.jar和commons-pool2-2.9.0.jar。

入门

打开铺满尘土的IDEA,创建一个动态web项目。

创建项目后,将刚才两个jar包导入进来

在src下创建一个包——cn.luoluo.jedis.test

然后写一个测试类——jedisTest.java

public class JedisTest {
    /**
     * 快速入门
     **/
    @Test
    public void test1(){
        //1.获取连接
        Jedis jedis=new Jedis("localhost",6379);
        //2.操作
        jedis.set("user","zhangsan");
        //3.关闭连接
        jedis.close();
    }
}

开启Redis服务端,然后直接单元运行这个方法,就实现了插入了,就是这么简单。

Jedis操作各种数据结构

Redis中对数据操作的命令在Jedis中就是对应的方法名。

下面的内容主要转自这篇文章

1. jedis中对键通用的操作

方法 描述 返回值 /补充说明
jedis.flush
jedis.flushDB 清空数据
boolean jedis.exists(String key) 判断某个键是否存在 true = 存在,false= 不存在
jedis.set(String key,String value) 新增键值对(key,value) 返回String类型的OK代表成功
Set<String> jedis.keys(*) 获取所有key 返回set 无序集合
jedis.del(String key) 删除键为key的数据项
jedis.expire(String key,int i) 设置键为key的过期时间为i秒
int jedis.ttl(String key) 获取建委key数据项的剩余时间(秒)
jedis.persist(String key) 移除键为key属性项的生存时间限制
jedis.type(String key) 查看键为key所对应value的数据类型

2. jedis中 字符串的操作

字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,这 便意味着该类型可以接受任何格式的数据,如JPEG图像数据或Json对象描述信息等。 在Redis中字符串类型的Value最多可以容纳的数据长度是512M。

语法 描述
jedis.set(String key,String value) 增加(或覆盖)数据项
jedis.setnx(String key,String value) 不覆盖增加数据项(重复的不插入)
jedis.setex(String ,int t,String value) 增加数据项并设置有效时间
jedis.del(String key) 删除键为key的数据项
jedis.get(String key) 获取键为key对应的value
jedis.append(String key, String s) 在key对应value 后边扩展字符串 s
jedis.mset(String k1,String V1,String K2,String V2,…) 增加多个键值对
String[] jedis.mget(String K1,String K2,…) 获取多个key对应的value
jedis.del(new String[](String K1,String K2,.... )) 删除多个key对应的数据项
String jedis.getSet(String key,String value) 获取key对应value并更新value
String jedis.getrang(String key , int i, int j) 获取key对应value第i到j字符 ,从0开始,包头包尾

3. jedis中对整数和浮点数操作

语法 描述
jedis.incr(String key) 将key对应的value 加1
jedis.incrBy(String key,int n) 将key对应的value 加 n
jedis.decr(String key) 将key对应的value 减1
jedis.decrBy(String key , int n) 将key对应的value 减 n

4. jedis中对列表(list)操作

在Redis中,List类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表 一样,我们可以在其头部(left)和尾部(right)添加新的元素。在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。List中可以包含的最大元素数量是 4294967295。
从元素插入和删除的效率视角来看,如果我们是在链表的两头插入或删除元素,这将 会是非常高效的操作,即使链表中已经存储了百万条记录,该操作也可以在常量时间内完成。然而需要说明的是,如果元素插入或删除操作是作用于链表中间,那将会是非常低效的。

list 元素的下表从0开始

语法 描述
jedis.lpush(String key, String v1, String v2,….) 添加一个List , 注意:如果已经有该List对应的key, 则按顺序在左边追加 一个或多个
jedis.rpush(String key , String vn) key对应list右边插入元素
jedis.lrange(String key,int i,int j) 获取key对应list区间[i,j]的元素,注:从左边0开始,包头包尾
jedis.lrem(String key,int n , String val) 删除list中 n个元素val
jedis.ltrim(String key,int i,int j) 删除list区间[i,j] 之外的元素
jedis.lpop(String key) key对应list ,左弹出栈一个元素
jedis.rpop(String key) key对应list ,右弹出栈一个元素
jedis.lset(String key,int index,String val) 修改key对应的list指定下标index的元素
jedis.llen(String key) 获取key对应list的长度
jedis.lindex(String key,int index) 获取key对应list下标为index的元素
jedis.sort(String key) 把key对应list里边的元素从小到大排序 (后边详细介绍)
    @Test
    public void test1(){
        //1.获取连接
        Jedis jedis=new Jedis("localhost",6379);
        //2.操作
        jedis.lpush("mylist","a","b","c");
        jedis.rpush("mylist","a","b","c");
        //list的范围获取
        List<String> mylist = jedis.lrange("mylist", 0, -1);
        System.out.println(mylist);
        //list弹出
        String element=jedis.lpop("mylist");
        System.out.println(element);
        //3.关闭连接
        jedis.close();
    }
输出:
[c, b, a, a, b, c]
c

 

5. jedis 集合set 操作

在Redis中,我们可以将Set类型看作为没有排序的字符集合,和List类型一样,也可以在该类型的数据值上执行添加、删除或判断某一元素是否存在等操作。需要 说明的是,这些操作的时间是常量时间。Set可包含的最大元素数是4294967295。
和List类型不同的是,Set集合中不允许出现重复的元素。和List类型相比,Set类型在功能上还存在着一个非常重要的特性,即在服务器端完成多个Sets之间的聚合计 算操作,如unions、intersections和differences(就是交集并集那些了)。由于这些操作均在服务端完成, 因此效率极高,而且也节省了大量的网络IO开销

set 的方法都以s开头

语法 操作
jedis.sadd(String key,String v1,String v2,…) 添加一个set
jedis.smenbers(String key) 获取key对应set的所有元素
jedis.srem(String key,String val) 删除集合key中值为val的元素
jedis.srem(String key, Sting v1, String v2,…) 删除值为v1, v2 , …的元素
jedis.spop(String key) 随机弹出栈set里的一个元素
jedis.scared(String key) 获取set元素个数
jedis.smove(String key1, String key2, String val) 将元素val从集合key1中移到key2中
jedis.sinter(String key1, String key2) 获取集合key1和集合key2的交集
jedis.sunion(String key1, String key2) 获取集合key1和集合key2的并集
jedis.sdiff(String key1, String key2) 获取集合key1和集合key2的差集

6. jedis中 有序集合Zsort

Sorted-Sets和Sets类型极为相似,它们都是字符串的集合,都不允许重复的成员出现在一个Set中。它们之间的主要差别是Sorted-Sets中的每一个成员都会有一个分数(score)与之关联,Redis正是通过分数来为集合中的成员进行从小到大的排序。然 而需要额外指出的是,尽管Sorted-Sets中的成员必须是唯一的,但是分数(score) 却是可以重复的。
在Sorted-Set中添加、删除或更新一个成员都是非常快速的操作,其时间复杂度为集合中成员数量的对数。由于Sorted-Sets中的成员在集合中的位置是有序的,因此,即便是访问位于集合中部的成员也仍然是非常高效的。事实上,Redis所具有的这一特征在很多其它类型的数据库中是很难实现的,换句话说,在该点上要想达到和Redis同样的高效,在其它数据库中进行建模是非常困难的。
例如:游戏排名、微博热点话题等使用场景。

语法 描述
jedis.zadd(String key,Map map) 添加一个ZSet
jedis.hset(String key,int score , int val) 往 ZSet插入一个元素(Score-Val)
jedis.zrange(String key, int i , int j) 获取ZSet 里下表[i,j] 区间元素Val
jedis. zrangeWithScore(String key,int i , int j) 获取ZSet 里下表[i,j] 区间元素Score – Val
jedis.zrangeByScore(String , int i , int j) 获取ZSet里score[i,j]分数区间的元素(Score-Val)
jeids.zscore(String key,String value) 获取ZSet里value元素的Score
jedis.zrank(String key,String value) 获取ZSet里value元素的score的排名
jedis.zrem(String key,String value) 删除ZSet里的value元素
jedis.zcard(String key) 获取ZSet的元素个数
jedis.zcount(String key , int i ,int j) 获取ZSet总score在[i,j]区间的元素个数
jedis.zincrby(String key,int n , String value) 把ZSet中value元素的score+=n

7. jedis中 哈希(Hash)操作

Redis中的Hashes类型可以看成具有String Key和String Value的map容器。所以该类型非常适合于存储值对象的信息。如Username、Password和Age等。如果Hash中包含很少的字段,那么该类型的数据也将仅占用很少的磁盘空间。每一个Hash可以存储4294967295个键值对。

语法 描述
jedis.hmset(String key,Map map) 添加一个Hash
jedis.hset(String key , String key, String value) 向Hash中插入一个元素(K-V)
jedis.hgetAll(String key) 获取Hash的所有(K-V) 元素
jedis.hkeys(String key) 获取Hash所有元素的key
jedis.hvals(String key) 获取Hash所有元素 的value
jedis.hincrBy(String key , String k, int i) 把Hash中对应的k元素的值 val+=i
jedis.hdecrBy(String key,String k, int i) 把Hash中对应的k元素的值 val-=i
jedis.hdel(String key , String k1, String k2,…) 从Hash中删除一个或多个元素
jedis.hlen(String key) 获取Hash中元素的个数
jedis.hexists(String key,String K1) 判断Hash中是否存在K1对应的元素
jedis.hmget(String key,String K1,String K2) 获取Hash中一个或多个元素value

8. 排序操作

使用排序, 首先需要生成一个排序对象

SortingParams  sortingParams =  new SortingParams();
语法 描述
jedis.sort(String key,sortingParams.alpha()) 队列按首字母a-z 排序
jedis.sort(String key, sortingParams.asc() ) 队列按数字升序排列
jedis.sort(String key , sortingParams.desc()) 队列按数字降序排列

使用示例:

 Jedis jedis = JedisPoolUtils.getJedis();
 SortingParams sortingParams = new SortingParams();
 List<String> sort = jedis.sort("list02", sortingParams.desc());

结合连接池

我们使用的连接池是JedisPool

使用步骤:

  1. 创建JedisPool连接池对象
  2. 调用方法 getResource() 方法获取Jedis连接
    @Test
    public void test2(){
        //0.创建配置对象
        JedisPoolConfig config=new JedisPoolConfig();
        config.setMaxTotal(50); //最大连接数
        config.setMaxIdle(10);  //最大空闲连接

        //1.创建Jedis连接池对象
        JedisPool jedisPool=new JedisPool(
                config,
                "localhost",
                6379
        );
        //2.获取连接
        Jedis jedis=jedisPool.getResource();
        //3.使用
        jedis.set("hehe","test");
        //4.关闭(归还到连接池)
        jedis.close();
    }

如果报错:java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory

请在该网站下载包——slf4j-api-1.7.2.jar,并导入。

 

为了更好的解耦,我们将连接池的部分抽取出来去做一个连接池工具类:

在包cn.luoluo.util下创建一个类——JedisPoolUtils.java

public class JedisPoolUtils {
    private static JedisPool jedisPool;
    //静态代码块
    static{
        //读取配置文件
        InputStream  is= JedisPoolUtils.class
                .getClassLoader()
                .getResourceAsStream("jedis.properties");
        //创建properties对象
        Properties pro=new Properties();
        //关联文件
        try {
            pro.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //获取数据,设置到JedisPoolConfig中
        JedisPoolConfig config=new JedisPoolConfig();
        config.setMaxTotal(
                Integer.parseInt(
                        pro.getProperty("maxTotal")));
        config.setMaxIdle(
                Integer.parseInt(
                        pro.getProperty("maxIdle")));
        //初始化JedisPool
        jedisPool=new JedisPool(config,
                pro.getProperty("host"),
                Integer.parseInt(
                        pro.getProperty("port")
                ));
    }
    /**
     * 获取连接的方法
     **/
    public static Jedis getJedis(){
        return jedisPool.getResource();
    }
}

在src下创建jedis.properties文件,写入

host=127.0.0.1
port=6379
maxTotal=50
maxIdle=10

好了,我们现在来重构刚才的test2:

    @Test
    public void test2(){
        //通过连接池工具类获取连接池中的对象
        Jedis jedis = JedisPoolUtils.getJedis();
        //3.使用
        jedis.set("hehe","test");
        //4.关闭(归还到连接池)
        jedis.close();
    }

一下就简洁了不少。

 


案例

下面我们来做一个小案例

需求与思路

案例需求:

  1. 提供index.html页面,页面中有一个省份,下拉列表
  2. 当页面加载完成后,发送AJAX请求,加载所有省份

思路

 

环境搭建

数据库环境搭建

首先,我们来打开mysql数据库,通过下面的SQL语句在MySQL数据库中存入一些信息:

CREATE  DATABASE  demo;
USE   demo;
CREATE  TABLE   province(    -- 创建表
        id   INT   PRIMARY  KEY  AUTO_INCREMENT,
        NAME   VARCHAR(20)   NOT   NULL
);
--  插入数据
INSERT   INTO   province   VALUES(NULL,'北京');
INSERT   INTO   province   VALUES(NULL,'深圳');
INSERT   INTO   province   VALUES(NULL,'上海');
INSERT   INTO   province   VALUES(NULL,'广州');

然后我们就创建成功了一个数据库、一个表,并且插入了四条数据。

IEAD环境

记得我们以前的那个大项目吗——中场案例,我们将那个项目里的jar包都需要用上

包括我们这篇文章里用到的那些,此外我们还需要JackSon.jar来序列化数据。

 

顺手把那个项目的druid的配置文件也拷过来吧。

然后我们再创建一些包,包括再web下还需要js文件——jQuery

 

实现案例

查询数据库与简单三层架构

在domain包下创建一个数据表Province对应的实体类——Province

public class Province {
    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

然后是我们util包下的JDBCUtils:

public class JDBCUtils {
    private static DataSource ds;

    static{
        try{
            //1.加载配置文件
            Properties pro=new Properties();
            pro.load(JDBCUtils.class
                    .getClassLoader()
                    .getResourceAsStream("druid.properties"));
            //2.获取DataSource
            ds= DruidDataSourceFactory.createDataSource(pro);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    /**
     * @Description 获取连接
     **/
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }
    /**
     * @Description 获取连接池的方法
     **/
    public static DataSource getDateSource(){
        return ds;
    }
    /**
     * @Description 释放资源
     **/
    public static void close(Statement stmt,Connection conn){
        if(stmt!=null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    public static void close(ResultSet rs, Statement stmt, Connection conn){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        close(stmt,conn);
    }
}

OK,接下来开始三层架构的设计,ProvinceDaoImpl:

public class ProvinceDaoImpl implements ProvinceDao {
    //1.声明成员变量 jdbctemplate
    private JdbcTemplate template=
        new JdbcTemplate(
             JDBCUtils.getDateSource());
    @Override
    public List<Province> findAll() {
        //1.定义sql
        String sql="select * from province";
        //2.执行sql
        List<Province> list = template.query(sql,
                new BeanPropertyRowMapper<Province>(
                        Province.class
                ));
        return list;
    }
}

ProvinceServiceImpl:

public class ProvinceServiceImpl implements ProvinceService {
    //声明Dao
    private ProvinceDao dao=new ProvinceDaoImpl();

    @Override
    public List<Province> findAll() {
        return dao.findAll();
    }
}

ProvinceServlet:

@WebServlet("/provinceServlet")
public class ProvinceServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //1.调用service查询
        ProvinceService service=new ProvinceServiceImpl();
        List<Province> list=service.findAll();
        //2.序列化list为json
        ObjectMapper mapper=new ObjectMapper();
        String json = mapper.writeValueAsString(list);
        System.out.println(json);
        //3.响应结果
        response.setContentType(
                "application/json;charset=utf-8");
        response.getWriter().write(json);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doPost(request, response);
    }
}

然后在web下新建一个index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <script src="js/jquery-3.5.1.min.js"></script>

    <script>
        $(function(){
            //发送ajax请求,加载所有省份数据
            $.get("provinceServlet",{},function(data){

            });
        });
    </script>
</head>
<body>
    <select id="province">
        <option>--请选择省份--</option>
    </select>
</body>
</html>

确保druid的配置信息等没问题,运行项目,在加载页面的时候不出意外就会看到控制台打印信息:

[{"id":1,"name":"北京"},{"id":2,"name":"深圳"},{"id":3,"name":"上海"},{"id":4,"name":"广州"}]

后端的部署就大功告成。

前端渲染数据

下面,我们来将数据显示到select标签中,修改我们的index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <script src="js/jquery-3.5.1.min.js"></script>

    <script>
        $(function(){
            //发送ajax请求,加载所有省份数据
            $.get("provinceServlet",{},function(data){
                //1.获取select
                var province=$("#province");
                //2.遍历json数组
                $(data).each(function(){
                    //3.创建<option>
                    var option=
                        "<option name='"+this.id
                        +"'>"+this.name+"</option>"
                    //4.调用select的append追加option
                    province.append(option);
                })
            });
        });
    </script>
</head>
<body>
    <select id="province">
        <option>--请选择省份--</option>
    </select>
</body>
</html>

到这里,基本的功能就实现了,我们实现了将数据库的信息写到index.html中

redis缓存优化

下面才是我们今天的重头戏——利用Redis来优化。

考虑到省份信息并不是经常变动的信息,故,我们可以通过Redis缓存数据。

 

思路:

  1. 从redis中查询数据*,没有
    1. 从数据库中查询
    2. 将数据存入redis
    3. 返回数据
  2. 从redis中查询数据*,有
    1. 返回数据

想好了思路我们就来作业了:

准备好我们的JedisUtil文件,上面写过的:

public class JedisPoolUtils {
    private static JedisPool jedisPool;
    //静态代码块
    static{
        //读取配置文件
        InputStream  is= JedisPoolUtils.class
                .getClassLoader()
                .getResourceAsStream("jedis.properties");
        //创建properties对象
        Properties pro=new Properties();
        //关联文件
        try {
            pro.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //获取数据,设置到JedisPoolConfig中
        JedisPoolConfig config=new JedisPoolConfig();
        config.setMaxTotal(
                Integer.parseInt(
                        pro.getProperty("maxTotal")));
        config.setMaxIdle(
                Integer.parseInt(
                        pro.getProperty("maxIdle")));
        //初始化JedisPool
        jedisPool=new JedisPool(config,
                pro.getProperty("host"),
                Integer.parseInt(
                        pro.getProperty("port")
                ));
    }
    /**
     * 获取连接的方法
     **/
    public static Jedis getJedis(){
        return jedisPool.getResource();
    }
}

配置文件别忘了,这样我们才能连接Redis

host=127.0.0.1
port=6379
maxTotal=50
maxIdle=10

然后,我们来修改一下Province的service层——ProvinceServiceImpl:

    /**
     使用redis缓存
     */
    @Override
    public String findAllJson() {
        //1.先从redis中查询数据
        //1.1获取redis的客户端连接
        Jedis jedis = JedisPoolUtils.getJedis();
        String province_json=jedis.get("province");
        //2.判断 province_json数据是否为null
        if(province_json==null||province_json.length()==0){
            //redis中没有数据
            //2.1从数据库中查询
            List<Province> pc = dao.findAll();
            //2.2将list序列化为json
            ObjectMapper mapper=new ObjectMapper();
            try {
                province_json = mapper.writeValueAsString(pc);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            System.out.println("查询数据库");
            //2.3将json数据存入redis中
            jedis.set("province",province_json);
            //归还连接
            jedis.close();
        }else{
            System.out.println("查询缓存");
        }
        return province_json;
    }

同时,修改我们的servlet:

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws  IOException {
        //1.调用service查询
        ProvinceService service=new ProvinceServiceImpl();
        String json = service.findAllJson();
        //3.响应结果
        response.setContentType(
                "application/json;charset=utf-8");
        response.getWriter().write(json);
    }

OK,大功告成!

注意:使用redis缓存一些不经常发生变化的数据。
数据库的数据一旦发生改变(即数据执行增删改),则需要更新缓存,可以在service对应的增删改方法中,将redis数据删除。

 

 


 

 

 

商业转载 请联系作者获得授权,非商业转载 请标明出处,谢谢

发表评论