【Redis高手修炼之路】案例——异步加载所有联系人

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 【Redis高手修炼之路】案例——异步加载所有联系人

1.案例需求与效果

  1. 案例需求与效果:

访问index.html页面,点击页面上的加载所有联系人按钮,才使用ajax请求异步加载所有联系人列表。用户第一次访问从数据库中获取数据,以后都从redis缓存里面获取。

  1. 执行效果

image.png

服务器控制器信息

image.png

MySQL中的数据

image.png

Redis中数据

image.png

2.项目分析

image.png

3.准备数据

3.1复制原型目录web目录下

image.png

3.2表数据

-- 联系人
create table contact (
   id int primary key auto_increment,
   name varchar(20) not null,  -- 姓名
   phone varchar(20),  -- 电话
   email varchar(50),  -- 邮箱
   birthday date  -- 生日
);
insert into contact (name,phone,email,birthday) values
('孙悟空','13423431234','wukong@itcast.cn', '1993-11-23'),
('猪八戒','13525678909','bajie@itcast.cn', '1953-05-02'),
('白骨精','18642343123','xiaobai@itcast.cn', '1943-03-12');
select * from contact;

3.3导入的包

3.4实体类

package com.itheima.entity;
import java.sql.Date;
/**
 * 联系人实体类
 */
public class Contact {
    private int id;  //编号
    private String name;  //姓名
    private String phone;  //电话
    private String email;  //邮箱
    private Date birthday;  //生日
    @Override
    public String toString() {
        return "Contact{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", phone='" + phone + '\'' +
                ", email='" + email + '\'' +
                ", birthday=" + birthday +
                '}';
    }
    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;
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}

3.5工具类和配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="default">
        <!--环境变量-->
        <environment id="default">
            <!--事务管理器-->
            <transactionManager type="JDBC"/>
            <!--数据源-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/day32"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!--映射器-->
    <mappers>
        <mapper class="com.itheima.dao.ContactDao"/>
    </mappers>
</configuration>
package com.itheima.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
/**
 会话工厂工具类
 */
