1. 程式人生 > >緩存服務—Redis

緩存服務—Redis

to do uil obj ktr caching gap parameter 修改 del

Redis 簡介
Redis 是一個開源(BSD 許可)的、內存中的數據結構存儲系統,它可以用作數據庫、緩存和
消息中間件。

為什麽要用 Redis

在高並發場景下,如果需要經常連接結果變動頻繁的數據庫,會導致數據庫讀取及存取的速
度變慢,數據庫壓力極大。
因此我們需要通過緩存來減少數據庫的壓力,使得大量的訪問進來能夠命中緩存,只有少量
的需要到數據庫層。由於緩存基於內存,可支持的並發量遠遠大於基於硬盤的數據庫。所以
對於高並發設計,緩存的設計是必不可少的一環。
而 Redis 作為比較熱門的內存存儲系統之一,由於其對數據持久化的支持,種類豐富的數據
結構,使其定位更傾向於內存數據庫,適用於對讀寫效率要求都很高、數據處理業務復雜和
對安全性要求較高的系統。

技術分享圖片

Redis Cluster 架構
Redis 搭建方式有很多種,本章主要介紹 Redis Cluster 集群構建方式:

技術分享圖片

Redis 3.0 之後版本支持 Redis Cluster 集群,Redis Cluster 采用無中心結構,每個節點保存數據
和整個集群狀態,每個節點都和其他所有節點連接。
Redis Cluster 為了保證數據的高可用性,加入了主從模式,一個主節點對應一個或多個從節
點,主節點提供數據存取,從節點則是從主節點拉取數據備份,當這個主節點掛掉後,就會
有這個從節點選取一個來充當主節點,從而保證集群不會掛掉。主從結構,一是為了純粹的
冗余備份,二是為了提升讀性能,比如很消耗性能的 SORT 就可以由從服務器來承擔。
Redis 的主從同步是異步進行的,這意味著主從同步不會影響主邏輯,也不會降低 redis 的處
理性能。
主從架構中,可以考慮關閉主服務器的數據持久化功能,只讓從服務器進行持久化,這樣可
以提高主服務器的處理性能。在主從架構中,從服務器通常被設置為只讀模式,這樣可以避
免從服務器的數據被誤修改。

Redis小測試

1.新建springboot項目,結構如下:

技術分享圖片

2 . pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>demo</name>
<description>Demo project for Spring Boot</description>

<!-- Spring Boot 啟動父依賴 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/>
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</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-redis</artifactId>
<version>1.3.2.RELEASE</version>
</dependency>


</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>

</build>


</project>

3.application.yml 文件如下
技術分享圖片



4. 在本地 mysql 中添加數據

  insert into cat(id,cat_age,cat_name) values( , , );

5. 構建並運行本 demo,然後根據 yml 文件中配置的地址,訪問生成的數據:

技術分享圖片

結果驗證
查看日誌,查詢第一次訪問數據所耗時間,返回的結果為 3183ms:

技術分享圖片

再次刷新頁面訪問數據,第二次並沒有調用方法打印數據,並且查詢所用時間僅為 5ms,查詢速度提高

技術分享圖片

其他具體代碼如下 :

package com.example.demo.config;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.serializer.StringRedisSerializer;

import java.lang.reflect.Method;

@Configuration
@EnableCaching//開啟註解
public class RedisConfig {

@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory){

RedisTemplate<Object, Object> template=new RedisTemplate<Object, Object>();

template.setConnectionFactory(connectionFactory);
//實現序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
//實現序列化和反序列化redis的value值,默認使用JdkSerializationRedisSerializer
//template.setValueSerializer(new RedisObjectSerializer());
//template.setValueSerializer();
return template;

}


@Bean
public CacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
// cacheManager.setCacheNames(Arrays.asList("users", "emptyUsers"));
cacheManager.setUsePrefix(true);
// Number of seconds before expiration. Defaults to unlimited (0)
cacheManager.setDefaultExpiration(1800L);
return cacheManager;
}

