spring cache默认缓存底层是使用CurrentHashMap, 本示例使用redis作为缓存载体
1. pom.xml依赖
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.48</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies>
2. application.yml配置
spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: org.gjt.mm.mysql.Driver url: jdbc:mysql://120.79.xx.xx:3306/demo?useUnicode=yes&characterEncoding=UTF-8&useSSL=false username: root password: 123456 jpa: hibernate: ddl-auto: update show-sql: true cache: type: redis redis: host: 120.79.xx.xx password: 123456 port: 6379 database: 0 timeout: 600ms jedis: pool: max-active: 8 max-wait: -1ms max-idle: 8 min-idle: 0 # 显示 Mybatis 的 SQL logging: level: qinfeng.zheng.springbootredis.repository: debug mybatis: configuration: map-underscore-to-camel-case: true
3. RedisConfig配置
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.condition.ConditionalOnMissingBean; 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.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import java.time.Duration; @Configuration @AutoConfigureAfter(RedisAutoConfiguration.class) public class RedisConfig { // https://www.ibm.com/developerworks/cn/java/know-redis-and-use-it-in-springboot-projects/index.html @Bean public RedisCacheConfiguration cacheConfiguration() { return RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofSeconds(600)) // redis缓存过期时间 .disableCachingNullValues(); } /** * spring cache管理者 * * @param factory * @return */ @Bean public RedisCacheManager cacheManager(RedisConnectionFactory factory) { return RedisCacheManager.builder(factory) .cacheDefaults(cacheConfiguration()) .transactionAware() .build(); } @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { // Jackson 序列方式 Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper om = new ObjectMapper(); // Jackson 默认自动识别 Public 修饰的成员变量、getter、setter // private、protected、public 修饰的成员变量都可以自动识别,无需都指定 getter、setter 或者 public。 // 参考 https://blog.csdn.net/sdyy321/article/details/40298081 om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 对于 8 种基本数据类型及其封装类和 String ,其他的类型在序列化的时候带上该类型和值 // 参考 https://www.jianshu.com/p/c5fcd2a1ab49 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); RedisTemplate<String, Object> template = new RedisTemplate<>(); // Redis 链接 template.setConnectionFactory(redisConnectionFactory); // Redis Key - Value 序列化使用 Jackson template.setKeySerializer(jackson2JsonRedisSerializer); template.setValueSerializer(jackson2JsonRedisSerializer); // Redis HashKey - HashValue 序列化使用 Jackson template.setHashKeySerializer(jackson2JsonRedisSerializer); template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } @Bean @ConditionalOnMissingBean(StringRedisTemplate.class) public StringRedisTemplate stringRedisTemplate( RedisConnectionFactory redisConnectionFactory) { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } }
@Entity @Table(name = "user", schema = "spring") public class User implements Serializable { private static final long serialVersionUID = 413797298970501130L; @Id private String username; private Byte age; public String getUsername() { return username; } public void setUsername(String userName) { this.username = userName; } public Byte getAge() { return age; } public void setAge(Byte age) { this.age = age; } }
持久层即可以使用Mybatis也可以使用JPA
@Mapper public interface UserMapper { /** * 根据用户名 查询用户信息 * * @param username 用户名 * @return 用户信息 */ @Select("Select username, age From user Where username=#{username}") User selectByUsername(String username); /** * 根据用户名更新用户昵称、用户年龄、用户性别 信息 * * @param user 用户信息 */ @Update("Update user Set age=#{age} Where username=#{username}") void update(User user); /** * 根据用户名 删除用户信息 * * @param username 用户名 */ @Delete("Delete From user where username=#{username}") void delete(String username); }
import io.lettuce.core.dynamic.annotation.Param; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import qinfeng.zheng.springbootredis.entity.User; @Repository public interface UserRepository extends JpaRepository<User, String> { /** * 根据用户查询 * * @param username 用户名 * @return 用户信息 */ User findByUsername(@Param("username") String username); }
缓存操作
import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import qinfeng.zheng.springbootredis.entity.User; import qinfeng.zheng.springbootredis.repository.UserMapper; import qinfeng.zheng.springbootredis.repository.UserRepository; import javax.annotation.Resource; import java.time.Duration; @RestController @CacheConfig(cacheNames = "users") // 类级别缓存的一些公共设置 public class RedisController { @Resource private StringRedisTemplate stringTemplate; @Resource private RedisTemplate<String, User> redisTemplate; @Resource private UserRepository userRepository; @Resource private UserMapper userMapper; @RequestMapping("/setString") public String setString(@RequestParam(value = "key") String key, @RequestParam(value = "value") String value) { stringTemplate.opsForValue().set(key, value); return "ok"; } @RequestMapping("/getString") public String getString(@RequestParam(value = "key") String key) { return stringTemplate.opsForValue().get(key); } @RequestMapping(value = "/setUser") public String setUser(@RequestBody User user) { redisTemplate.opsForValue().set(user.getUsername(), user, Duration.ofMinutes(1)); return "ok"; } @RequestMapping("/getUser") public User getUser(@RequestParam(value = "key") String key) { return redisTemplate.opsForValue().get(key); } @RequestMapping("/delUser") public User delUser(@RequestParam(value = "key") String key) { User user = redisTemplate.opsForValue().get(key); redisTemplate.delete(key); return user; } @RequestMapping("/select") @Cacheable(key = "#username") // 将查询结果添加到redis缓存中,redis中的key= cacheNames + key public User select(@RequestParam(value = "username") String username) { return userRepository.findByUsername(username); } @RequestMapping("/update") @CachePut(key = "#user.username") // 修改 public User update(@RequestBody User user) { return userRepository.save(user); } @RequestMapping("/delete") @CacheEvict(key = "#username") // 删除 public User delete(@RequestParam(value = "username") String username) { User user = select(username); userRepository.delete(user); return user; } @RequestMapping("/deleteAllCache") @CacheEvict(allEntries = true) // 删除所有 public String deleteAllCache() { // 删除所有缓存 return "OK"; } @RequestMapping("/mySelect") @Cacheable(value = "users", key = "#username") public User mySelect(@RequestParam(value = "username") String username) { return userMapper.selectByUsername(username); } @RequestMapping("/myUpdate") @CachePut(value = "users", key = "#user.username") public User myUpdate(@RequestBody User user) { userMapper.update(user); return userMapper.selectByUsername(user.getUsername()); } @RequestMapping("/myDelete") @CacheEvict(value = "users", key = "#username") public User myDelete(@RequestParam(value = "username") String username) { userMapper.delete(username); return userMapper.selectByUsername(username); } }
最后一步,在启动类上开启Cache操作
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; @EnableCaching // 启用缓存 @SpringBootApplication public class RedisApplication { public static void main(String[] args) { SpringApplication.run(RedisApplication.class, args); } }
完毕!
感觉使用起来还是挺简单的,只需要添加几个注解即可!
@Cacheable @CacheEvict @CachePut