public class SessionFactoryUtils {
    private static SqlSessionFactory factory;
    static {
        //实例化工厂建造类
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //读取核心配置文件
        try (InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml")) {
        //创建工厂对象
            factory = builder.build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     得到会话对象
     @return 会话对象
     */
    public static SqlSession getSession() {
        return factory.openSession();
    }
    /**
     得到工厂对象
     @return 会话工厂对象
     */
    public static SqlSessionFactory getSqlSessionFactory() {
        return factory;
    }
}

  3.6Jedis工具类和配置文件

jedis.properties

# 主机名
host=localhost
# 端口号
port=6379
# 最大连接数
maxTotal=30
# 最长等待时间
maxWaitMillis=3000

JedisUtils.java

package com.itheima.utils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.ResourceBundle;
/**
 * 创建Jedis工具类
 */
public class JedisUtils {
    private static JedisPool pool;
    static {
        //读取src下的配置文件,得到ResourceBundle对象
        ResourceBundle bundle = ResourceBundle.getBundle("jedis");
        //得到所有的属性并且赋值
        String host = bundle.getString("host");
        //以下属性要转成整数类型
        int port = Integer.parseInt(bundle.getString("port"));
        int maxTotal = Integer.parseInt(bundle.getString("maxTotal"));
        int maxWaitMillis = Integer.parseInt(bundle.getString("maxWaitMillis"));
        //创建配置对象
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxWaitMillis(maxWaitMillis);
        config.setMaxTotal(maxTotal);
        //创建连接池对象
        pool = new JedisPool(config, host, port);
    }
    /**
     * 从连接池中得到Jedis连接对象
     */
    public static Jedis getJedis() {
        return pool.getResource();
    }
}

4.项目结构

f62aa4a8423a4042a9638f715a9f0f06.png

5.源代码

数据访问层

package com.itheima.dao;
import com.itheima.entity.Contact;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
 联系人数据访问层
 */
public interface ContactDao {
    /**
     查询所有联系人
     */
    @Select("select * from contact")
    List<Contact> findAll();
}
package com.itheima.dao.impl;
import com.itheima.dao.ContactDao;
import com.itheima.entity.Contact;
import com.itheima.utils.SessionFactoryUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import java.util.List;
/**
 联系人数据访问层
 */
public class ContactDaoImpl implements ContactDao {
    private SqlSessionFactory factory = SessionFactoryUtils.getSqlSessionFactory();
    /**
     查询所有联系人
     */
    public List<Contact> findAll() {
        SqlSession session = factory.openSession();
        ContactDao contactDao = session.getMapper(ContactDao.class);
        List<Contact> contacts = contactDao.findAll();
        session.close();
        return contacts;
    }
}

业务层

package com.itheima.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.itheima.dao.ContactDao;
import com.itheima.dao.impl.ContactDaoImpl;
import com.itheima.entity.Contact;
import com.itheima.utils.JedisUtils;
import redis.clients.jedis.Jedis;
import java.util.List;
/**
 业务层 */
public class ContactService {
    private ContactDao contactDao = new ContactDaoImpl();
    /**
     读取联系人的JSON数据
     */
    public String findAllContacts() {
        //1. 从redis中获取联系人列表
        Jedis jedis = JedisUtils.getJedis();
        String contacts = jedis.get("contacts");
        //2. 判断数据是否为空,如果为空则调用DAO去MySQL找联系人,找到后转成JSON对象写入到redis中
        if (contacts == null) {
            System.out.println("访问MySQL");
            List<Contact> list = contactDao.findAll();
            //转成JSON对象
            try {
                contacts = new ObjectMapper().writeValueAsString(list);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            //写入到redis中
            jedis.set("contacts", contacts);
        } else {
            System.out.println("访问Redis");
        }
        //3.如果不为空,则从redis获取json数据。
        return contacts;
    }
}

Servlet

package com.itheima.servlet;
import com.itheima.service.ContactService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(name = "ContactServlet",urlPatterns = "/contact")
public class ContactServlet extends HttpServlet {
    private ContactService contactService = new ContactService();
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //指定为json类型
        response.setContentType("text/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        //调用业务类方法,得到所有联系人
        String contacts = contactService.findAllContacts();
        out.print(contacts);
    }
}

页面

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>通讯录管理</title>
    <link href="css/bootstrap.min.css" rel="stylesheet">
    <script src="js/jquery-3.3.1.min.js"></script>
    <script src="js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
    <br>
    <input id="btnLoad" type="button" class="btn btn-primary" value="加载联系人列表">
    <input id="btnClear" type="button" class="btn btn-danger" value="清空联系人列表">
    <hr>
    <table class="table table-bordered table-hover table-striped">
        <thead>
        <tr class="success">
            <th>编号</th>
            <th>姓名</th>
            <th>电话</th>
            <th>邮箱</th>
            <th>生日</th>
        </tr>
        </thead>
        <tbody id="contacts">
        </tbody>
    </table>
</div>
</body>
<script type="text/javascript">
    $("#btnLoad").click(function () {
        //使用jquery和get方法去访问servlet
        $.get({
            url: "contact",
            success: function (contacts) {
                var str = "";
                 if (contacts.length > 0) {
                     //element表示每个元素
                    $.each(contacts, function (index, element) {
                        str+= "<tr>";
                        str+= "<td>" + element.id + "</td>";
                        str+= "<td>" + element.name + "</td>";
                        str+= "<td>" + element.phone + "</td>";
                        str+= "<td>" + element.email + "</td>";
                        str+= "<td>" + element.birthday + "</td>";
                        str+= "</tr>";
                    });
                    //把所有行的加入tbody中
                     $("#contacts").html(str);
                 }
            }
        })
    })
    //删除按钮
    $("#btnClear").click(function () {
        //清空子元素
        $("#contacts").empty();
    })
</script>
</html>
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
NoSQL Linux Redis
linux安装单机版redis详细步骤,及python连接redis案例
这篇文章提供了在Linux系统中安装单机版Redis的详细步骤,并展示了如何配置Redis为systemctl启动,以及使用Python连接Redis进行数据操作的案例。
63 2
|
1月前
|
消息中间件 NoSQL Kafka
大数据-116 - Flink DataStream Sink 原理、概念、常见Sink类型 配置与使用 附带案例1:消费Kafka写到Redis
大数据-116 - Flink DataStream Sink 原理、概念、常见Sink类型 配置与使用 附带案例1:消费Kafka写到Redis
120 0
|
5月前
|
JSON NoSQL Redis
|
6月前
|
缓存 NoSQL Java
Redis7的10大应用场景和案例解析
你在项目中使用 Redis 实现了什么应用场景,欢迎一起跟 V 哥讨论。同时也做个小调查,朋多少兄弟是需要了解 Redis 核心源码的,人多的话,下一篇 V 哥写 Redis7的源码分析,人少的话就算了,感谢。
134 0
|
6月前
|
存储 监控 NoSQL
【Redis技术专区】「优化案例」谈谈使用Redis慢查询日志以及Redis慢查询分析指南
【Redis技术专区】「优化案例」谈谈使用Redis慢查询日志以及Redis慢查询分析指南
161 0
|
6月前
|
缓存 NoSQL 前端开发
【Redis技术专区】「实战案例」谈谈使用Redis缓存时高效的批量删除的几种方案
【Redis技术专区】「实战案例」谈谈使用Redis缓存时高效的批量删除的几种方案
143 0
|
6月前
|
NoSQL Java 数据库
优惠券秒杀案例 - CAS、Redis+Lua脚本解决高并发并行
优惠券秒杀案例 - CAS、Redis+Lua脚本解决高并发并行
303 0
|
存储 缓存 NoSQL
案例01-修改数据redis没有同步更新
修改数据redis没有同步更新
117 0
|
6月前
|
存储 NoSQL 关系型数据库
Redis系列-8.Redis案例实战之Bitmap、Hyperloglog、GEO(下)
Redis系列-8.Redis案例实战之Bitmap、Hyperloglog、GEO
65 0
|
6月前
|
存储 NoSQL 算法
Redis系列-8.Redis案例实战之Bitmap、Hyperloglog、GEO(上)
Redis系列-8.Redis案例实战之Bitmap、Hyperloglog、GEO
95 0
下一篇
无影云桌面