Redis事務
- 事務Redis 事務本質: 一組命令的集合!一個事務中的所有命令都會被序列化,在事務執行過程的中,會按照順序執行!一次性、順序性、排他性、執行一些列的命令!
Redis事務沒有沒有隔離級別的概念!
- 所有的命令在事務中,並沒有直接被執行!只有發起執行命令的時候纔會執行!
Redis單條命令式保存原子性的,但是事務不保證原子性!
- redis的事務:
- 開啓事務(multi)
- 命令入隊(…)
- 執行事務(exec)
- 取消事務 (DISCARD)
- 事務隊列中命令都不會被執行!
- 編譯型異常(代碼有問題!命令有錯!),事務中所有的命令都不會被執行!
- 運行時異常(1/0),如果事務隊列中存在語法性,那麼執行命令的時候,其他命令是可以正常執行的,錯誤命令拋出異常!
監控 Watch
- 悲觀鎖: 認爲什麼時候都會出問題,無論做什麼都會加鎖。
- 樂觀鎖: 認爲什麼時候都不會出問題,所以不會上鎖,redis可以當樂觀鎖操作,就是使用watch來監控
- 更新數據的時候去判斷一下,在此期間是否有人修改過這個數據。
- 獲取
version
- 更新的時候比較
versionRedis
測監視測試正常執行成功!
Jedis
Redis
官方推薦的java
連接開發工具!使用Java
操作Redis
中間件!- 所有的命令都和jedis中的方法是一模一樣的
整合SpringBoot
-
SpringBoot
操作數據的有:spring-data jpa jdbc mongodb redis!
-
說明:
在 SpringBoot2.x
之後,原來使用的jedis
被替換爲了lettuce
-
jedis
: 底層採用的直連,如果多個線程操作的話是不安全的,如果想要避免不安全的,使用jedis pool
連接池,這就更像 BIO 模式。 -
lettuce
: 採用netty
,實例可以再多個線程中進行共享,不存在線程不安全的情況!可以減少線程數據了,更像 NIO 模式 -
源碼分析
- RedisAutoConfiguration.java
如下主要代碼如下所示
@Bean
// 我們可以自己定義一個redisTemplate來替換這個默認的!
@ConditionalOnMissingBean(name = {"redisTemplate"})
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
// 默認的 RedisTemplate 沒有過多的設置,redis 對象都是需要序列化!
// 兩個泛型都是 Object, Object 的類型,我們後使用需要強制轉換 <String, Object>
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
// 由於 String 是redis中最常使用的類型,所以說單獨提出來了一個bean!
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
SpringBoot
整合Redis
- 導入依賴
<!-- 操作redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 在
application.properites
中配置連接
# 配置redis
spring.redis.host=127.0.0.1
spring.redis.port=6379
- 測試
@SpringBootTest
class Redis02SpringbootApplicationTests {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Test
void contextLoads() {
redisTemplate.opsForValue().set("mikey","daq");
System.out.println(redisTemplate.opsForValue().get("mikey"));
}
}
- 序列化分析
- 關於對象的保存:所有的對象,都需要序列化
編寫模板RedisTemplate
- 自己定義了一個
RedisTemplate
- 這是一個固定模板,可以直接用
package com.daq.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
// 爲了開發方便,一般直接使用 <String, Object>
RedisTemplate<String, Object> template=new RedisTemplate<String,Object>();
template.setConnectionFactory(factory);
// Json序列化配置
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer=new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om=new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// String 的序列化
StringRedisSerializer stringRedisSerializer=new StringRedisSerializer();
// key採用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也採用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式採用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式採用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}