@Bean
public KeyGenerator accountKeyGenerator() {
return new KeyGenerator(){
@Override
public Object generate(Object target, Method method, Object... params) {
//first parameter is caching object
//second paramter is the name of the method, we like the caching key has nothing to do with method name
//third parameter is the list of parameters in the method being called
return target.getClass().toString() + "accountId:" + params[0].toString();
}
};
}
}








package com.example.demo.controller;

import com.example.demo.model.Cat;
import com.example.demo.service.CatService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
public class CatController {

@Autowired
private CatService catService;

@RequestMapping(value = "/cat/{id}", method = RequestMethod.GET)
public Cat findOne(@PathVariable("id") Integer id) {
long beginTime=System.currentTimeMillis();
Cat cat=catService.findOneCat(id);
long time=System.currentTimeMillis()-beginTime;
System.out.println(time);
return cat;
}
@RequestMapping(value = "/cat", method = RequestMethod.POST)
public void createCat(@RequestBody Cat cat) {
catService.saveCat(cat);
}

// @RequestMapping(value = "/cat/{id}", method = RequestMethod.DELETE)
// public void modifyCity(@PathVariable("id") Integer id) {
// catService.deleteCat(id);
// }

}








package com.example.demo.model;

import org.hibernate.annotations.GenericGenerator;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.io.Serializable;

/**
* 創建了一個實體類。
*
* 如何持久化呢?
*
* 1、使用@Entity進行實體類的持久化操作,當JPA檢測到我們的實體類當中有
*
* @Entity 註解的時候,會在數據庫中生成對應的表結構信息。
*
*
* 如何指定主鍵以及主鍵的生成策略?
*
* 2、使用@Id指定主鍵.
*
*
*
*/
@Entity
public class Cat implements Serializable{

/**
* 使用@Id指定主鍵.
*
* 使用代碼@GeneratedValue(strategy=GenerationType.AUTO)
* 指定主鍵的生成策略,mysql默認的是自增長。
*
*/

@Id @GeneratedValue(strategy=GenerationType.AUTO)
private int id;//主鍵.

private String catName;//姓名. cat_name

private int catAge;//年齡. cat_age;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getCatName() {
return catName;
}

public void setCatName(String catName) {
this.catName = catName;
}

public int getCatAge() {
return catAge;
}

public void setCatAge(int catAge) {
this.catAge = catAge;
}


}







package com.example.demo.repository;


import com.example.demo.model.Cat;
import org.springframework.data.repository.CrudRepository;

/**
* Repository -- 是接口 ,不是class.
*/
public interface CatRepository extends CrudRepository<Cat, Integer> {

}




package com.example.demo.service.impl;


import com.example.demo.model.Cat;
import com.example.demo.repository.CatRepository;
import com.example.demo.service.CatService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class CatServiceImpl implements CatService {

@Autowired
private CatRepository catRepository;
//與@Cacheable不同的是使用@CachePut標註的方法在執行前不會去檢查緩存中是否存在之前執行過的結果,而是每次都會執行該方法,並將執行結果以鍵值對的形式存入指定的緩存中。
@CachePut(value="baseCatInfo")
public void saveCat(Cat cat) {
catRepository.save(cat);
}

@Override
public int updateCat(Cat cat) {
// TODO Auto-generated method stub
return 0;
}

//@CacheEvict是用來標註在需要清除緩存元素的方法或類上的。當標記在一個類上時表示其中所有的方法的執行都會觸發緩存的清除操作
@CacheEvict(value="cat")
public void deleteCat(int id) {
System.out.println(id);

}

@Override
public List<Cat> getCatAll() {
return (List<Cat>) catRepository.findAll();
}

@Cacheable(value="cat", keyGenerator = "accountKeyGenerator")
@Override
public Cat findOneCat(Integer id) {
System.out.println("開始查詢.....");
try {
Thread.sleep(3 * 1000l);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("查詢結束......");
Cat cat=catRepository.findOne(id);

return cat;
}

}




package com.example.demo.service;


import com.example.demo.model.Cat;

import java.util.List;

public interface CatService {


public void saveCat(Cat cat);

public int updateCat(Cat cat);

public void deleteCat(int id);

//查詢數據.
public List<Cat> getCatAll();

public Cat findOneCat(Integer id);
}





package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@EnableTransactionManagement
@SpringBootApplication
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

緩存服務—Redis