是一个基于内存的单线程高性能Key-Value型数据库。整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flash到硬盘上进行保存。因为是纯内存操作,Redis性能非常出色,每秒可以处理超过10万次读写操作,是已知性能最高的Key-Value数据库。
Redis可以存储键和五种不同类型的值之间的映射。键的类型只能为字符串,值支持五种数据类型:string(字符串)、list(列表)、set(集合)、hash(哈希类型)、Sorted Set(有序集合)。
参考https://blog.csdn.net/icetime17/article/details/45767559
创建SpringBoot项目
首先创建Spring Boot Web项目,添加Redis依赖,并添加Redis的缓冲连接池,常用的缓冲连接池为Lettuce和Jedis。Jedis在多线程使用同一个连接时,线程是不安全的,所以要使用连接池,得为每一个Jedis实例分配一个连接。Lettuce在多线程使用统一连接实例时,线程是安全的。Redis默认使用Lettuce连接池,依赖如下:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-pool2artifactId>
dependency>
配置文件
在application.properties中,添加如下配置信息:
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.lettuce.pool.max-wait=-1ms
# 连接池中的最大空闲连接
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
创建实体类
创建一个City类:
package com.shenziyi.db.entity;
import java.io.Serializable;
public class City implements Serializable {
private int id;
private String name;
private String country;
public City(int id, String name, String country) {
this.id = id;
this.name = name;
this.country = country;
}
@Override
public String toString() {
return "City{" +
"id=" + id +
", name='" + name + '\'' +
", country='" + country + '\'' +
'}';
}
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 getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
创建Controller
实体类及Redis的连接信息添加完成后,创建一个CityController进行测试:
package com.shenziyi.db.controller;
import com.shenziyi.db.entity.City;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.GetMapping;
public class CityController {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@GetMapping("/")
public void testRedis(){
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
//添加字符串
ops.set("name", "beixi");
String name=ops.get("name");
System.out.println(name);
ValueOperations opsForValue = redisTemplate.opsForValue();
City city=new City(1, "北京", "中国");
//添加实体类
opsForValue.set("city", city);
Boolean exists = redisTemplate.hasKey("city");
System.out.println("redis是否存在相应的key:"+exists);
//删除
redisTemplate.delete("city");
//更新
redisTemplate.opsForValue().set("city", new City(2, "山西","中国"));
//查询
City c2 = (City) redisTemplate.opsForValue().get("city");
System.out.println("从redis数据库中获取city:"+c2.toString());
}
}
RedisTemplate和StringRedisTemplate都是Spring Data Redis为我们提供的模板类,用来对数据进行操作,都通过Spring提供的Serializer序列化到数据库。其中StringRedisTemplate是RedisTemplate的子类,只针对键值都是字符串的数据进行操作,采用的序列化方案是StringRedisSerializer,而RedisTemplate可以操作对象,采用的序列化方案是JdkSerializationRedisSerializer。在SpringBoot中默认提供这两个模板类,RedisTemplate和StringRedisTemplate都提供了Redis的基本操作方法。
RedisTemplate和StringRedisTemplate还为我们提供了下面几个数据访问方法:
测试:在浏览器中输入http://localhost:8080/访问,观察控制台上打印的日志信息:
也可以使用RedisClient客户端工具查看Redis缓冲数据库中的数据:
在开发中,如果以相同的查询条件频繁查询数据库,会给数据库带来很大的压力。因此,我们需要对查询出来的数据进行缓存,这样客户端只需从数据库查询一次数据,然后放入缓存中,以后再次查询的时候可以从缓存中读取,这样便提高了数据的访问速度,并发步骤如下:
准备工作
开启Redis数据库,创建Spring Boot Web项目。使用MySql数据库创建user表用于项目开发数据的存储,如下:
导入依赖
在pom.xml文件中导入Redis数据库、持久层MyBatis、MySQL驱动等相关依赖(引入MySQL JDBC驱动时要根据自己安装的MySQL版本而定,win+r输入cmd,在终端输入mysql --version查看自己的MySQL版本,我的是8.0.24):
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>1.3.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.24version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
<dependency>
<groupId>redis.clientsgroupId>
<artifactId>jedisartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-cacheartifactId>
dependency>
配置文件
接下来在application.yml中配置Redis连接信息、MySQL数据库连接等相关信息:
server:
port: 8081
#数据库连接
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useUnicode=true
driver-class-name: com.mysql.jdbc.Driver
username: root
password: admin123
## Redis 配置
redis:
## Redis数据库索引(默认为0)
database: 0
## Redis服务器地址
host: localhost
## Redis服务器连接端口
port: 6379
## Redis服务器连接密码(默认为空)
password:
jedis:
pool:
## 连接池最大连接数(使用负值表示没有限制)
#spring.redis.pool.max-active=8
max-active: 8
## 连接池最大阻塞等待时间(使用负值表示没有限制)
#spring.redis.pool.max-wait=-1
max-wait: -1
## 连接池中的最大空闲连接
#spring.redis.pool.max-idle=8
max-idle: 8
## 连接池中的最小空闲连接
#spring.redis.pool.min-idle=0
min-idle: 0
## 连接超时时间(毫秒)
timeout: 1200
#将themilef的默认缓存禁用,热加载生效
thymeleaf:
cache: false
#mybatis的下划线转驼峰配置
configuration:
map-underscore-to-camel-case: true
#另外一种打印语句的方式
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#打印sql时的语句
logging:
level:
com:
acong:
dao: debug
实体类
创建与数据库相对应的User实体类:
package com.shenziyi.db.entity;
import java.io.Serializable;
public class User implements Serializable {
private int id;
private String name;
private String pwd;
public User() {
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
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 getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
创建持久层
接着是Mapper持久层Dao,这里主要用注解写比较方便,也可以使用MyBatis的XML配置文件写SQL语句:
package com.shenziyi.db.Dao;
import com.shenziyi.db.entity.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface UserDao {
@Select("select * from user")
List<User> queryAll();
@Select("select * from user where id = #{id}")
User findUserById(int id);
}
业务层
创建UserService,这里主要使用Redis模板来写:
package com.shenziyi.db.service;
import com.shenziyi.db.Dao.UserDao;
import com.shenziyi.db.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Autowired
private RedisTemplate redisTemplate;
public List<User> queryAll() {
return userDao.queryAll();
}
/**
* 获取用户策略:先从缓存中获取用户,没有则取数据表中 数据,再将数据写入缓存
*/
public User findUserById(int id) {
String key = "user_" + id;
ValueOperations<String, User> operations = redisTemplate.opsForValue();
//判断redis中是否有键为key的缓存
boolean hasKey = redisTemplate.hasKey(key);
if (hasKey) {
User user = operations.get(key);
System.out.println("从缓存中获得数据:" + user.getName());
System.out.println("------------------------------------");
return user;
} else {
User user = userDao.findUserById(id);
System.out.println("查询数据库获得数据:" + user.getName());
System.out.println("------------------------------------");
// 写入缓存
operations.set(key, user, 5, TimeUnit.HOURS);
return user;
}
}
}
控制层
创建UserController,用于暴露访问接口:
package com.shenziyi.db.controller;
import com.shenziyi.db.entity.User;
import com.shenziyi.db.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/queryAll")
public List<User> queryAll(){
List<User> lists = userService.queryAll();
return lists;
}
@RequestMapping("/findUserById")
public Map<String, Object> findUserById(@RequestParam int id){
User user = userService.findUserById(id);
Map<String, Object> result = new HashMap<>();
result.put("id", user.getId());
result.put("name", user.getName());
result.put("pwd", user.getPwd());
return result;
}
}
测试
这里主要使用RedisTemplate来对Redis操作,每次访问controller暴露的接口,首先判断Redis缓存中是否存在该数据,若不存在就从数据库中读取数据,然后保存在Redis缓存中,当下次访问的时候,就直接从缓存中取出来。这样就不用每次都执行SQL语句,能够提高访问速度。但是当数据保存到缓存中时,需要设置键和值及超时删除,注意设置超市删除缓存时间不用太长,否则会给服务器压力。
启动SpringBoot项目,在浏览器输入http://localhost:8081/findUserById?id=1,当我们第一次访问数据时从数据库获取,再次访问时则从缓存中获取保存的数据:(没有id为3的数据,所以报错)
SpringBoot集成MySQL非常简单。SpringBoot连接数据库有四种方式:
采用JDBC方式直接连接烦琐,易错,我们直接略过,不做考虑。通过MyBatis、SpringDataJPA等连接,我们后续再讲。JdbcTemplate在JDBC的基础上做了大量的封装,本节采用JdbcTemplate连接MySQL。
引入依赖
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
添加数据库配置
在application.yml文件中添加如下配置:
spring:
datasource:
#MySQL连接信息 serverTimezone=GMT%2B8解决时区时间差报错问题
url: jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8
# 账号
username: root
# 密码
password: admin123
# 驱动
driver-class-name: com.mysql.jdbc.Driver
设计表和实体
配置完信息之后,在test数据库中新建一张用户表user(之前已建好)
表和数据准备好之后,在项目中新建User实体类:
package com.shenziyi.entity;
public class User {
private int id;
private String name;
private String password;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
控制层
创建UserController类:
package com.shenziyi.controller;
import com.shenziyi.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
@Controller
public class UserController {
@Autowired
JdbcTemplate jdbcTemplate;
@ResponseBody
@RequestMapping("/list")
public List mySqlTest(){
String sql="select * from user";
/*query()是JdbcTemplate对象中的方法,RowMapper对象可以查询数据库中的数据*/
List<User>users=jdbcTemplate.query(sql,new RowMapper<User>(){
@Override
/*RowMapper对象通过调用mapRow()方法将数据库中的每一行数据封装成User对象,并返回*/
public User mapRow(ResultSet rs,int i)throws SQLException {
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setPassword(rs.getString("password"));
return user;
}
});
System.out.println("查询成功: "+users);
return users;
}
}
代码解释如下: