【Redis】Redis入门篇(2)

Redis入门篇(1):涉及到Redis概念、Redis下载安装、命令行操作、Redis数据结构、持久化操作
Redis入门篇(2):了解使用Java客户端操作Redis。Redis连接池、实际应用案例。


五.使用Java客户端操作Redis

介绍Java客户端一款工具 :Jedis。它一款Java操作redis数据库的工具。类似操作MySQL的JDBC工具。

5.1 Jedis使用步骤

使用步骤:

  1. 下载jedis的jar包,导入工程目录
  2. 在程序中创建Jedis的实例:
    • 获取redis连接
    • 使用Jedis的实例操作redis
    • 释放资源,关闭连接

jar包:jar包资源.提取码:6379

在这里插入图片描述

commons-pool2-2.3.jar:包含Jedis连接池
jedis-2.7.0.jar:Jedis工具
junit-4.10.jar:测试框架


快速入门:

写一个Jedis测试类JedisTest,里面有多个测试方法,测试使用Jedis工具。

/**
 * 快速入门:在redis中存储zhangsan字符串数据
 */
@Test
public void test1() {
    //1.获取连接
    Jedis jedis = new Jedis("localhost", 6379);//参数:主机IP,端口号
    //2.数据库操作
    jedis.set("username", "zhangsan");
    //3.关闭连接
    jedis.close();
}

注意:运行程序前,需要先开启本地localhost的redis服务器,如果是连接其它主机的redis服务器,修改成对应主机的IP地址即可。

Jedis方便Java程序操作Redis中的各种数据结构


5.2 Jedis操作Redis中的数据结构

调用Jedis实例中的各种方法来操作redis中对应的数据结构,方法名基本与redis客户端命令行操作指令一致。

这里就把代码写一遍,直观了解。程序运行的结果在redis客户端获取查看对应的数据进行验证。这里不验证了

1.字符串类型 string
/**
 * string 数据结构操作
 */
@Test
public void test2() {
    //1.获取连接
    Jedis jedis = new Jedis();//如果使用空参构造,默认值就是连接本机的"localhost",6379端口
    //2.数据库操作
    //存储string
    jedis.set("username", "zhangsan");
    //获取
    String username = jedis.get("username");
    System.out.println(username);

    //可以使用setex()方法存储可以指定过期实际的 key,value
    jedis.setex("activecode", 20, "8888");//将activecode:8888键值对存入redis,并且20秒后自动删除该键值对

    //3.关闭连接
    jedis.close();
}

2.哈希类型 hash : Map格式
/**
 * hash 数据结构操作
 */
@Test
public void test3() {
    //1.获取连接
    Jedis jedis = new Jedis();//如果使用空参构造,默认值就是连接本机的"localhost",6379端口
    //2.数据库操作
    //存储hash
    jedis.hset("user", "name", "lisi");
    jedis.hset("user", "age", "23");
    jedis.hset("user", "gender", "male");
    //获取hash
    String name = jedis.hget("user", "name");
    System.out.println(name);

    //获取hash的所有map中的数据
    Map<String, String> user = jedis.hgetAll("user");
    //遍历map
    Set<String> set = user.keySet();
    for (String key : set) {
        //获取value
        String value = user.get(key);
        System.out.println(key + ":" + value);
    }

    //可以使用setex()方法存储可以指定过期实际的 key,value
    jedis.setex("activecode", 20, "8888");//将activecode:8888键值对存入redis,并且20秒后自动删除该键值对

    //3.关闭连接
    jedis.close();
}

3.列表类型 list : LinkedList格式。支持重复元素
/**
 * list 数据结构操作
 */
@Test
public void test4() {
    //1.获取连接
    Jedis jedis = new Jedis();
    //2.数据库操作
    // list 存储
    jedis.lpush("myList","a","b","c");//从左边存 cba
    jedis.rpush("myList","a","b","c");//从右边存 abc

    // list 范围获取
    List<String> myList = jedis.lrange("myList", 0, -1);
    System.out.println(myList);

    // list 弹出
    String element1 = jedis.lpop("myList");//c
    System.out.println(element1);

    String element2 = jedis.rpop("myList");//c
    System.out.println(element2);

    List<String> myList1 = jedis.lrange("myList", 0, -1);
    System.out.println(myList1);

    //3.关闭连接
    jedis.close();
}

