上幾節講了利用
Mybatis-Plus
這個第三方的ORM框架進行數據庫訪問,在實際工做中,在存儲一些非結構化或者緩存一些臨時數據及熱點數據時,通常上都會用上mongodb
和redis
進行這方面的需求。因此這一章節準備講下緩存數據庫Redis
的集成,同時會介紹下基於Redis
和註解驅動的Spring Cache
的簡單使用。html
你們應該對
Redis
應該比較熟悉了。這幾年也是大行其道的緩存數據庫,目前的memcached
因爲使用場景及其存儲數據結構的單一(不知道如今是否有改善,如今基本沒有接觸了),在工做中也使用的少了。引用官網的簡介,Redis是一個開源的使用ANSI C語言編寫、遵照BSD協議、支持網絡、可基於內存亦可持久化的日誌型、Key-Value數據庫,並提供多種語言的API。前端
推薦redis中國社區:http://www.redis.cn/java
0.本章節以上一章節的示例基礎上進行集成。因此你們可下載第十章節示例或者在章節末尾直接下載本章節示例。git
1.pom依賴github
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
直接引入,相關依賴會自動加載的,這就是springboot
讓人愉悅之處呀。redis
2.application.properties
配置加入redis相關配置spring
配置自動加載類爲:
org.springframework.boot.autoconfigure.data.redis.RedisProperties
,可在屬性文件中點擊某屬性快捷跳轉。注意到其啓動類爲org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
。這裏就不介紹了,後面會寫一篇關於Springboot
自動加載配置的文章。mongodb
# REDIS (RedisProperties) # Redis數據庫索引(默認爲0) spring.redis.database=0 # Redis服務器地址 spring.redis.host=127.0.0.1 # Redis服務器鏈接端口 spring.redis.port=6379 # Redis服務器鏈接密碼(默認爲空) spring.redis.password= # 鏈接池最大鏈接數(使用負值表示沒有限制) spring.redis.pool.max-active=8 # 鏈接池最大阻塞等待時間(使用負值表示沒有限制) spring.redis.pool.max-wait=-1 # 鏈接池中的最大空閒鏈接 spring.redis.pool.max-idle=8 # 鏈接池中的最小空閒鏈接 spring.redis.pool.min-idle=0 # 鏈接超時時間(毫秒) spring.redis.timeout=0
3.通常上經過以上兩步就可以使用了,但工做中通常上是經過StringRedisTemplate
(默認採用string
的序列化,保存key和值時都是經過此序列化策略)接口進行操做,因此這裏直接配置了StringRedisTemplate
bean類。 RedisConfig.java數據庫
/** * * @author oKong * */ @Configuration public class RedisConfig { /** * 定義 StringRedisTemplate ,指定序列化和反序列化的處理類 * @param factory * @return */ @Bean public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) { StringRedisTemplate template = new StringRedisTemplate(factory); 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); //序列化 值時使用此序列化方法 template.setValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } }
4.編寫控制類,測試集成是否生效。 RedisController.java瀏覽器
@RestController @RequestMapping("/redis") @Api(tags = "redis 測試API") public class RedisController { @Autowired StringRedisTemplate redisTemplate; @GetMapping("set/{key}/{value}") @ApiOperation(value="設置緩存") public String set(@PathVariable("key")String key,@PathVariable("value") String value) { //注意這裏的 key不能爲null spring 內部有檢驗 redisTemplate.opsForValue().set(key, value); return key + "," + value; } @GetMapping("get/{key}") @ApiOperation(value="根據key獲取緩存") public String get(@PathVariable("key") String key) { return "key=" + key + ",value=" + redisTemplate.opsForValue().get(key); } }
5.訪問:http://127.0.0.1:8080/swagger-ui.html。 也可直接瀏覽器輸入:
set值
get值
瀏覽器訪問
查看redis記錄:
至此,redis
就集成好了。實際中可根據業務須要進行相關操做,好比緩存session記錄,緩存菜單列表等。
Spring Cache
是Spring
框架提供的對緩存使用的抽象類,支持多種緩存,好比Redis
、EHCache
等,集成很方便。同時提供了多種註解來簡化緩存的使用,可對方法進行緩存。
0.修改RedisConfig
配置類,加入註解@EnableCaching
,同時設置CacheManager
緩存管理類,這裏使用RedisCacheManager
,其餘的管理類還有:SimpleCacheManager
、ConcurrentMapCacheManager
等,默認提供的在類org.springframework.cache.support
下,可自行查閱。
/** * * @author oKong * */ @Configuration @EnableCaching public class RedisConfig { /** * 定義 StringRedisTemplate ,指定序列號和反序列化的處理類 * @param factory * @return */ @Bean public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) { StringRedisTemplate template = new StringRedisTemplate(factory); 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); //序列化 值時使用此序列化方法 template.setValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } @Bean public CacheManager cacheManager(RedisTemplate<String,String> redisTemplate) { RedisCacheManager rcm = new RedisCacheManager(redisTemplate); //使用前綴 rcm.setUsePrefix(true); //緩存分割符 默認爲 ":" // rcm.setCachePrefix(new DefaultRedisCachePrefix(":")); //設置緩存過時時間 //rcm.setDefaultExpiration(60);//秒 return rcm; } }
1.改造UserController
控制層,引入@Cacheable
等註解。
/** * 用戶控制層 簡單演示增刪改查及分頁 * 新增了swagger文檔內容 2018-07-21 * 新增了@caching使用 2018-07-23 * @author oKong * */ @RestController @RequestMapping("/user") @Api(tags="用戶API") public class UserController { @Autowired IUserService userService; @PostMapping("add") @ApiOperation(value="用戶新增") //正常業務時, 須要在user類裏面進行事務控制,控制層通常不進行業務控制的。 //@Transactional(rollbackFor = Exception.class) public Map<String,String> addUser(@Valid @RequestBody UserReq userReq){ User user = new User(); user.setCode(userReq.getCode()); user.setName(userReq.getName()); //因爲設置了主鍵策略 id可不用賦值 會自動生成 //user.setId(0L); userService.insert(user); Map<String,String> result = new HashMap<String,String>(); result.put("respCode", "01"); result.put("respMsg", "新增成功"); //事務測試 //System.out.println(1/0); return result; } @PostMapping("update") @ApiOperation(value="用戶修改") //更新時 直接刪除緩存 以保證下次獲取時先從數據庫中獲取最新數據 @CacheEvict(value="OKONG", key="#userReq.id") public Map<String,String> updateUser(@Valid @RequestBody UserReq userReq){ if(userReq.getId() == null || "".equals(userReq.getId())) { throw new CommonException("0000", "更新時ID不能爲空"); } User user = new User(); user.setCode(userReq.getCode()); user.setName(userReq.getName()); user.setId(Long.parseLong(userReq.getId())); userService.updateById(user); Map<String,String> result = new HashMap<String,String>(); result.put("respCode", "01"); result.put("respMsg", "更新成功"); return result; } @GetMapping("/get/{id}") @ApiOperation(value="用戶查詢(ID)") @ApiImplicitParam(name="id",value="查詢ID",required=true) @Cacheable(value="OKONG",key="#id") public Map<String,Object> getUser(@PathVariable("id") String id){ //查詢 User user = userService.selectById(id); if(user == null) { throw new CommonException("0001", "用戶ID:" + id + ",未找到"); } UserResp resp = UserResp.builder() .id(user.getId().toString()) .code(user.getCode()) .name(user.getName()) .status(user.getStatus()) .build(); Map<String,Object> result = new HashMap<String,Object>(); result.put("respCode", "01"); result.put("respMsg", "成功"); result.put("data", resp); return result; } @GetMapping("/page") @ApiOperation(value="用戶查詢(分頁)") public Map<String,Object> pageUser(int current, int size){ //分頁 Page<User> page = new Page<>(current, size); Map<String,Object> result = new HashMap<String,Object>(); result.put("respCode", "01"); result.put("respMsg", "成功"); result.put("data", userService.selectPage(page)); return result; } }
2.利用Swagger
控制頁面,新增一個用戶,而後獲取用戶,會發現緩存裏已經有此id的用戶數據了。
redis查看:
再次獲取,會發現此次沒有直接訪問數據庫了,而是直接從緩存讀取。你們可在觀察下控制檯的輸出狀況(可先清空控制檯,而後在請求)。
此時控制檯無任何輸出,但前端已經獲取到值了。
經常使用的就以上幾個,對於@CacheConfig
沒使用過,這裏就不說明了。
對於對幾個註解類的簡單使用就結束了,相關的詳細用法,好比自定義條件緩存,自定義註解等,這裏就不闡述了,請讀者自行
Spring Cache提供了一些供咱們使用的SpEL上下文數據,下表直接摘自互聯網:
名稱 | 位置 | 描述 | 示例 |
---|---|---|---|
methodName | root對象 | 當前被調用的方法名 | root.methodName |
method | root對象 | 當前被調用的方法 | root.method.name |
target | root對象 | 當前被調用的目標對象 | root.target |
targetClass | root對象 | 當前被調用的目標對象類 | root.targetClass |
args | root對象 | 當前被調用的方法的參數列表 | root.args[0] |
caches | root對象 | 當前方法調用使用的緩存列表(如@Cacheable(value={「cache1」, 「cache2」})),則有兩個cache | root.caches[0].name |
argument name | 執行上下文 | 當前被調用的方法的參數,如findById(Long id),咱們能夠經過#id拿到參數 | user.id |
result | 執行上下文 | 方法執行後的返回值(僅當方法執行以後的判斷有效,如‘unless’,’cache evict’的beforeInvocation=false) | result |
@CacheEvict(value = "user", key = "#user.id", condition = "#root.target.canCache() and #root.caches[0].get(#user.id).get().username ne #user.username", beforeInvocation = true) public void conditionUpdate(User user)
本章節主要是對
redis
結合Spring Cache
的集成和簡單使用進行了說明,詳細的用法,可自行搜索相關資料下,這裏就不闡述了。由於對於百分之八十之上的緩存要求基本能知足了。使用緩存時,必定要注意緩存生命週期的控制,否則容易出現數據不一致的狀況,謹記!
目前互聯網上不少大佬都有
SpringBoot
系列教程,若有雷同,請多多包涵了。本文是做者在電腦前一字一句敲的,每一步都是實踐的。若文中有所錯誤之處,還望提出,謝謝。
499452441
lqdevOps
本文原地址:https://blog.lqdev.cn/2018/07/23/springboot/chapter-eleven/
完整示例:chapter-11