Redis的缓存优化案例
1.准备事项
需求简要:在index.html中添加一个下拉列表,显示省份信息。当页面加载完成后,发送ajax请求,从服务器端获取数据回显到页面。在服务器端使用Redis缓存优化(在服务器接收到客户端的请求后,会先去缓存中找数据如果缓存中有该数据,则直接响应给客户端,不会使用数据库的资源。如果缓存中没有该数据,则再去使用数据库的资源去找数据并将该数据存储在缓存中以供下次使用)。
参考文档:
(1)非关系型数据库Redis的入门学习。https://blog.csdn.net/q961250375/article/details/102680405
(2)Jedis学习,一款Java操作Redis数据库的工具。https://blog.csdn.net/q961250375/article/details/102688899
案例源码下载【百度网盘mnlq】。
2.案例实现
2.1.创建数据库
CREATE DATABASE demo CHARACTER SET utf8 COLLATE utf8_general_ci; USE demo; CREATE TABLE province( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20) NOT NULL )CHARACTER SET utf8 COLLATE utf8_general_ci; -- 插入数据 INSERT INTO province VALUES(NULL,"北京"); INSERT INTO province VALUES(NULL,'上海'); INSERT INTO province VALUES(NULL,'广州'); INSERT INTO province VALUES(NULL,'深圳'); INSERT INTO province VALUES(NULL,'湖北');
2.2.项目结构及相关Jar包
2.3.项目具体代码
(1)数据库连接池配置文件:druid.properties
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql:///demo username=root password=root initialSize=5 maxActive=10 maxWait=3000
(2)Redis连接池配置文件:jedis.properties
host=127.0.0.1 port=6379 maxTotal=50 maxIdle=10
(3)JDBC工具类:JDBCUtils
package com.atlantis.util; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import java.io.IOException; import java.io.InputStream; import java.util.Properties; /** * JedisPoolUtils * 记载配置文件,配置连接池参数,提供获取连接的方法 */ public class JedisPoolUtils { private static JedisPool jedisPool; static { // 读取jedis.properties配置文件 InputStream inputStream = JedisPoolUtils.class.getClassLoader().getResourceAsStream("jedis.properties"); // 创建Properties对象 Properties properties = new Properties(); // 关联配置文件 try { properties.load(inputStream); } catch (IOException e) { e.printStackTrace(); } // 获取数据并设置到JedisPoolConfig中 JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); // 在此处设置JedisPool的配置信息 START jedisPoolConfig.setMaxTotal(Integer.parseInt(properties.getProperty("maxTotal"))); jedisPoolConfig.setMaxIdle(Integer.parseInt(properties.getProperty("maxIdle"))); // ......... // 在此处设置JedisPool的配置信息 END // 初始化JedisPool jedisPool = new JedisPool(jedisPoolConfig, properties.getProperty("host"), Integer.parseInt(properties.getProperty("port"))); } /** * 获取连接 */ public static Jedis getJedis() { return jedisPool.getResource(); } }
(4)JedisPool工具类:JedisPoolUtils
package com.atlantis.util; import com.alibaba.druid.pool.DruidDataSourceFactory; import javax.sql.DataSource; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; /** * 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(); } }
(5)Province省份实体类设计
package com.atlantis.entity; public class Province { private int id; private String name; // 省略构造方法 // 省略get和set方法 }
(6)数据持久层Dao:只贴ProvinceDaoImpl.java实现接口代码
package com.atlantis.dao.impl; import com.atlantis.dao.ProvinceDao; import com.atlantis.entity.Province; import com.atlantis.util.JDBCUtils; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import java.util.List; public class ProvinceDaoImpl implements ProvinceDao { private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource()); @Override public List<Province> findAll() { String sql = "select * from province "; List<Province> list = template.query(sql, new BeanPropertyRowMapper<Province>(Province.class)); return list; } }
(7)服务持久层Service:只贴ProvinceServiceImpl.java实现接口代码
package com.atlantis.service.impl; import com.atlantis.dao.ProvinceDao; import com.atlantis.dao.impl.ProvinceDaoImpl; import com.atlantis.entity.Province; import com.atlantis.service.ProvinceService; import java.util.List; public class ProvinceServiceImpl implements ProvinceService { //声明dao private ProvinceDao dao = new ProvinceDaoImpl(); @Override public List<Province> findAll() { return dao.findAll(); } }
(8)控制层Servlet:ProvinceServlet
package com.atlantis.web.servlet; import com.atlantis.entity.Province; import com.atlantis.service.ProvinceService; import com.atlantis.service.impl.ProvinceServiceImpl; import com.fasterxml.jackson.databind.ObjectMapper; 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.util.List; @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 { this.doPost(request, response); } }
3.Redis缓存优化
可以发现,每次页面刷新或访问ProvinceServlet时都会访问数据库,耗时也耗资源。而且数据库中province表中的省份数据一般情况下是“固定”的,不会发生变化。
因此,可以通过Redis缓存优化的方案,将这些“固定”的数据放入缓存中。
服务器接收到客户端的请求后,会先去缓存中找数据。
如果缓存中有该数据,则直接响应给客户端,不会使用数据库的资源。如果缓存中没有该数据,则再去使用数据库的资源去找数据并将该数据存储在缓存中以供下次使用。
这样就大大降低了访问数据库的频率,提升了整体的查询性能。
3.1.代码改造
(1)在服务层Service的接口定义一个方法并且在ProvinceServiceImpl中实现这个方法,该方法用于从缓存中查询数据,返回类型是JSON,即String类型。
@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从数据中查询 List<Province> ps = dao.findAll(); //2.2将list序列化为json ObjectMapper mapper = new ObjectMapper(); try { province_json = mapper.writeValueAsString(ps); } catch (JsonProcessingException e) { e.printStackTrace(); } //2.3 将json数据存入redis jedis.set("province",province_json); //归还连接 jedis.close(); }else{ System.out.println("redis中有数据,查询缓存..."); } return province_json; }
(2)最后在ProvinceServlet方法中,调用服务层Service的findAllJson()方法即可。
package com.atlantis.web.servlet; import com.atlantis.entity.Province; import com.atlantis.service.ProvinceService; import com.atlantis.service.impl.ProvinceServiceImpl; import com.fasterxml.jackson.databind.ObjectMapper; 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.util.List; @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);*/ //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); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
- Mybatis+Redis纯注解方案实现缓存案例
- java(优化25) Redis缓存加索引处理数据库百万级并发的方案
- HashMap作为缓存时的性能优化及与redis,EhCache等的应用比较
- SpringBoot2.0 基础案例(08):集成Redis数据库,实现缓存管理
- 使用Redis进行缓存优化
- Java系统高并发之Redis后端缓存优化
- [置顶] 小白的web优化之路 二、实战使用redis来缓存列表信息
- 《转》基于redis的缓存机制的思考和优化
- SpringBoot2.0 基础案例(08):集成Redis数据库,实现缓存管理
- Redis(二)-----缓存优化
- 基于redis的缓存机制的思考和优化
- Django缓存优化之redis
- Java系统高并发之Redis后端缓存优化
- 使用Redis脚本做缓存的小案例
- [MySQL优化案例]系列 -- 无法使用查询缓存
- WEB项目,使用redis做缓存小案例
- [MySQL优化案例]系列 -- 无法使用查询缓存
- 高性能缓存系统Redis安装与使用