4.集合类型 set : 不允许重复元素
/**
 * set 数据结构操作
 */
@Test
public void test5() {
    //1.获取连接
    Jedis jedis = new Jedis();
    //2.数据库操作

    // set 存储
    jedis.sadd("mySet","java","php","c++");//无序,不允许重复

    // set 获取
    Set<String> mySet = jedis.smembers("mySet");
    System.out.println(mySet);

    //3.关闭连接
    jedis.close();
}

5.有序集合类型 sortedset:不允许重复元素,且元素有顺序
/**
 * sortedset 数据结构操作
 */
@Test
public void test6() {
    //1.获取连接
    Jedis jedis = new Jedis();
    //2.数据库操作
    // sortedset 存储
    jedis.zadd("mySortedSet",3,"亚瑟");
    jedis.zadd("mySortedSet",30,"后裔");
    jedis.zadd("mySortedSet",25,"李白");

    // sortedset 获取
    Set<String> mySortedSet = jedis.zrange("mySortedSet", 0, -1);//有序,不允许重复
    System.out.println(mySortedSet);

    //3.关闭连接
    jedis.close();
}

5.3 Jedis连接池: JedisPool

Jedis连接池,存放Redis连接对象的容器,主要可以复用连接对象,提高性能。数据库连接池的原理可以参考另一篇博文:JDBC(二):数据库连接池(C3P0、Druid)

虽然Redis数据存储在内存中,也会涉及到频繁的IO操作。这里简单说下连接池的好处:

  1. 节约资源
  2. 用户访问高效

1.Jedis连接池使用

使用:

  1. 创建JedisPool连接池对象
  2. 连接池对象调用方法 getResource()方法获取Jedis连接
  3. 使用Jedis连接

一般我们会在创建Jedis连接池对象前,会使用配置对象JedisPoolConfig 对连接池进行配置(不配置会使用默认配置)。根据实际需求调整配置,连接池的配置都封装到JedisPoolConfig 了,调用其实例的设置方法即可。

/**
 * jedis连接池使用
 */
@Test
public void test7(){
    //0.创建一个配置对象
    JedisPoolConfig config = new JedisPoolConfig();
    config.setMaxTotal(50);//最大活动对象数
    config.setMaxIdle(10);//最大能保持idel空闲状态的对象数

    //1.创建Jedis连接池对象
    //JedisPool jedisPool = new JedisPool();
    JedisPool jedisPool = new JedisPool(config,"localhost",6379);

    //2.获取连接对象
    Jedis jedis = jedisPool.getResource();
    //3.使用Jedis对象,进行数据库操作
    jedis.set("name","wangwu");

    //4.关闭连接,归还到连接池中
    jedis.close();
}

来了解下Jedis连接池详细配置的一些属性:

jedis详细配置.properties

#最大活动对象数     
redis.pool.maxTotal=1000    

#最大能够保持idel状态的对象数      
redis.pool.maxIdle=100  

#最小能够保持idel状态的对象数   
redis.pool.minIdle=50    

#当池内没有返回对象时,最大等待时间    
redis.pool.maxWaitMillis=10000    

#当调用borrow Object方法时,是否进行有效性检查    
redis.pool.testOnBorrow=true    

#当调用return Object方法时,是否进行有效性检查    
redis.pool.testOnReturn=true  

#“空闲链接”检测线程,检测的周期,毫秒数。如果为负值,表示不运行“检测线程”。默认为-1.  
redis.pool.timeBetweenEvictionRunsMillis=30000  

#向调用者输出“链接”对象时,是否检测它的空闲超时;  
redis.pool.testWhileIdle=true  

# 对于“空闲链接”检测线程而言,每次检测的链接资源的个数。默认为3.  
redis.pool.numTestsPerEvictionRun=50  

