1. pom.xml 文件中添加 Redis 依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
	<exclusions>
		<exclusion>
			<groupId>io.lettuce</groupId>
			<artifactId>lettuce-core</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
</dependency>

2. application.properties 文件中添加 Redis 相关配置

spring.redis.host=10.112.77.2
spring.redis.port=6379
spring.redis.database=0
spring.redis.password=
spring.redis.timeout=1s

spring.redis.jedis.pool.min-idle=5
spring.redis.jedis.pool.max-active=10
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.max-wait=2s

3. 在代码相关位置使用 @Resource 注入 RedisTemplate 或者 @Autowired 注入 StringRedisTemplate

@Controller
@RequestMapping("/user")
public class UserController {
	@Resource
	private RedisTemplate<String, String> redisTemplate;
	@Autowired
	private StringRedisTemplate stringRedisTemplate;

	@RequestMapping("/testRedis")
	@ResponseBody
	public Integer testRedis() {
		stringRedisTemplate.opsForValue().set("str1", "str11");
		stringRedisTemplate.opsForList().leftPush("list1", "list11");
		stringRedisTemplate.opsForHash().put("map1", "key1", "value1");
		stringRedisTemplate.opsForSet().add("set1", "set11", "set22");
		stringRedisTemplate.opsForZSet().add("zset1", "zset11", 1.0);
		Set<String> set = stringRedisTemplate.opsForSet().members("set1");
		Object value = stringRedisTemplate.opsForHash().get("map1", "key1");
		return 1;
	}
}
@RequestMapping("/testRedis2")
@ResponseBody
public Integer testRedis2() {
    // 使用boundSetOps进行对应key的频繁操作
	BoundSetOperations<String, String> boundSetOperations = stringRedisTemplate.boundSetOps("set1");
	boundSetOperations.add("set33", "set44", "set55");
	return 1;
}

4. 在 SpringBoot 主类中设置 redis 序列化方式

@PostConstruct 注解修饰非静态的 void 方法, 在 servlet 的构造方法之后 init() 方法之前执行

@PreDestory 注解修饰的非静态的 void 方法, 会在 servlet 的 destory() 方法之前执行 

@PostConstruct
public void initRedisTemplate() {
	RedisSerializer<String> stringSerializer = redisTemplate.getStringSerializer();
	redisTemplate.setKeySerializer(stringSerializer);
	redisTemplate.setStringSerializer(stringSerializer);
	redisTemplate.setHashKeySerializer(stringSerializer);
}

5. 使用 SessionCallback 和 RedisCallback 接口

通过使用这两个接口让 RedisTemplate 回调, 可以在同一条连接下执行多条 Redis 命令, 避免 RedisTemplate 多次获取不同的连接

SessionCallback 是封装良好, 对开发者友好, 实际的开发中尽量选择使用它

RedisCallback 接口比较底层, 需要处理的比较多, 可读性差, 实际开发中尽量不使用它

6. Redis 的事务

SpringBoot 整合 Redis-LMLPHP

watch......multi......exec 是 Redis 的事务流程

watch 监控 redis 的一些键值是否发生变化, multi 开始事务, 开启事务后, 不会马上执行命令, 而是存放在一个队列里, exec 命令是执行事务, 如果 watch 监控的键值发生变化(哪怕新值和原值一样, 也是发生变化), 就取消事务的执行, 如果键值没有发生变化, 就执行事务. 执行事务的时候, 如果执行某条命令报错, 也只能是报错, 后面的命令会正常执行, 这是和数据库事务不一样的地方, 所以 redis 的事务时, 要不都执行, 要不都不执行, 数据库事务是要不都成功, 要不都失败.

// 貌似 executePipelined() 流水线方法是不能用来执行事务的.
stringRedisTemplate.execute(new SessionCallback<Object>() {
	@SuppressWarnings({"unchecked", "rawtypes" })
	@Override
	public Object execute(RedisOperations operations) throws DataAccessException {
		operations.watch("str1");
		operations.multi();
		operations.opsForValue().set("str2", "str2");
		operations.opsForValue().set("str3", "str3");
		operations.exec();
		return null;
	}
});

7. Redis 的流水线

executePipelined() 方法用来批量执行语句, 性能高

@RequestMapping("/testRedis5")
@ResponseBody
public Integer testRedis5() {
	long start = System.currentTimeMillis();
	stringRedisTemplate.executePipelined(new SessionCallback<Object>() {
		@SuppressWarnings({ "rawtypes", "unchecked" })
		@Override
		public Object execute(RedisOperations operations) throws DataAccessException {
			for (int i = 0; i < 100000; i++) {
				operations.opsForValue().set("str_" + i, "value_"+i);
				String value = (String) operations.opsForValue().get("strr" + i);
				if (i == 900) {
					System.out.println("值为 " + value);
				}
			}
			return null;
		}
	});
	System.out.println("time: " + (System.currentTimeMillis() - start));
	return 1;
}
01-22 23:37