Redis
- Redis定位是缓存,提高数据读写速度,减轻对数据库存储与访问压力
- Redis 不建议存储敏感数据
Docker 创建Redis容器
docker run \
--restart always \
--log-opt max-size=100m \
--log-opt max-file=2 \
-p 6379:6379 \
--name redis \
-v /redis/myredis/myredis.conf:/etc/redis/redis.conf \
-v /redis/myredis/data:/data \
-d redis redis-server /etc/redis/redis.conf \
--appendonly yes \
--requirepass 123
简易设置
docker run -d --restart always --name redis -p 6379:6379 redis:latest --requirepass 123
Redis数据类型
常用:string(字符串),hash(哈希),list(列表),set(集合),zset(sorted set:有序集合)
不常用: HyperLogLog,Bitmap(位图),Bloom Filter(布隆过滤器),Geospatial(地理位置),Module(模块),Stream(流)
- string指令
- 应用场景
- 自增
- 登录session共享
- hash指令
- 应用场景
- 共享session
- list指令
应用场景
- 用户文章收藏列表
- set指令(无序)
- 应用场景
- 去重
- 抽奖
- Sorted set指令(有序)
- 应用场景
- 排行榜
Value设计
考虑方式:
- 是否需要排序?需要则使用Sorted set
- 缓存数据是单个值还是多个值
- 多个值:允许重复选List,不允许重复的Set
- 单个值:简单值选择string,对象值选择hash
Key的设计
- 唯一性
- 可读性
- 灵活性
- 时效性
Redis持久化机制
- 快照方式(RDB, Redis DataBase)
- 文件追加方式(AOF, Append Only File)
- 混合持久化方式(混合使用RDB和AOF)
SpringBoot整合Redis
创建项目
- 创建maven空项目,添加boot版本
<!-- boot版本 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.7.RELEASE</version>
</parent>
添加依赖
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Redis依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 通用池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<!-- 通用mapper -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
配置
- 创建application.yml
# 端口、mysql数据源、redis、mybatis、log
server:
port: 8080
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC
redis:
host: 192.168.150.128
port: 6379
password: 123
timeout: 1000
jedis:
pool:
min-idle: 5
max-idle: 10
max-wait: -1
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.company.redisDemo.entity
configuration:
map-underscore-to-camel-case: true
业务实现
reids简单实现
创建
@SpringBootApplication
public class RedisDemoApplication {
public static void main(String[] args) {
SpringApplication.run(RedisDemoApplication.class);
}
}
@RestController
public class RedisController {
@Autowired
private RedisTemplate redisTemplate;
@GetMapping("/redis/get/{key}")
public Object get(@PathVariable("key") String key) {
return redisTemplate.opsForValue().get(key);
}
@PostMapping("redis/set/{key}/{value}")
public Object set(@PathVariable("key")String key,@PathVariable("value")String value) {
redisTemplate.opsForValue().set(key, value);
return "set success";
}
}
- 自定义序列化,创建RedisConfig
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<String, Object> redisTemplate=new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(factory);
//指定kv序列化方式
Jackson2JsonRedisSerializer jsonRedisSerializer=new Jackson2JsonRedisSerializer(Object.class);
//redisTemplate.setDefaultSerializer(jsonRedisSerializer);
redisTemplate.setValueSerializer(jsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
}
结合mybatis
- 新建数据库表sql
CREATE TABLE emp (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100),
age INT
);
- 创建实体类
@Data
@Table(name = "emp")
public class Emp implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private Integer age;
}
- 创建mapper接口
public interface EmpMapper extends Mapper<Emp> {
}
- 创建service接口
public interface EmpService {
public void addEmp(Emp emp);
public Emp getEmpById(Integer id);
}
- 创建serviceimpl实现类
@Service
public class EmpServiceImpl implements EmpService{
@Resource
private EmpMapper empMapper;
public void addEmp(Emp emp) {
// TODO Auto-generated method stub
empMapper.insert(emp);
}
public Emp getEmpById(Integer id) {
// TODO Auto-generated method stub
return empMapper.selectByPrimaryKey(id);
}
}
- redis结合mybatis
@Service
public class EmpServiceImpl implements EmpService{
@Resource
private EmpMapper empMapper;
@Autowired
private RedisTemplate redisTemplate;
public void addEmp(Emp emp) {
// TODO Auto-generated method stub
empMapper.insert(emp);
}
public Object getEmpById(Integer id) {
// TODO Auto-generated method stub
//先从缓存查询数据,如果有则直接返回
//如果无则查询mysql,并将数据设置到缓存
String key= "user:"+id;
Object userObj=redisTemplate.opsForValue().get(key);
if(userObj==null) {
synchronized (this.getClass()) { //同步代码块,防止高并发时多次访问数据库
userObj=redisTemplate.opsForValue().get(key);
if(userObj==null) {
System.out.println("----->查询数据库");
Emp emp=empMapper.selectByPrimaryKey(id);
redisTemplate.opsForValue().set(key, emp);
return emp;
}else {
System.out.println("----->查询缓存(同步代码块)");
return userObj;
}
}
}
System.out.println("----->查询缓存");
return userObj;
}
}
- 在EmpController添加方法做测试
@GetMapping("/empp/{id}")
public Object getEmpByIdT(@PathVariable("id") Integer id) {
ExecutorService eService=Executors.newFixedThreadPool(200);
for(int i=0;i<500;i++) {
eService.submit(new Runnable() {
public void run() {
// TODO Auto-generated method stub
empService.getEmpById(id);
}
});
}
return empService.getEmpById(id);
}