
缓存是一种介于数据永久存储介质与数据应用之间的数据临时存储介质
目的:使用缓存可以有效减少低俗数据读取过程的此数(例如磁盘IO),提高系统性能(如果当前缓存中没有本次要查询的数据,则进行查询,否则就从缓存中获取,就不用再访问数据库,同时也减少了数据库的压力)
缓存不仅可以用于提高永久性存储介质的数据读取效率,还可以提供临时的数据存储空间
2.Spring缓存使用方式(默认Simple方式演示)springboot提供了缓存技术
需要的maven坐标基本配置org.springframework.boot spring-boot-starter-cache
#第二种方法:Druid专用配置 推荐
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/user_db?serverTimezone=GMT
username: root
password: admin
#开启MP运行日志
mybatis-plus:
configuration:
# 标准输出 打印到控制台上 以后我们就不用sout输出了, 这个东西会帮我们输出
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
开启缓存功能
@SpringBootApplication
@EnableCaching // 这个注解的作用是开启缓存功能
public class Springboot19CacheApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot19CacheApplication.class, args);
}
}
代码演示
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookService bookService;
@GetMapping("{id}")
public Book get(@PathVariable Integer id){
return bookService.getById(id);
}
@PostMapping
public boolean save (@RequestBody Book book){
return bookService.save(book);
}
@PutMapping
public boolean updata(@RequestBody Book book){
return bookService.update(book);
}
@DeleteMapping("{id}")
public boolean delete(@RequestBody Integer id){
return bookService.delete(id);
}
@GetMapping
public List getAll(){
return bookService.getAll();
}
}
@Mapper //通过这个实现数据库的操作 里面有数据库中各种各样的操作 public interface BookDao extends BaseMapper{//指定泛型才能知道操作谁 }
@Data //get+set+toString+hashcode+equals 但是没有构造方法
@TableName(value = "t_book")
public class Book {
// 这里的属性名 要和数据库表中的属性名一致,要不然最终的查询结果是null
// 将数据库中的结果对此变量名进行注入
@TableId(value="id",type = IdType.AUTO) //代表自增算法
@TableField(value = "id")
private int id;
@TableField(value = "bookName")
private String bookName;
@TableField(value = "statue")
private String statue;
@TableField(value="type")
private String type;
public Book() {
}
public Book(int id, String bookName, String statue, String type) {
this.id = id;
this.bookName = bookName;
this.statue = statue;
this.type = type;
}
}
public interface BookService extends IService{ public Book getById(Integer id); public boolean save(Book book); public boolean update(Book book); public boolean delete(Integer id); public List getAll(); }
对getById方法设置缓存机制
就下面这个图而言,如果这个cacheSpace空间中有key的这个操作,那就从CacheSpace中找出来,如果没有的话,再执行方法体中的内容,从而达到了缓存的操作
@Service public class BookServiceImpl extends ServiceImplimplements BookService { @Autowired private BookDao bookDao; @Override @Cacheable(value = "catchSpace",key = "#id") //是否是课缓存的,其中要指定两个参数,value 就是放的位置,随便定义;下次找用id找,所以key=id // 运行之后,我们就会把查询之后的数据放到上面这个“id”里面,作为key public Book getById(Integer id){ return bookDao.selectById(id); } @Override public boolean save(Book book) { return bookDao.insert(book) >0; } @Override public boolean update(Book book) { return bookDao.updateById(book) >0; } @Override public boolean delete(Integer id) { return bookDao.deleteById(id) >0; } @Override public List getAll() { return bookDao.selectList(null); } }
运行下面这个程序
@SpringBootApplication
@EnableCaching // 这个注解的作用是开启缓存功能
public class Springboot19CacheApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot19CacheApplication.class, args);
}
}
接下来在postman中执行下面的语句两次
但是我们发现在idea中只有一条运行结果,所以我们缓存成功
3.手机验证码利用缓存的方式验证controller.SMSCodeController
@RestController
@RequestMapping("/sms")
public class SMSCodeController {
@Autowired
private SMSCodeService service;
// 通过接受到的电话,得到code码
@GetMapping
public String getCode(String tele){
String code = service.sendCodeToSMS(tele);
return code;
}
// 检验一下code码是否正确
// 把电话号码和验证码都给我们,然后验证是否正确
@PostMapping
public boolean checkCode( SMSCode smsCode){//SMSCode类型属性中包含tele和code
return service.checkCode(smsCode);
}
}
domain.SMSCode
@Data
public class SMSCode {
private String tele; //手机号码
private String code; //手机验证码
}
service.serviceImpl.SMSCodeServiceImpl
@Service
public class SMSCodeServiceImpl implements SMSCodeService {
@Autowired
private CodeUtils codeUtils;
@Override
// 开启缓存功能
// @Cacheable(value = "cacheSpace" , key = "#tele") 这个语句在这里其实并不适用,因为我们一般的验证码都是一分钟以内,如果再次获取验证码,就不是这个了
// value = "smsCode" 缓存空间
@CachePut(value="smsCode",key="#tele") //这个注解可以做到往缓存中放入return的code值,把指定的返回值放到指定的key的位置
public String sendCodeToSMS(String tele) {
String code= codeUtils.generator(tele);
return code;
}
@Override
public boolean checkCode(SMSCode smsCode) {
// 取出内存中的验证码与传递过来的验证码进行对比,如果相同,返回true
String code = smsCode.getCode();
String cacheCode =codeUtils.get(smsCode.getTele()); //这是缓存中的验证码,因为tele是key,所以在此处要传入一个tele
return code.equals(cacheCode);
}
}
service.SMSCodeService
public interface SMSCodeService {
public String sendCodeToSMS(String tele);
public boolean checkCode(SMSCode smsCode);
}
utils.CodeUtils
@Component
public class CodeUtils {
private String[] patch = {"00000","0000","000","00","0",""}; //利用数据结构的优化,进行补零
public String generator(String tele){
int hash = tele.hashCode(); //这个得到的tele的哈希值和我们即将要生成的验证码有很必要的关系
int encryption = 20206666;
// 第一次加密
long result = hash ^ encryption;
// 第二次加密
long nowTime = System.currentTimeMillis();
result = result^nowTime;
// 取某result的某些位数作为 验证码
long code = result%1000000; //六个余数
code = code<0 ? -code :code; //将验证码的复数排除
// 如果我们生成的code前面几位是零的话,就会省略了前面的零,但是省略的之后,就不足六位了,我们现在要对不足六位的数据进行补零
String codeStr = code+"";
int len = codeStr.length();
return patch[len-1]+codeStr;
}
@Cacheable(value = "smsCode" , key = "#tele") //key在这里就是电话号码,类似将电话号码作为key
public String get(String tele){
// 如果缓存中有对应数据,那我们就利用key获取到了
// 如果缓存中没有对应的数据,那我们就返回null,也非常的合理
return null;
}
}
postman获取验证码:
postman对验证码进行验证
4.Ehcache缓存工具
maven坐标
net.sf.ehcache ehcache
配置文件的配置
#第二种方法:Druid专用配置 推荐
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/user_db?serverTimezone=GMT
username: root
password: admin
cache:
type: ehcache
#开启MP运行日志
mybatis-plus:
configuration:
# 标准输出 打印到控制台上 以后我们就不用sout输出了, 这个东西会帮我们输出
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
下面的这个配置要和上面的左边进行配对,如果有这个配置,但是没有坐标,一样会出现错误
以及还有下面的ehcache.xml配置文件
上面的这组配置,是配置的默认的缓存的地方,但是从我们的代码来看,我们显然不是存放在默认的地方,而是“smsCode”缓存空间中,则我们还需要添加一组配置(不同的数据,缓存不一样,所以可以设置多个缓存策略)
其中,下面的 “name”就是我们指定缓存空间