Springboot2.0访问Redis集群
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作高性能的key-value数据库、缓存和消息中间件,掌握它是程序员的必备技能,下面是一个springboot访问redis的demo。
新建一个springboot项目,这里取名spring-boot-demo
项目结构目录如下
pom.xml文件内容
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.carry</groupId> <artifactId>spring-boot-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>spring-boot-demo</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.2.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <mybatis.version>1.3.2</mybatis.version> </properties> <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.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>${mybatis.version}</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <fork>true</fork> </configuration> </plugin> </plugins> </build> </project>
下面我们来配置redis,因为需要用到mysql数据库,这里使用mybatis访问
application.yml文件内容
#mybatis配置
mybatis:
mapper-locations: classpath:mapper/*Mapper.xml
type-aliases-package: com.carry.domain
#数据源
spring:
datasource:
url: jdbc:mysql://192.168.68.100:3306/test
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
#jackson时间格式化
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
#redis配置
redis:
cluster:
nodes: 192.168.68.100:7000,192.168.68.100:7001,192.168.68.101:7000,192.168.68.101:7001,192.168.68.102:7000,192.168.68.102:7001
timeout: 6000ms
password: 123456
lettuce:
pool:
max-active: 8
max-wait: -1ms
max-idle: 8
min-idle: 0
database: 0
新建文件RedisConfig.java,内容如下
package com.carry.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; @Configuration @AutoConfigureAfter(RedisAutoConfiguration.class) public class RedisConfig { @Bean public RedisTemplate<String, Object> redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory) { //redis序列化器 Jackson2JsonRedisSerializer<Object> 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); RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); template.setKeySerializer(jackson2JsonRedisSerializer); template.setValueSerializer(jackson2JsonRedisSerializer); template.setHashKeySerializer(jackson2JsonRedisSerializer); template.setHashValueSerializer(jackson2JsonRedisSerializer); return template; } }
最后在项目启动类SpringBootDemoApplication上加上注解@EnableCaching开启缓存
配置至此结束,下面我们来通过代码来访问redis集群
先写一个访问mysql的mapper,其中只包含一个方法List<User> findAll();
对应SQL语句为select * from user
User实体类跟user表字段一一对应
UserServiceImpl代码内容
package com.carry.service.impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import com.carry.domain.User; import com.carry.mapper.UserMapper; import com.carry.service.UserService; @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Cacheable(value = "findAll", key = "'test'") public List<User> findAll() { System.out.println("如果没打印这句话,说明走了缓存!"); return userMapper.findAll(); } }
UserController代码内容
package com.carry.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import com.carry.domain.User; import com.carry.service.UserService; @RestController public class UserController { @Autowired private UserService userService; @GetMapping("/getUsers") public List<User> getUsers(){ return userService.findAll(); } }
最后启动项目在浏览器中访问http://localhost:8080/getUsers
第一次访问控制台输出“如果没打印这句话,说明走了缓存!”
再次访问控制台则没有输出。
我们通过redis-cli连接redis会发现key值是一个很奇怪的值
其实就是我们在@Cacheable注解配的值拼起来的
需要注意的是key的值需要用单引号''引起来不然会报错
最后写了几个test case,读者自己去运行看看控制台会输出什么
1 package com.carry; 2 3 import java.util.Date; 4 import java.util.HashSet; 5 import java.util.List; 6 import java.util.Map; 7 import java.util.Set; 8 import java.util.concurrent.ExecutorService; 9 import java.util.concurrent.Executors; 10 import java.util.stream.IntStream; 11 12 import org.junit.Test; 13 import org.junit.runner.RunWith; 14 import org.slf4j.Logger; 15 import org.slf4j.LoggerFactory; 16 import org.springframework.beans.factory.annotation.Autowired; 17 import org.springframework.boot.test.context.SpringBootTest; 18 import org.springframework.data.redis.core.Cursor; 19 import org.springframework.data.redis.core.DefaultTypedTuple; 20 import org.springframework.data.redis.core.HashOperations; 21 import org.springframework.data.redis.core.ListOperations; 22 import org.springframework.data.redis.core.RedisTemplate; 23 import org.springframework.data.redis.core.ScanOptions; 24 import org.springframework.data.redis.core.SetOperations; 25 import org.springframework.data.redis.core.StringRedisTemplate; 26 import org.springframework.data.redis.core.ValueOperations; 27 import org.springframework.data.redis.core.ZSetOperations; 28 import org.springframework.test.context.junit4.SpringRunner; 29 30 import com.carry.domain.User; 31 32 @RunWith(SpringRunner.class) 33 @SpringBootTest 34 public class SpringBootDemoApplicationTests { 35 36 private static final Logger log = LoggerFactory.getLogger(SpringBootDemoApplicationTests.class); 37 38 39 @Autowired 40 private StringRedisTemplate stringRedisTemplate; 41 42 @Autowired 43 private RedisTemplate<String, Object> redisCacheTemplate; 44 45 46 @Test 47 public void redisTest() { 48 ExecutorService executorService = Executors.newFixedThreadPool(1000); 49 IntStream.range(0, 1000).forEach(i -> 50 executorService.execute(() -> stringRedisTemplate.opsForValue().increment("kk", 1)) 51 ); 52 } 53 54 @Test 55 public void redisTestString() { 56 stringRedisTemplate.opsForValue().set("carry", "chan"); 57 final String v1 = stringRedisTemplate.opsForValue().get("carry"); 58 log.info("[字符缓存结果] - [{}]", v1); 59 } 60 61 @Test 62 public void redisTestObject() { 63 //以下只演示整合,具体Redis命令可以参考官方文档,Spring Data Redis 只是改了个名字而已,Redis支持的命令它都支持 64 String key = "carry:user:1"; 65 ValueOperations<String, Object> valueOperations = redisCacheTemplate.opsForValue(); 66 valueOperations.set(key, new User(1, "carry", new Date(), "longhua")); 67 //对应 String(字符串) 68 final User user = (User) valueOperations.get(key); 69 log.info("[对象缓存结果] - [{}]", user); 70 } 71 72 @Test 73 public void redisTestList() { 74 ListOperations<String, Object> listOperations = redisCacheTemplate.opsForList(); 75 listOperations.trim("key1", 1, 0); 76 List<Object> list = listOperations.range("key1", 0, -1); 77 log.info("[对象缓存结果] - {}", list); 78 listOperations.leftPush("key1", 1); 79 listOperations.leftPush("key1", 2); 80 listOperations.rightPush("key1", 3); 81 list = listOperations.range("key1", 0, -1); 82 log.info("[对象缓存结果] - {}", list); 83 } 84 85 @Test 86 public void redisTestHash() { 87 HashOperations<String, Object, Object> hashOperations = redisCacheTemplate.opsForHash(); 88 hashOperations.put("hkey", "k1", "v1"); 89 hashOperations.put("hkey", "k2", "v2"); 90 hashOperations.put("hkey", "k3", "v3"); 91 Map<Object, Object> map = hashOperations.entries("hkey"); 92 log.info("[对象缓存结果] - [{}]", map); 93 } 94 95 @Test 96 public void redisTestSet() { 97 SetOperations<String, Object> setOperations = redisCacheTemplate.opsForSet(); 98 setOperations.add("skey", "v1", "v2", "v3", "v4"); 99 Cursor<Object> cursor = setOperations.scan("skey", ScanOptions.NONE); 100 while (cursor.hasNext()) { 101 System.out.println(cursor.next()); 102 } 103 log.info("[对象缓存结果] - [{}]", cursor); 104 } 105 106 @Test 107 public void redisTestZSet() { 108 ZSetOperations<String, Object> zSetOperations = redisCacheTemplate.opsForZSet(); 109 ZSetOperations.TypedTuple<Object> tuple1 = new DefaultTypedTuple<>("v1", 9.6); 110 ZSetOperations.TypedTuple<Object> tuple2 = new DefaultTypedTuple<>("v2", 9.9); 111 Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<>(); 112 tuples.add(tuple1); 113 tuples.add(tuple2); 114 zSetOperations.add("zkey", tuples); 115 Set<Object> set = zSetOperations.range("zkey", 0, -1); 116 log.info("[对象缓存结果] - {}", set); 117 } 118 }