Redis
之持久化與一致性
一、 對象序列化
1.1. 將對象轉成JSON
字符串
創建一個實體類:
@Data
public class UserEntity {
private String name;
private String pass;
private Integer age;
}
對象轉字符串
@RestController
public class RedisController {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@GetMapping("/addData")
public String add() {
UserEntity userEntity = new UserEntity();
userEntity.setAge(12);
userEntity.setName("張三");
userEntity.setPass("123456");
stringRedisTemplate.opsForValue().set("user", JSONObject.toJSONString(userEntity));
return "success";
}
}
結果:
1.2. 將對象序列化後存儲(二進制)
需要實現序列換接口:
@Data
class UserEntity implements Serializable {
private static final long serialVersionUID = -2700793157456551921L;
private String name;
private String pass;
private Integer age;
}
設置和獲取:
@RestController
public class RedisController {
/** 使用@Autowired會報錯,使用@Resource通過名字獲取注入的類 */
@Resource
private RedisTemplate<String, Object> redisTemplate;
/** 設置 */
@GetMapping("/addData")
public String add() {
UserEntity userEntity = new UserEntity();
userEntity.setAge(12);
userEntity.setName("張三");
userEntity.setPass("123456");
redisTemplate.opsForValue().set("user", userEntity);
return "success";
}
/** 獲取 */
@GetMapping("/getDate")
public UserEntity get() {
UserEntity user = (UserEntity) redisTemplate.opsForValue().get("user");
return user;
}
}
結果:
獲取:
二、 持久化機制
2.1. 全量同步和增量同步的區別
全量同步: 就是每天定時(避開高峯期)或者採用一個週期實現將數據拷貝到一個地方也就是RDB
存儲。
增量同步: 比如採用對行爲的操作實現對數據的同步,也就是AOF
。
全量與增量的比較: 增量同步比全量同步更加消耗服務器的內存,但是能夠更加的保證數據的同步。
2.2. RDB
和AOF
實現持久化的區別
Redis
提供了兩種持久化的機制,分別爲RDB
、AOF
實現,RDB
採用定時(全量)持久化機制,但是服務器因爲某種原因宕機後可能數據會丟失,AOF
是基於數據日誌操作實現的持久化,所以AOF
採用增量同步的方案。
Redis
已經幫助我默認開啓了RDB
存儲。
2.3. Redis
的RDB
同步配置
開啓RDB
同步配置:
# Redis默認採用rdb方式實現數據的持久化,以快照的形式將數據持久化到磁盤的是一個二進制的文件dump.rdb
RDB
相關配置
# Redis會將數據集的快照dump到dump.rdb文件中,可以通過配置文件來修改Redis服務器dump快照的頻率.
save 900 1 # 在900秒(15分鐘)之後,如果至少有1個key發生變化,則dump內存快照。
save 300 10 # 在300秒(5分鐘)之後,如果至少有10個key發生變化,則dump內存快照。
save 60 10000 # 在60秒(1分鐘)之後,如果至少有10000個key發生變化,則dump內存快照。
RDB
同步流程:
2.4. Redis
的AOF
同步配置
AOF
是以執行命令的形式實現同步
開啓AOF
同步:
# redis.conf文件中將 appendonly從no改爲yes
appendonly yes
AOF
相關配置:
appendfsync always # 每次有數據修改發生時都會寫入AOF文件,能夠保證數據不丟失,但是效率非常低。
appendfsync everysec # 每秒鐘同步一次,可能會丟失1s內的數據,但是效率非常高。
appendfsync no # 從不同步。高效但是數據不會被持久化。
同步流程:
三、Springboot
整合註解版Redis
開啓緩衝註解:
@SpringBootApplication
@EnableCaching
public class RedisApplication {
public static void main(String[] args) {
SpringApplication.run(RedisApplication.class, args);
}
}
控制器上使用:
@RestController
public class RedisController {
@GetMapping("/getDate")
@Cacheable(cacheNames = "user", key = "'getDate'")
public UserEntity get() {
UserEntity userEntity = new UserEntity();
userEntity.setAge(12);
userEntity.setName("張三");
userEntity.setPass("123456");
return userEntity;
}
}
這裏需要注意,實體類UserEntity
需要實現序列化的接口,因爲Redis
註解緩衝使用的二進制對象緩衝,否則會報一下SerializationFailedException
異常:
{
"timestamp":"2019-12-02T15:33:34.162+0000",
"status":500,
"error":"Internal Server Error",
"message":"Cannot serialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [com.mly.redis.UserEntity]",
"path":"/getDate"
}
所以實體類需要和上一個例子一樣:
class UserEntity implements Serializable {
private static final long serialVersionUID = -2700793157456551921L;
private String name;
private String pass;
private Integer age;
}
四、 一致性解決同步問題
MySQL
與Redis
一致性問題的解決
- 直接清除
Redis
的緩衝,重新讀取數據庫 - 使用
mq
異步訂閱MySQL
的binlog
實現增量同步- 使用
alibaba
的cancal
github
地址:https://github.com/alibaba/canal/wiki
- 使用
五、所有例子的依賴文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>