#redis服务器的IP    
redis.ip=xxxxxx  

#redis服务器的Port    
redis1.port=6379   

我们只需要配置常用的几个属性就行,需要其它属性的时候再配置。这样在程序里一个一个的配置太麻烦,回想起JDBC的经历,封装成工具类,还世界一片安宁。


2.连接池工具类

连接池常需要配置的属性放在配置文件中,配置时读取文件中的属性:

jedis.properties

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

连接池工具类,比较简单的封装,其它可以自由发挥:

JedisPoolutils.java

/**
 * JedisPool 工具类
 * 1.加载配置文件,配置连接池的参数
 * 2.提供获取连接的方法
 */
public class JedisPoolutils {
    //声明JedisPool
    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.setMaxTotal(Integer.parseInt(pro.getProperty("maxIdle")));

        //初始化JedisPool
        jedisPool = new JedisPool(config, pro.getProperty("host"), Integer.parseInt(pro.getProperty("port")));
    }

    /**
     * 提供获取连接的方法
     * @return
     */
    public static Jedis getJedis() {
        return jedisPool.getResource();
    }
}

再使用一下连接池工具类:

/**
 * jedis连接池工具类使用
 */
@Test
public void test8(){
    //通过连接池工具类获取
    Jedis jedis = JedisPoolutils.getJedis();

    //使用Jedis对象
    jedis.set("hello","world");

    //4.关闭连接,归还到连接池中
    jedis.close();
}

简洁直接。最后完成一个Redis的综合练习。


六.Redis案例

1.案例需求

  • 1.提供index.html页面,页面中有一个**“省份”**下拉列表
  • 2.省份数据都在MySQL数据库中
  • 3.当页面加载完成后发送ajax请求,加载所有省份

一般省份信息是长时间不会发生变化的,如果相同的信息每次都从MySQL数据库中获取出来,从电脑的磁盘中读数据,效率低下,影响系统性能,用户体验较差。像这样的场景,利用缓存的思想来提高系统的性能,我们可以使用redis缓存一些不经常发生变化。

案例效果预览:

在这里插入图片描述
需要注意的是:

  • 数据库的数据一旦发生改变,则需要更新缓存
  • 像数据库的表执行 “增删改” 的相关操作,需要将redis缓存数据情况,再次存入;
    具体操作,在service层对应的增删改方法中,将redis数据删除

案例分析:

在这里插入图片描述

主要技术点:JQuery+Ajax+Json+Servlet+JdbcTemplate+Druid+MySQL+Redis


2.案例实现

2.1 数据库准备
-- 创建数据库,设置utf-8编码格式
CREATE DATABASE example CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
USE example; 			   -- 使用数据库
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,'陕西');

数据库表:

在这里插入图片描述


2.2 创建Web工程,导入jar包

目录结构:

在这里插入图片描述
导入相关jar包:

在这里插入图片描述

案例jar包资源:jar包资源.提取码:6379


