SpringBoot笔记 —— 利用redis数据库和mysql数据库查询获取数据
在之前写的SpringBoot项目中SpringBoot笔记 —— 使用MVC和三层架构模拟网站用户登录检查SpringBoot笔记 —— 数据库连接池使用数据库连接池,解决了多次创建连接的问题。现在又要开始思考一个新的问题,那就是如何提高查询效率。在上面的博客里面,我都是通过查询mysql数据库来获取相应的数据,但是当要查询的表里面的数据非常多的时候,比如数十万的数据,查询效率就会很低,往往要消
在之前写的SpringBoot项目中
SpringBoot笔记 —— 使用MVC和三层架构模拟网站用户登录检查
SpringBoot笔记 —— 数据库连接池
使用数据库连接池,解决了多次创建连接的问题。现在又要开始思考一个新的问题,那就是如何提高查询效率。
在上面的博客里面,我都是通过查询mysql数据库来获取相应的数据,但是当要查询的表里面的数据非常多的时候,比如数十万的数据,查询效率就会很低,往往要消耗两三秒的时间才能查询到一条数据。
而在学习redis数据库之后,我们可以通过这个基于内存的数据库来提升查询效率。redis数据库的查询效率很高,往往在几毫秒的时间就可以完成一条数据的查询,因此选择redis作为SpringBoot项目中的缓存。将一部分的数据存储在缓存,也就是redis数据库中。每次查询数据的时候,先到缓存中查询,如果查询成功则直接返回数据,如果查询失败再通过到mysql数据库中查询的方式获取数据。
初次之外,对于redis数据库的连接方式,我们也像连接mysql数据库一样,使用连接池。
最后还要思考一件事情,应该把什么样的数据放入缓存呢?
我们将数据放入缓存的思路是这样的:
一开始缓存为空,数据都在MySQL中。第一次访问某一条数据时,先到缓存查询,缓存为空,必然查询失败,因此到mysql中查询,返回查询的结果,并且将这条数据放入缓存中。这样缓存中有了第一条数据,之后再访问这条数据时就会直接从缓存中获取,而不需要查询数据库了。
但是这样下去,缓冲中的数据量会一直增加,如果缓存中存储的数据量与mysql数据库的一致,那么就无法体现出缓存的优势了。所以应该只是把一部分经常被使用到的数据放入缓存中。
我们可以通过redis数据库的设置过期时间的方式,给缓存中的每一条数据设置一个过期时间,比如30秒,如果30秒后这条数据没有被第二次访问,就会在缓存中被删除。而如果30秒内,这条数据被再次访问了,那么就重新给这条数据设置一个过期时间。也可以理解为刷新这条数据的过期时间,重新变回30秒。
关于如何给redis数据库的数据设置过期时间,我在之前的博客也写过了
Redis笔记 ——String (用位图统计一段时间内用户登录天数,与网站指定时间段内活跃用户数)
整体的思路都梳理完毕,下面就是具体实现的代码
Students类
用来存放mysql数据库中查询到的数据,每一个Students类对象都是一条数据库中的数据
package com.shujia.spring.mvc1.bean;
import lombok.*;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Students {
private String id;
private String name;
private String age;
private String sex;
private String clazz;
}
表现层
package com.shujia.spring.mvc1.controller;
import com.shujia.spring.mvc1.service.UserServiceImpl;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@RequestMapping("/selectById")
public String selectById(String id){
UserServiceImpl userService = new UserServiceImpl();
String s = userService.selectById(id);
return s;
}
}
业务逻辑层
接口
package com.shujia.spring.mvc1.service;
public interface UserSeriver {
public String selectById(String id);
}
package com.shujia.spring.mvc1.service;
import com.shujia.spring.mvc1.bean.Students;
import com.shujia.spring.mvc1.bean.User;
import com.shujia.spring.mvc1.dao.UserDao;
import com.shujia.spring.mvc1.dao.UserDaoImpl;
import com.shujia.spring.util.RedisUtil;
import redis.clients.jedis.Jedis;
import java.util.HashMap;
import java.util.Map;
//业务逻辑层 验证
public class UserServiceImpl implements UserSeriver {
//利用Jedis连接池来获取连接,连接到redis
Jedis jedis = RedisUtil.getJedis();
static UserDao userdao=new UserDaoImpl();
public String selectById(String id){
try {
/*
连接redis
使用hash作为缓存数据结构,即value值的类型为hash散列
通过key值id,查询得到value值,也就是一个map,map的值有三种情况
情况一:如果map中有数据,即查询成功
情况二:如果map的内容为{},说明map中没有数据,为空,但是有一对大括号,
所以不能用null判断,应该用isEmpty判断
情况三:连接中断异常,导致map为null
*/
Map<String, String> map = jedis.hgetAll("student:"+id);
//查询到数据则返回数据内容,map不为null且不为空,才算查询数据成功
if(map!=null&&!map.isEmpty()){
//缓存中的这一条数据被访问,则刷新过期时间为30秒
jedis.expire("student:"+id,30);
return "redis---"+map.toString();
}
jedis.close();
}catch (Exception e){
System.out.println("redis查询失败");
e.printStackTrace();
}finally {
jedis.close();
}
//如果在缓冲中没有查询到数据,那么就到mysql中查询数据
//然后将查询到的数据存储在缓存中
Students students = userdao.loginStudent(id);
//mysql的查询结果stu,也有两种结果,查询成功则有值,查询失败则为null
if(students==null){
return "用户不存在";
}
//查询到数据,则将数据存储到缓存中
//因为选择redis的hash数据结构存储数据,所以key值为String,value值为HashMap
//这里创建一个HashMap对象用来存储数据,然后插入redis数据库中
try {
Map<String, String> stu = new HashMap<>();
stu.put("id",students.getId());
stu.put("name",students.getName());
stu.put("age",students.getAge());
stu.put("sex",students.getSex());
stu.put("clazz",students.getClazz());
System.out.println(stu);
//注意这里要用 hmet 批量插入,因为HashMap对象stu中有多个键值对
//如果只有一个键值对使用hset,多个键值对批量插入用hmet
jedis.hmset("student:"+id,stu);
//给放入缓存中的每一条数据设置一个过期时间30秒
jedis.expire("student:"+id,30);
}catch (Exception e){
System.out.println("redis存储失败");
e.printStackTrace();
}finally {
jedis.close();
}
return "mysql---"+students.toString();
}
}
持久化层(Dao层)
接口
package com.shujia.spring.mvc1.dao;
import com.shujia.spring.mvc1.bean.Students;
public interface UserDao {
public Students loginStudent(String id);
}
package com.shujia.spring.mvc1.dao;
import com.shujia.spring.mvc1.bean.Students;
import com.shujia.spring.mvc1.bean.User;
import com.shujia.spring.util.JDBCUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class UserDaoImpl implements UserDao {
public Students loginStudent(String id){
Students students=null;
try {
Connection conn = JDBCUtil.getConn();
PreparedStatement ps = conn.prepareStatement("select * from studentTest where id=?");
ps.setString(1,id);
ResultSet rs = ps.executeQuery();
if (rs.next()){
students=new Students();
students.setId(rs.getString("id"));
students.setName(rs.getString("name"));
students.setAge(rs.getString("age"));
students.setSex(rs.getString("sex"));
students.setClazz(rs.getString("clazz"));
}
rs.close();
ps.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
return students;
}
}
mysql数据库的连接池
package com.shujia.spring.util;
import org.apache.commons.dbcp2.BasicDataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class JDBCUtil {
private static BasicDataSource bds;
static {
System.out.println("创建连接池");
bds = new BasicDataSource();
bds.setInitialSize(5);
bds.setUrl("jdbc:mysql://master:3306/show1?useUnicode=true&characterEncoding=utf-8");
bds.setDriverClassName("com.mysql.jdbc.Driver");
bds.setUsername("root");
bds.setPassword("123456");
}
public static Connection getConn(){
System.out.println("获取连接");
try {
return bds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
Redis数据库的连接池
Redis数据库的连接池需要Jedis工具,利用maven导入相关jar包
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.0.0</version>
</dependency>
package com.shujia.spring.util;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class RedisUtil {
private static JedisPool jedisPool;
static {
//创建连接池对象
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
//设置连接池的最大连接数
jedisPoolConfig.setMaxTotal(5);
//设置连接失败时的最大等待时间
jedisPoolConfig.setMaxWaitMillis(100);
//配置连接到redis数据库的连接信息
jedisPool= new JedisPool(jedisPoolConfig,"master",6379);
}
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
接下来就可以运行程序,尝试查询一条id为15001000086的数据
右小角有第一条查询这条数据时的用时,用时为477毫秒,这里是从mysql数据库中查询数据
然后第二次查询这条数据,可以发现用时降低到了13毫秒,这里是从缓存中查询得到的
过了30秒后,再次查询这条数据
会发现结果的最前面的信息,又从redis变成了mysql,说明这条数据超过了设置的过期时间,已经被缓存删除,所以又从mysql数据库中查询。
更多推荐
所有评论(0)