æç« ç®å½
- ââä¸ãä»ä¹æ¯ ç¼åï¼ââ
- âââ 为ä»ä¹ç¨ç¼åï¼ââ
- âââ¡å¦ä½ä½¿ç¨ç¼åââ
- ââäºãå®ç°ä¸ä¸ªå家ç¼åââ
- âââç¯å¢æ建ââ
- âââ¨ï¸æ ¸å¿æºç ââ
- âââ æµè¯æ¥å£ââ
- ââä¸ãéç¨ å¾®æå¡ Spring Boot 注解å¼å¯ç¼åââ
- âââï¸@CacheEnable 注解详解ââ
- âââ¿è°ç¨æ¥å£æµè¯ââ
- âââµå°ç»ââ
ä¸ãä»ä¹æ¯ ç¼åï¼
ç¼å(Cache),å°±æ¯æ°æ®äº¤æ¢çç¼å²åº,ä¿ç§°çç¼åå°±æ¯ç¼å²åºå çæ°æ®,ä¸è¬ä»æ°æ®åºä¸è·å,åå¨äºæ¬å°ä»£ç ï¼ä¾å¦ï¼
ä¾1:Static final ConcurrentHashMap<K,V> map = new ConcurrentHashMap<>(); æ¬å°ç¨äºé«å¹¶å
ä¾2:static final Cache<K,V> USER_CACHE = CacheBuilder.newBuilder().build(); ç¨äºredisçç¼å
ä¾3:Static final Map<K,V> map = new HashMap();
ç±äºå ¶è¢«Static修饰,æ以éçç±»çå è½½è被å è½½å°å åä¹ä¸,ä½ä¸ºæ¬å°ç¼å,ç±äºå ¶å被final修饰,æä»¥å ¶å¼ç¨(ä¾3:map)å对象(ä¾3:new HashMap())ä¹é´çå ³ç³»æ¯åºå®ç,ä¸è½æ¹å,å æ¤ä¸ç¨æ å¿èµå¼(=)导è´ç¼å失æ;
â 为ä»ä¹ç¨ç¼åï¼
ä¸å¥è¯æ»ç»ï¼ å 为使ç¨äºç¼ååï¼æçä¼å¤§å¤§çæåï¼åå°äºä¸å¿ è¦çèµæºæ¶èï¼æåäºç¨æ·ä½éªã
ä½æ¯ä½¿ç¨ç¼åä¼å¢å 代ç å¤æ度åè¿ç»´çææ¬ï¼ä¾å¦ï¼Redis é群ï¼å¤ä¸»å¤ä»ï¼çç
â¡å¦ä½ä½¿ç¨ç¼å
å¨å®é å¼åä¸ï¼æ们ä¼æ建ç¼åæ¥æåç³»ç»ç稳å®ãé«å¯ç¨æ§ï¼ä½¿å ¶æ§è½å¾å°è¿ä¸æ¥çæåãæ常ç¨çæ¯ æ们 â
âæ¬å°æ°æ®ä¸Redis æ°æ®åºç»å使ç¨â
â
æµè§å¨ç¼åï¼ä¸»è¦æ¯åå¨äºæµè§å¨ç«¯çç¼å
åºç¨å±ç¼åï¼ å¯ä»¥å为tomcatæ¬å°ç¼åï¼æ¯å¦mapéåï¼æè æ¯ä½¿ç¨redisä½ä¸ºç¼å
æ°æ®åºç¼åï¼ å¨æ°æ®åºä¸æä¸ç空é´æ¯ buffer pool ï¼ç¼å²æ± ï¼ï¼å¢æ¹æ¥æ°æ®é½ä¼å å è½½å°mysqlçç¼åä¸
CPUç¼åï¼ å½ä»£è®¡ç®æºæ大çé®é¢æ¯ cpuæ§è½æåäºï¼ä½å å读åé度没æè·ä¸ï¼æ以为äºéåºå½ä¸çæ åµï¼å¢å äºcpuçL1ï¼L2ï¼L3级çç¼å
äºãå®ç°ä¸ä¸ªå家ç¼å
éæ±è¯´æ
æ¬ é¡¹ç®åºäº Spring Boot æ´åRedis 并å¼å ¥ MyBatis-Plus æ¥å®æå¼å
- è¦æ±è¾¾å°ç¬¬ä¸æ¬¡å è½½ï¼æ¥è¯¢redisç¼åæ¯å¦åå¨ï¼è¥ä¸åå¨ï¼åæ¥è¯¢æ°æ®åºï¼æ¥è¯¢å®æ¯åï¼åå ¥redisï¼å次访é®æ¶åªè·åredisç¼åä¸çæ°æ®ï¼ä¸å¿ å次å è½½æ°æ®åºï¼åè½»æ°æ®åºååã
âç¯å¢æ建
æ¬é¡¹ç®ä¾èµäº 3åéææé¿éäºæå¡å¨é¨ç½²Reids并æ´åSpring Boot
æ°æ®åº MySQL 8.0
CREATE TABLE `tb_shop` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主é®',
`name` varchar(128) NOT NULL COMMENT 'åéºå称',
`type_id` bigint(20) unsigned NOT NULL COMMENT 'åéºç±»åçid',
`images` varchar(1024) NOT NULL COMMENT 'åéºå¾çï¼å¤ä¸ªå¾ç以'',''éå¼',
`area` varchar(128) DEFAULT NULL COMMENT 'ååï¼ä¾å¦é家å´',
`address` varchar(255) NOT NULL COMMENT 'å°å',
`x` double unsigned NOT NULL COMMENT 'ç»åº¦',
`y` double unsigned NOT NULL COMMENT '维度',
`avg_price` bigint(10) unsigned DEFAULT NULL COMMENT 'åä»·ï¼åæ´æ°',
`sold` int(10) unsigned zerofill NOT NULL COMMENT 'éé',
`comments` int(10) unsigned zerofill NOT NULL COMMENT 'è¯è®ºæ°é',
`score` int(2) unsigned zerofill NOT NULL COMMENT 'è¯åï¼1~5åï¼ä¹10ä¿åï¼é¿å
å°æ°',
`open_hours` varchar(32) DEFAULT NULL COMMENT 'è¥ä¸æ¶é´ï¼ä¾å¦ 10:00-22:00',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'å建æ¶é´',
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ´æ°æ¶é´',
PRIMARY KEY (`id`) USING BTREE,
KEY `foreign_key_type` (`type_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT
pomä¾èµ
// Mybatis-Plus æ ¸å¿ä¾èµ
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
// hutool å·¥å
·å
ï¼åç§å°è£
åè½ ä¸åºä¿±å
¨
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.5</version>
</dependency>
æ ¸å¿é ç½® application.yaml
server:
port: 8082
spring:
application:
name: easydp
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/db_easy_dp?useSSL=false&serverTimezone=UTC
username: root
password: 111111
redis:
host: redis ipå°å
port: 6379
password: rediså¯ç ï¼å¦æ²¡æä¸åå³å¯
lettuce:
pool:
max-active: 10
max-idle: 10
min-idle: 1
time-between-eviction-runs: 10s
jackson:
default-property-inclusion: non_null # JSONå¤çæ¶å¿½ç¥é空å段
mybatis-plus:
type-aliases-package: com.chen.entity # å«åæ«æå
logging:
level:
com.chen:
â¨ï¸æ ¸å¿æºç
Entity å®ä½ç±»å±
package com.chen.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* @author whc
* @date 2022/9/3 10:29
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("tb_shop")
public class ShopEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主é®
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* åéºå称
*/
private String name;
/**
* åéºç±»åçid
*/
private Long typeId;
/**
* åéºå¾çï¼å¤ä¸ªå¾ç以','éå¼
*/
private String images;
/**
* ååï¼ä¾å¦é家å´
*/
private String area;
/**
* å°å
*/
private String address;
/**
* ç»åº¦
*/
private Double x;
/**
* 维度
*/
private Double y;
/**
* åä»·ï¼åæ´æ°
*/
private Long avgPrice;
/**
* éé
*/
private Integer sold;
/**
* è¯è®ºæ°é
*/
private Integer comments;
/**
* è¯åï¼1~5åï¼ä¹10ä¿åï¼é¿å
å°æ°
*/
private Integer score;
/**
* è¥ä¸æ¶é´ï¼ä¾å¦ 10:00-22:00
*/
private String openHours;
/**
* å建æ¶é´
*/
private LocalDateTime createTime;
/**
* æ´æ°æ¶é´
*/
private LocalDateTime updateTime;
@TableField(exist = false)
private Double distance;
}
Mapperæä¹ åå±
package com.chen.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.chen.entity.ShopEntity;
/**
* @author whc
* @date 2022/9/3 10:33
*/
public interface ShopMapper extends BaseMapper<ShopEntity> {
}
Service æ¥å£
package com.chen.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.chen.common.ResultBean;
import com.chen.dto.ShopDTO;
import com.chen.entity.ShopEntity;
/**
* @author whc
* @date 2022/9/3 10:35
*/
public interface ShopService extends IService<ShopEntity> {
ResultBean<ShopDTO> queryById(Long id);
}
ServiceImpl å®ç°å±
package com.chen.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chen.common.ResultBean;
import com.chen.dto.ShopDTO;
import com.chen.entity.ShopEntity;
import com.chen.mapper.ShopMapper;
import com.chen.service.ShopService;
import com.chen.utils.RedisConstants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
/**
* @author whc
* @date 2022/9/3 10:36
*/
@Slf4j
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, ShopEntity> implements ShopService{
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public ResultBean<ShopDTO> queryById(Long id) {
try {
// æ¼æ¥ redis key
String key = RedisConstants.CACHE_SHOP_KEY + id;
//ä»redisä¸è·åæ¯å¦å·²åå¨ï¼è¥åå¨ï¼åç´æ¥è¿å
String json = stringRedisTemplate.opsForValue().get(key);
//å¤æå¦æåå¨ï¼å°±è¿å
if (StrUtil.isNotBlank(json)) {
ShopDTO shopDTO = JSONUtil.toBean(json, ShopDTO.class);
return ResultBean.create(0, "success", shopDTO);
}
//ä»æ°æ®åºæ¥è¯¢æ°æ® getById(id) æ¯ MyBatis-Plus æä¾çæ¥è¯¢æ¹æ³ï¼ç´æ¥è°ç¨å³å¯å®ææ¥è¯¢
ShopEntity shopEntity = getById(id);
//转æ¢å¯¹è±¡
ShopDTO shopDTO = BeanUtil.toBean(shopEntity, ShopDTO.class);
//å°æ°æ®åå
¥redis
stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shopDTO));
return ResultBean.create(0, "success", shopDTO);
} catch (Exception e) {
log.error("è·ååå详æ
å¤±è´¥ï¼ e ==> {}", e);
return ResultBean.create(-1, "è·ååå详æ
å¤±è´¥ï¼ e ==> {}" + e);
}
}
}
Controllerå±
package com.chen.controller;
import com.chen.common.ResultBean;
import com.chen.dto.ShopDTO;
import com.chen.service.ShopService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @author whc
* @date 2022/9/3 11:06
*/
@RestController
@CrossOrigin
@RequestMapping("/shop")
public class ShopController {
@Autowired
private ShopService shopService;
@GetMapping("/{id}")
public ResultBean<ShopDTO> queryShopById(@PathVariable("id") Long id) {
return shopService.queryById(id);
}
}
å·¥å ·ç±»
package com.chen.utils;
/**
* redis key 常é
* @author whc
* @date 2022/9/3 13:40
*/
public class RedisConstants {
public static final String CACHE_SHOP_KEY = "cache:shop:";
public static final Long CACHE_SHOP_TTL = 30L;
}
â æµè¯æ¥å£
è¿éæ使ç¨äºRediså¯è§åå·¥å ·ï¼RESPï¼å°åï¼ââhttps://resp.app/zh/ââ
æå¼åå¯ä»¥ç´æ¥è¿æ¥ä½ çredisæ°æ®åºï¼å¯è§åå±ç¤º
å©ç¨ ApiFoxæµè¯æ¥å£ï¼å¯åè ãäºåçãåå端å离项ç®ä¸ å¦ä½ä¼é çèè°ç¨åºï¼â
第ä¸æ¬¡è°ç¨èæ¶ 1.61s ï¼æ¯å 为æ们第ä¸æ¬¡redisä¸æ æ°æ®ï¼èµ°äºæ¥è¯¢æ°æ®åºçæä½ï¼ç¶ååå ¥redisï¼æ»èæ¶1.61s
第äºæ¬¡è°ç¨
第äºæ¬¡è°ç¨ç´æ¥èµ°çç¼åï¼å¯è§æçæåäºå¾å¤ï¼
ä¸ãéç¨ å¾®æå¡ Spring Boot 注解å¼å¯ç¼å
å¼å¯æ³¨è§£å¯å¨ç¼å
Spring é»è®¤æ¯æç¼åï¼ä½çæ¬å¿ é¡»å¨3.1以ä¸ï¼å¨å¯å¨ç±»å å ¥ â
â@EnableCachingâ
â å¼å¯å³å¯
package com.chen;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
/**
* @author whc
* @date 2022/9/3 10:27
*/
//å¼å¯ç¼åæ¯æ
@EnableCaching
@MapperScan("com.chen.mapper")
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
âï¸@CacheEnable 注解详解
@CacheEnableï¼ ç¼ååå¨ï¼å使ç¨ç¼åï¼ä¸åå¨ï¼åæ§è¡æ¹æ³ï¼å¹¶å°ç»æå¡å ¥ç¼å
ShopServiceImpl å®ç°ç±»
@Cacheable(cacheNames = "shop", key = "#root.methodName")
public ShopDTO queryById(Long id) {
try {
String key = RedisConstants.CACHE_SHOP_KEY + id;
String json = stringRedisTemplate.opsForValue().get(key);
if (StrUtil.isNotBlank(json)) {
ShopDTO shopDTO = JSONUtil.toBean(json, ShopDTO.class);
return shopDTO;
}
ShopEntity shopEntity = getById(id);
//转æ¢å¯¹è±¡
ShopDTO shopDTO = BeanUtil.toBean(shopEntity, ShopDTO.class);
stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(shopDTO), RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);
return shopDTO;
} catch (Exception e) {
log.error("è·ååå详æ
å¤±è´¥ï¼ e ==> {}", e);
return null;
}
}
â¿è°ç¨æ¥å£æµè¯
第ä¸æ¬¡è°ç¨ï¼èæ¶å¾é¿
å次è°ç¨ï¼èµ°ç¼å
æ¥çRediså¯è§åkey
å¤§å° 1.11k åè
åçjsonåå ¥
å¤§å° 653 åè
综ä¸èèï¼åºäºå åçåå ï¼æ们éæ©ä½¿ç¨jsonåå ¥redisï¼æ´çå åï¼