2.3 前端页面

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>redis案例</title>
    <!-- 引入Jquery框架 -->
    <script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
    <script>
        $(function () {
            //发送ajax请求,加载所有省份数据
            $.get("provinceServlet", {}, function (data) {
                //data:[{"id":1,"name":"北京"},{"id":2,"name":"上海"},{"id":3,"name":"广州"},{"id":4,"name":"陕西"}]

                //1.获取select标签的对象
                var province = $("#province");
                //2.遍历json数组
                $(data).each(function () {
                    console.log(data);
                    //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>
2.3 util层

MySQL

druid.properties

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/example?useSSL=false&characterEncoding=UTF-8
username=root
password=201703457
initialSize=5
maxActive=10
maxWait=3000

JDBCUtils.java

/**
 * JDBC工具类 使用Durid连接池
 */
public class JDBCUtils {

    private static DataSource ds ;

    static {
        try {
            //1.加载配置文件
            Properties pro = new Properties();
            //使用ClassLoader加载配置文件,获取字节输入流
            InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
            pro.load(is);

            //2.初始化连接池对象
            ds = DruidDataSourceFactory.createDataSource(pro);

        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接池对象
     */
    public static DataSource getDataSource(){
        return ds;
    }

    /**
     * 获取连接Connection对象
     */
    public static Connection getConnection() throws SQLException {
        return  ds.getConnection();
    }
}

Redis

jedis.properties

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

JedisPoolutils.java

/**
 * JedisPool 工具类
 * 1.加载配置文件,配置连接池的参数
 * 2.提供获取连接的方法
 */
public class JedisPoolutils {
    //声明JedisPool
    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.setMaxTotal(Integer.parseInt(pro.getProperty("maxIdle")));

        //初始化JedisPool
        jedisPool = new JedisPool(config, pro.getProperty("host"), Integer.parseInt(pro.getProperty("port")));
    }

    /**
     * 提供获取连接的方法
     * @return
     */
    public static Jedis getJedis() {
        return jedisPool.getResource();
    }

}

2.4 domain层

Province.java

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;
    }

    @Override
    public String toString() {
        return "Province{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

2.5 dao层

ProvinceDao.java

/**
 * 持久层接口
 */
public interface ProvinceDao {
    /**
     * 查询所有的方法
     * @return
     */
    public List<Province> findAll();

}

ProvinceDaoImpl.java

/**
 * 持久层接口实现类
 */
public class ProvinceDaoImpl implements ProvinceDao {

    //1.声明成员变量 JdbcTemplate
    private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());

    /**
     * 查询所有的方法
     * @return
     */
    @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;
    }
}

2.6 Service层

ProvinceService.java

/**
 * 业务成接口
 */
public interface ProvinceService {

    /**
     * 查询所有的方法
     * @return
     */
    public List<Province> findAll();

    /**
     * 查询所有并转换为json
     * @return
     */
    public String findAllJson();
}

ProvinceServiceImpl.java

/**
 * 业务成接口的实现类
 */
public class ProvinceServiceImpl implements ProvinceService {

    //声明Dao的引用
    private ProvinceDao dao = new ProvinceDaoImpl();

    @Override
    public List<Province> findAll() {
        //调用dao层方法
        return dao.findAll();
    }

    /**
     * 使用redis缓存
     * @return
     */
    @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中没有数据
            System.out.println("redis中没有数据,查询数据库...");
            //2.1 从mysql数据库中查询
            List<Province> pro_list = dao.findAll();
            //2.2 将list 序列化为json
            ObjectMapper mapper = new ObjectMapper();
            try {
                province_json = mapper.writeValueAsString(pro_list);
                //2.3 将json数据存入redis中
                jedis.set("province",province_json);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }finally {
                //归还连接
                jedis.close();
            }
        }else {
            System.out.println("redis中有数据,查询缓存...");
        }
        //返回json格式字符串
        return province_json;
    }
}

2.7 Web层

ProvinceServlet.java

@WebServlet(name = "ProvinceServlet", urlPatterns = "/provinceServlet")
public class ProvinceServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        this.doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //1.调用service方法查询
        ProvinceService service = new ProvinceServiceImpl();
        String json = service.findAllJson();

        System.out.println(json);
        //3.响应结果
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write(json);
    }
}

3.案例测试

服务器电脑需要启动MySQL服务器和Redis服务器。

启动项目,访问index.html,可以看到:

在这里插入图片描述


多刷新几次页面,查看控制台的打印:

在这里插入图片描述

第一次访问时,会从数据库中读取数据,并将数据存入缓存。之后再次访问就直接从缓存中拿数据,不会再去查询MySQL数据库了,极大提升了系统性能、响应效率。

查看Redis中的数据:
在这里插入图片描述
Redis中也存入了省份数据。案例完成。

以上就是Redis入门篇(2)的全部内容。Redis的强大远不止这些,继续加油。


推荐阅读:
Redis入门篇(1).
Redis入门篇(2).

欢迎点赞评论,指出不足,笔者由衷感谢哦!~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值