docker启动redis
docker run -p 6379:6379 --name myredis redis
查看容器
[root@topcheer ~]# docker ps -lCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES14b1139f889d f7302e4ab3a8 "docker-entrypoint..." 20 hours ago Up 20 hours 0.0.0.0:6379->6379/tcp myredis[root@topcheer ~]#
注:本文只讲整合,后面补充docker及redis知识
整合Redis
application.yml 配置文件
spring: datasource: username: scott password: tiger url: jdbc:oracle:thin:@//localhost:1521/ORCL driver-class-name: oracle.jdbc.driver.OracleDriver redis: host: 192.168.180.113 port: 6379
pom.xml (选取开发所需的依赖)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.18</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.33</version> </dependency> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc8</artifactId> <version>12.2.0.1.0</version> </dependency>
启动类加上注解
/* 整合redis作为缓存 * Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 * 1、安装redis:使用docker; * 2、引入redis的starter * 3、配置redis * 4、测试缓存 * 原理:CacheManager===Cache 缓存组件来实际给缓存中存取数据 * 1)、引入redis的starter,容器中保存的是 RedisCacheManager; * 2)、RedisCacheManager 帮我们创建 RedisCache 来作为缓存组件;RedisCache通过操作redis缓存数据的 * 3)、默认保存数据 k-v 都是Object;利用序列化保存;如何保存为json * 1、引入了redis的starter,cacheManager变为 RedisCacheManager; * 2、默认创建的 RedisCacheManager 操作redis的时候使用的是 RedisTemplate<Object, Object> * 3、RedisTemplate<Object, Object> 是 默认使用jdk的序列化机制 * 4)、自定义CacheManager; * */@MapperScan("com.topcheer.*.*.dao")@SpringBootApplication@EnableCaching //开启缓存public class Oss6Application { public static void main(String[] args) { SpringApplication.run(Oss6Application.class, args); }}
Web层
/** * @author WGR * @create 2019/9/7 -- 15:14 */@RestController@RequestMapping("/sys/user")@Slf4jpublic class UserController { @Autowired UserService userService; //根据主键查询 @GetMapping("/findById") public R findById(Integer id) { return userService.findById(id); }}
Service层
/** * @author WGR * @create 2019/9/7 -- 15:14 */@Servicepublic class UserService { @Autowired(required = false) UserMapper userMapper; /** * 缓存的数据能存入redis; * 第二次从缓存中查询就不能反序列化回来; * 存的是dept的json数据;CacheManager默认使用RedisTemplate<Object, Employee>操作Redis * * * @param id * @return */ @Cacheable(cacheNames = "user",key="#root.methodName+'['+#id+'}'") public R findById(Integer id) { return R.ok().addData( userMapper.selectById(id) ); }}
注解JSR107缓存说明(当pom加入redis时,生效的是RedisCacheConfiguration)
将方法的运行结果进行缓存;以后再要相同的数据,直接从缓存中获取,不用调用方法; CacheManager管理多个Cache组件的,对缓存的真正CRUD操作在Cache组件中,每一个缓存组件有自己唯一一个名字; 原理: 1、自动配置类;CacheAutoConfiguration 2、缓存的配置类 org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration org.springframework.boot.autoconfigure.cache.GuavaCacheConfiguration org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration【默认】 org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration 3、哪个配置类默认生效:SimpleCacheConfiguration; 4、给容器中注册了一个CacheManager:ConcurrentMapCacheManager 5、可以获取和创建ConcurrentMapCache类型的缓存组件;他的作用将数据保存在ConcurrentMap中; 运行流程: @Cacheable: 1、方法运行之前,先去查询Cache(缓存组件),按照cacheNames指定的名字获取; (CacheManager先获取相应的缓存),第一次获取缓存如果没有Cache组件会自动创建。 2、去Cache中查找缓存的内容,使用一个key,默认就是方法的参数; key是按照某种策略生成的;默认是使用keyGenerator生成的,默认使用SimpleKeyGenerator生成key; SimpleKeyGenerator生成key的默认策略; 如果没有参数;key=new SimpleKey(); 如果有一个参数:key=参数的值 如果有多个参数:key=new SimpleKey(params); 3、没有查到缓存就调用目标方法; 4、将目标方法返回的结果,放进缓存中 @Cacheable标注的方法执行之前先来检查缓存中有没有这个数据,默认按照参数的值作为key去查询缓存, 如果没有就运行方法并将结果放入缓存;以后再来调用就可以直接使用缓存中的数据; 核心: 1)、使用CacheManager【ConcurrentMapCacheManager】按照名字得到Cache【ConcurrentMapCache】组件 2)、key使用keyGenerator生成的,默认是SimpleKeyGenerator 几个属性: cacheNames/value:指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存; key:缓存数据使用的key;可以用它来指定。默认是使用方法参数的值 1-方法的返回值 编写SpEL; #i d;参数id的值 #a0 #p0 #root.args[0] getEmp[2] keyGenerator:key的生成器;可以自己指定key的生成器的组件id key/keyGenerator:二选一使用; cacheManager:指定缓存管理器;或者cacheResolver指定获取解析器 condition:指定符合条件的情况下才缓存; ,condition = "#id>0" condition = "#a0>1":第一个参数的值》1的时候才进行缓存 unless:否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到结果进行判断 unless = "#result == null" unless = "#a0==2":如果第一个参数的值是2,结果不缓存; sync:是否使用异步模式
Dao层
/** * @author WGR * @create 2019/9/7 -- 15:10 */public interface UserMapper extends OssMapper<User> {}
Bo类
@AllArgsConstructor@NoArgsConstructor@Data@TableName("Z010_USER")@KeySequence(value="SEQ_Z010_USER",clazz=Integer.class)public class User implements Serializable{ private static final long serialVersionUID = 1L; @TableId private Integer id; // 主键 private String account; // 账号,唯一,可供登录(同时作为密码的盐值) private String name; // 姓名 @JSONField(serialize=false) private String password; // 密码,MD5盐值加密 @Code private String gender; // 性别,字典 private Date birthday; // 出生日期 @Code private String certType; // 证件类型,字典 private String certNumber; // 证件号码 private String telNumber; // 固定电话 private String mobNumber; // 手机号码 private String faxNumber; // 传真号码 private String email; // 电子邮件,唯一,可供登录 private String empId; // 工号,唯一,可供登录 @Code private String position; // 职位 private Integer managerId; // 直属上级 20180417 @JSONField(format="yyyy-MM-dd") private Date loginLastTime; // 最后登录时间 private Integer loginSuccessCount; // 登录成功次数(成功登录时+1) private String passwordStatus; // 密码状态,0-临时密码 1-永久密码(临时密码登录提示修改密码) private Integer passwordTryCount; // 密码尝试次数(错误累计,成功登录清零) @JSONField(format="yyyy-MM-dd") private Date passwordTryLastTime; // 密码最后尝试时间 @JSONField(format="yyyy-MM-dd") private Date passwordExpiryDate; // 密码过期日期(密码即将过期提示, 已经过期强制修改密码) private String wxOpenid; // 微信公众号openId private String headPic; // 用户头像 private String createUser; // 创建人员 @JSONField(format="yyyy-MM-dd") private Date createTime; // 创建时间 private String modifyUser; // 修改人员 @JSONField(format="yyyy-MM-dd") private Date modifyTime; // 修改时间 @Code private String status; // 状态, 0-禁用 1-启用 @TableLogic @JSONField(serialize=false) private String delFlag; // 数据删除标记, 0-已删除 1-有效 private String remark; // 备注 @TableField(exist=false) private String permType; // 权限类型}
/** * @author WGR * @create 2019/10/10 -- 23:47 */public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> { public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); private Class<T> clazz; static { //开启白名单,不能序列化的时候会报错 ParserConfig.getGlobalInstance().addAccept("com.topcheer.oss."); } public FastJson2JsonRedisSerializer(Class<T> clazz) { super(); this.clazz = clazz; } public byte[] serialize(T t) throws SerializationException { if (t == null) { return new byte[0]; } return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET); } public T deserialize(byte[] bytes) throws SerializationException { if (bytes == null || bytes.length <= 0) { return null; } String str = new String(bytes, DEFAULT_CHARSET); return (T) JSON.parseObject(str, clazz); }}
/** * @author WGR * @create 2019/10/10 -- 23:33 */@Configurationpublic class RedisConfig extends CachingConfigurerSupport { @Bean("redisCacheManager") @Primary public CacheManager cacheManager(RedisConnectionFactory connectionFactory) { //初始化一个RedisCacheWriter RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory); FastJson2JsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJson2JsonRedisSerializer<>(Object.class); RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer); RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair); //设置过期时间 30天 defaultCacheConfig = defaultCacheConfig.entryTtl(Duration.ofDays(30)); //初始化RedisCacheManager RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, defaultCacheConfig); ParserConfig.getGlobalInstance().setAutoTypeSupport(true); // ParserConfig.getGlobalInstance().addAccept("com.topcheer.oss."); return cacheManager; } @Bean(name = "redisTemplate") @SuppressWarnings("unchecked") @ConditionalOnMissingBean(name = "redisTemplate") public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); //使用fastjson序列化 FastJson2JsonRedisSerializer fastJsonRedisSerializer = new FastJson2JsonRedisSerializer(Object.class); // value值的序列化采用fastJsonRedisSerializer template.setValueSerializer(fastJsonRedisSerializer); template.setHashValueSerializer(fastJsonRedisSerializer); // key的序列化采用StringRedisSerializer template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setConnectionFactory(redisConnectionFactory); return template; }}
结果: