一、Redis基础知识学习
1.缓存的引入
1.1 当我们直接使用mysql时,要考虑高并发的问题,当很多人同一个时间段内访问数据库时会给数据库造成极大的压力
1.2 缓存:减少数据库访问次数(利用空间换时间)
1.3 使用缓存的出现的问题:数据同步
1.4 可用的解决方式:只要有任何增删改的操作就清空缓冲(但是不建议)
1.5 使用缓存场景:数据经常查询,增删改比较少
1.5 redis作用:用来做缓存用的
2.Redis的概念
Redis(全称:Remote Dictionary Server 远程字典服务)
2.1 开源、免费、高性能、非关系型数据库
2.2 可基于内存亦可持久化的日志型、Key-Value数据库
2.3 Redis的默认端口:6379
关系型数据库(mysql)和非关系型数据库(redis)的区别
关系型数据库:既可以存储数据,又可以存储数据与数据之间的关系
sql:结构化查询语言去操作关系型数据库
User表
id|username|password
1 | tom | 123
2 | jerry | 456
3 | color7 | 789
Order表
id|money|uid
1 |1000 | 1
2 |2000 | 1
3 |1200 | 2
存储数据关系解释:
1.在User表中,单个的id username password的数据并没有意义,而关系型数据库就可以将这些毫无关系的数据联系起来,变成一个有意义的数据--用户信息
2.在多表连接中,我们可以通过Order表的uid去找到User表的id,然后两种表就可以产生联系
非关系型数据库:只能存储数据,不能存储数据与数据之间的联系
不能使用sql语言去操作这种类型的数据库,只能通过命令行的形式去操作
id:1
username:tom
password:123
二、Redis的安装和启动
1.Redis下载地址
1.1 官网:https://redis.io/
1.2 百度网盘下载地址
链接:https://pan.baidu.com/s/1LVH3sCE9sMos8EXJ3oHBWg
提取码:fwlr
复制这段内容后打开百度网盘手机App,操作更方便哦
2.直接解压即可使用
3.点击redis-server.exe启动服务,服务启动后不要关闭窗口
4.点击redis-cli.exe启动客户端
三、Redis的使用
1.Redis的特点
1.1 数据默认都是存储在内存中的
1.2 以key-value键值对形式存储的
2.Redis通过key-value存储数据
2.1 key是固定的字符串类型
2.2 value有五种数据类型(数据结构)
string(字符串)
hash(哈希)
list(列表)
set(集合)
zset(sorted set:有序集合)
3.Redis文档:https://www.runoob.com/redis/redis-backup.html
4.Redis命令
四、Redis的持久化
1.什么是持久化
redis是一个内存数据库,当redis服务器重启,获取电脑重启,数据会丢失,我们可以将redis内存中的数据持久化保存到硬盘的文件中(备份)。
2.Redis持久化机制
1. RDB:默认方式,不需要进行配置,默认就使用这种机制
* 在一定的间隔时间中,检测key的变化情况,然后持久化数据
1. 编辑redis.windwos.conf文件
# after 900 sec (15 min) if at least 1 key changed
save 900 1
# after 300 sec (5 min) if at least 10 keys changed
save 300 10
# after 60 sec if at least 10000 keys changed
save 60 10000
2. 重新启动redis服务器,并指定配置文件名称
redis-2.8.9>redis-server.exe redis.windows.conf
2. AOF:日志记录的方式,可以记录每一条命令的操作。可以每一次命令操作后,持久化数据
1. 编辑redis.windwos.conf文件
appendonly no(关闭aof) --> appendonly yes (开启aof)
# appendfsync always : 每一次操作都进行持久化
# appendfsync everysec : 每隔一秒进行一次持久化
# appendfsync no : 不进行持久化
3.Redis的事务命令
redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days"
QUEUED
redis 127.0.0.1:6379> GET book-name
QUEUED
redis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series"
QUEUED
redis 127.0.0.1:6379> SMEMBERS tag
QUEUED
redis 127.0.0.1:6379> EXEC
1) OK
2) "Mastering C++ in 21 days"
3) (integer) 3
4) 1) "Mastering Series"
2) "C++"
3) "Programming"
五、Jedis:java操作redis的客户端,类似于jdbc
1.导入依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.7.2</version>
</dependency>
2.创建jedis客户端
//1.创建redis的连接对象
Jedis jedis = new Jedis("localhost",6379);
//2.通过连接操作redis
jedis.set("name","fox");
String value = jedis.get("name");
System.out.println(value);
//3.释放ziyuan
jedis.close();
3.maven-java项目的redis效果演示
六、Jedis工具类
1.在resources中新建一个jedis.properties
jedis.host=localhost
jedis.port=6379
jedis.maxIdle=5000
jedis.maxTotal=50
jedis.maxWaitMillis=50
2.新建一个JedisUtils的工具类
package com.bianyiit.util;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.io.IOException;
import java.util.Properties;
/**
* 获取连接池,直接从连接池中获取连接
*/
public class JedisUtils {
private static JedisPool jedisPool;
static {
Properties properties = new Properties();
try {
properties.load(JedisUtils.class.getClassLoader().getResourceAsStream("jedis.properties"));
} catch (IOException e) {
e.printStackTrace();
}
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(Integer.parseInt(properties.getProperty("jedis.maxIdle")));
jedisPoolConfig.setMaxTotal(Integer.parseInt(properties.getProperty("jedis.maxTotal")));
jedisPoolConfig.setMaxWaitMillis(Integer.parseInt(properties.getProperty("jedis.maxWaitMillis")));
String host = properties.getProperty("jedis.host");
int port = Integer.parseInt(properties.getProperty("jedis.port"));
jedisPool=new JedisPool(jedisPoolConfig,host,port);
}
/**
* 获取jedis连接池
* @return
*/
public static JedisPool getJedisPool(){
return jedisPool;
}
/**
* 获取jedis连接对象
* @return
*/
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
3.测试JedisUtils是否正确
4.注意:Maven的控制台乱码问题解决方案
七、在maven-javaweb项目中使用Redis加快查询速度
1.配置好项目的pom.xml全局配置文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.bianyiit</groupId>
<artifactId>day12_redis_role</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>day12_redis_role Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!--json转换相关依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<!--jedis依赖-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.7.2</version>
</dependency>
<!--jdbcTemplate依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<!--druid连接池依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--数据库驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--web相关依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<!--junit依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>day12_redis_role</finalName>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!-- 指定端口 -->
<port>8080</port>
<!-- 请求路径 -->
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.在src/main/resources下创建两个配置文件
druid.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/login
username=root
password=123
initialSize=5
maxActive=10
maxWait=3000
jedis.properties
jedis.host=localhost
jedis.port=6379
jedis.maxIdle=5000
jedis.maxTotal=50
jedis.maxWaitMillis=5000
3.在src/mian/java下新建五个包
4.在util下新建两个工具类
JdbcUtils
package com.bianyiit.util;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class JdbcUtils {
private static DataSource dataSource;
static {
try {
Properties properties = new Properties();
InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
properties.load(is);
dataSource = DruidDataSourceFactory.createDataSource(properties);
}catch (Exception e){
}
}
/**
* 从连接池中获取连接
* @return
*/
public static Connection getConnection(){
try {
return dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
/**
* 获取连接池
* @return
*/
public static DataSource getDataSource(){
return dataSource;
}
}
JedisUtils
package com.bianyiit.util;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.io.IOException;
import java.util.Properties;
public class JedisUtils {
private static JedisPool jedisPool;
static {
Properties properties = new Properties();
try {
properties.load(JedisUtils.class.getClassLoader().getResourceAsStream("jedis.properties"));
} catch (IOException e) {
e.printStackTrace();
}
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(Integer.parseInt(properties.getProperty("jedis.maxIdle")));
jedisPoolConfig.setMaxTotal(Integer.parseInt(properties.getProperty("jedis.maxTotal")));
jedisPoolConfig.setMaxWaitMillis(Long.parseLong(properties.getProperty("jedis.maxWaitMillis")));
String host = properties.getProperty("jedis.host");
int port = Integer.parseInt(properties.getProperty("jedis.port"));
jedisPool = new JedisPool(jedisPoolConfig,host,port);
}
/**
* 获取jedis连接池
* @return
*/
public static JedisPool getJedisPool(){
return jedisPool;
}
/**
* 获取jedis对象
* @return
*/
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
5.在WEB-INF/新建一个register.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>网站注册页面</title>
<style>
#contanier{
border: 0px solid white;
width: 1300px;
margin: auto;
}
#form{
height: 500px;
padding-top: 70px;
margin-bottom: 10px;
}
a{
text-decoration: none;
}
.error{
font-family:georgia;
font-size: 15px;
font-style: normal;
color: red;
}
#father{
border: 0px solid white;
padding-left: 307px;
}
#form2{
border: 5px solid gray;
width: 660px;
height: 450px;
}
</style>
<script type="text/javascript" src="./js/jquery-1.11.0.min.js" ></script>
<script>
/**
* 校验用户名是否可用
* 1.给用户名输入框注册失去焦点的事件
* 2.获取用户输入的用户名
* 3.将用户输入的用户名传递到服务器
*/
$(function () {
$.get("/findAll",{},function (data) {
for (let i = 0; i < data.length; i++) {
var option = "<option>"+data[i].username+"</option>"
$("#role_list").append(option)
}
});
$("#btn_form").click(function () {
for (let j = 0; j < 3000; j++) {
$.get("/findAll?time="+new Date().getTime(),{},function (data) {})
}
})
})
</script>
</head>
<body>
<div id="contanier">
<div id="form">
<form action="#" method="get" id="registForm">
<div id="father">
<div id="form2">
<table border="0px" width="100%" height="100%" align="center" cellpadding="0px" cellspacing="0px" bgcolor="white">
<tr align="center">
<td colspan="2" >
<font size="5">会员注册</font>
</td>
</tr>
<tr align="center" >
<td colspan="2" >
<div id="error_msg" style="display: none" class="error">错误信息</div>
</td>
</tr>
<tr align="center">
<td width="180px">
<label for="user" >用户名</label>
</td>
<td>
<em style="color: red;">*</em>
<input type="text" name="username" size="35px" id="user"/>
<span id="errorMsg_username"></span>
</td>
</tr>
<tr align="center">
<td>
密码
</td>
<td>
<em style="color: red;">*</em>
<input type="password" name="password" size="35px" id="password" />
<span id="errorMsg_password"></span>
</td>
</tr>
<tr align="center">
<td>
确认密码
</td>
<td>
<em style="color: red;">*</em>
<input type="password" name="repassword" size="35px"/>
</td>
</tr>
<tr align="center">
<td>
Email
</td>
<td>
<em style="color: red;">*</em>
<input type="text" name="email" size="35px" id="email"/>
</td>
</tr>
<tr align="center">
<td>
用户角色
</td>
<td>
<em style="color: red;">*</em>
<select id="role_list">
<option>--请求选择--</option>
</select>
</td>
</tr>
<tr align="center">
<td>
姓名
</td>
<td>
<em style="color: red;">*</em>
<input type="text" name="username" size="35px"/>
</td>
</tr>
<tr align="center">
<td>
性别
</td>
<td>
<span style="margin-right: 155px;">
<em style="color: red;">*</em>
<input type="radio" name="sex" value="男"/>男
<input type="radio" name="sex" value="女"/>女<em></em>
</span>
</td>
</tr>
<tr align="center">
<td>
出生日期
</td>
<td>
<em style="color: red;">*</em>
<input type="text" name="birthday" size="35px"/>
</td>
</tr>
<tr align="center">
<td colspan="2">
<input id="btn_form" type="button" value="注 册" height="50px"/>
</td>
</tr>
</table>
</div>
</div>
</form>
</div>
</div>
</body>
</html>
6.在domain下新建一个Role类
package com.bianyiit.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
public class Role {
private int id;
private String username;
/*忽略这个字段,在转json字符串的时候,加上这个注解的字段不会被转换到json中*/
@JsonIgnore
private String password;
/*设置当前当前字段转换的一个基本日期格式*/
@JsonFormat(pattern="yyyy-MM-dd")
private String birthday;
private String sex;
private String email;
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", email='" + email + '\'' +
'}';
}
}
7.在web下创建FindAllServlet
package com.bianyiit.web;
import com.bianyiit.services.RoleService;
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;
@WebServlet("/findAll")
public class FindAllServlet extends HttpServlet {
RoleService roleService = new RoleService();
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
String roleList = roleService.findAll();
response.getWriter().println(roleList);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
8.在service下创建一个RoleService
package com.bianyiit.services;
import com.bianyiit.dao.RoleDao;
import com.bianyiit.domain.Role;
import com.bianyiit.util.JedisUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import redis.clients.jedis.Jedis;
import java.util.List;
public class RoleService {
int i = 0;
public String findAll() {
Jedis jedis = JedisUtils.getJedis();
String roleList_json = jedis.get("roleList");
if (roleList_json== null || roleList_json.length()==0){
System.out.println("调用dao从数据库查询所有角色");
List<Role> roleList = new RoleDao().findAll();
ObjectMapper mapper = new ObjectMapper();
try {
roleList_json = mapper.writeValueAsString(roleList);
jedis.set("roleList", roleList_json);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}else {
System.out.println("从redis中获取数据" + i++);
}
jedis.close();
return roleList_json;
}
}
9.在dao下创建RoleDao类
package com.bianyiit.dao;
import com.bianyiit.domain.Role;
import com.bianyiit.util.JdbcUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
public class RoleDao {
public List<Role> findAll() {
JdbcTemplate template = new JdbcTemplate(JdbcUtils.getDataSource());
String sql = "select * from usermsg";
List<Role> roleList = template.query(sql, new BeanPropertyRowMapper<Role>(Role.class));
return roleList;
}
}
10.模拟2000个用户同时访问的效果
解释:由于redis基于内存的,所以除了在第一次用户需要访问磁盘的数据库内容之外,其它的用户可以直接在内存中的redis中取出数据,而且采用了redis的线程池,它明显比直接访问数据库速度要快的多,而且不会轻易崩溃!!