客户端
1. jedis
- Redis不仅是使用命令来操作,现在基本上主流的语言都有客户端支持,比如java、C、C#、C++、php、Node.js、Go等
- 在官方网站里列一些Java的客户端,有Jedis、Redisson、Jredis、JDBC-Redis、等其中官方推荐使用Jedis和Redisson
- Jedis同样也是托管在github上,地址:GitHub - redis/jedis: Redis Java client
- Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个 Jedis实例增加物理连接,官方推荐
2. Lettuce
- Lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,应为StatefulRedisCon最ection是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。
- 在SpringBoot Data Redis1.X之前默认使用的是Jedis,但目前最新版的修改成了Lettuce。
Jedis
Spring Data Redis 版本 Jedis 版本
1.7.x 2.9.0
2.0.x 2.9.0
2.1.x 2.9.0
2.2.x 3.2.0
2.3.x 3.2.0
2.4.x 3.6.0
#最大活动对象数
redis.pool.maxTotal=1000
#最大能够保持idel状态的对象数
redis.pool.maxIdle=100
#最小能够保持idel状态的对象数
redis.pool.minIdle=50
#当池内没有返回对象时,最大等待时间
redis.pool.maxWaitMillis=10000
#当调用borrow Object方法时,是否进行有效性检查
redis.pool.testOnBorrow=true
#当调用return Object方法时,是否进行有效性检查
redis.pool.testOnReturn=true
#“空闲链接”检测线程,检测的周期,毫秒数。如果为负值,表示不运行“检测线程”。默认为-1.
redis.pool.timeBetweenEvictionRunsMillis=30000
#向调用者输出“链接”对象时,是否检测它的空闲超时;
redis.pool.testWhileIdle=true
# 对于“空闲链接”检测线程而言,每次检测的链接资源的个数。默认为3.
redis.pool.numTestsPerEvictionRun=50
#redis服务器的IP
redis.ip=xxxxxx
#redis服务器的Port
redis1.port=6379
引入配置
<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>
spring:
data:
redis:
host: 82.157.62.33
password: du123
port: 6899
database: 8
lettuce:
pool:
max-active: 30
max-idle: 10
max-wait: 12
min-idle: 3
# 释放连接的扫描间隔(毫秒)
time-between-eviction-runs: 3000
enabled: true
序列化
默认使用 jdk 序列化 二进制
1. 对象必须实现序列化接口
2. 默认使用的JDK的序列化
RedisDemoBean redisDemoBean = new RedisDemoBean();
redisDemoBean.setAa("ss");
redisDemoBean.setTrh("dd");
redisTemplate.opsForValue().set("dd",redisDemoBean);
配置序列化
@Configuration
public class RedisTemplateConfiguration {
@Bean("redisTemplate")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
Jackson2JsonRedisSerializer<Object> objectJackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);
// 设置key和value的序列化规则
redisTemplate.setValueSerializer(objectJackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(objectJackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
@SpringBootTest
public class JsonTest {
@Autowired
RedisTemplate<String,Object> redisTemplate;
@Test
public void redisTempTestMy(){
UserBean build = UserBean.builder().age(11).password("oo").name("ddd").build();
redisTemplate.opsForValue().set("user007", build);
System.out.println();
}
}
Pipeline管道
Rdis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。当请求进来以后,都是经过服务器进行返回,那如果服务器没有响应时,那么其他请求进入等待。这时服务器也无法处理新请求,那有没有办法解决呢?使用管道就能解决,即:将多个命令发送到服务器,而不用等待回复,最后在一个步骤中读取该答复。这种技术应用非常广泛比如MySQL的批量插入就如此
@SpringBootTest
@Slf4j
public class RestaurantTest {
@Resource
private RedisTemplate redisTemplate;
@Resource
TRestaurantsMapper tRestaurantsMapper;
// 逐行插入
@Test
void testSyncForHash() {
List<TRestaurants> restaurants = tRestaurantsMapper.selectList(null);
TimeInterval timer = DateUtil.timer();
restaurants.forEach(restaurant -> {
Map<String, Object> restaurantMap = BeanUtil.beanToMap(restaurant);
String key = "res" + restaurant.getId();
redisTemplate.opsForHash().putAll(key, restaurantMap);
});
log.info("执行时间:{}", timer.intervalSecond()); // 执行时间:118957
}
/**
* Pipeline 管道插入
*/
@Test
void testSyncForHashPipeline() {
List<TRestaurants> restaurants = tRestaurantsMapper.selectList(null);
TimeInterval timer = DateUtil.timer();
List<Long> list = redisTemplate.executePipelined((RedisCallback<Long>) connection -> {
for (TRestaurants restaurant : restaurants) {
try {
String key = "res" + restaurant.getId();
Map<String, Object> restaurantMap = BeanUtil.beanToMap(restaurant);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
Map<byte[], byte[]> restaurantStringMap = Maps.newHashMap();
restaurantMap.forEach((k, v) -> {
restaurantStringMap.put(stringRedisSerializer.serialize(k), jackson2JsonRedisSerializer.serialize(v));
});
connection.hashCommands().hMSet(stringRedisSerializer.serialize(key), restaurantStringMap);
} catch (Exception e) {
log.info(restaurant.toString());
continue;
}
}
return null;
});
log.info("执行时间:{}", timer.intervalSecond());
}
}