1. 程式人生 > 實用技巧 >spring-boot -快取註解

spring-boot -快取註解

快取:商品資訊放到快取中介軟體中,

    驗證碼幾秒鐘有效也是放在快取中介軟體。

快取規範

互動流程:

如果需要使用jRS107需要匯入包:

java.cache.cache-api

JSR107提供的是介面,如果需要用那些快取的元件,就需要加入對應的實現,

如果沒有對應的實現的話,是需要自己寫的。

spring裡面提供了快取抽象,

CacheAutoConfiguration 加入的自動配置類

預設加入SimpleCacheConfiguration

@Configuration(
    proxyBeanMethods = false
) @ConditionalOnMissingBean({CacheManager.class}) @Conditional({CacheCondition.class}) class SimpleCacheConfiguration { SimpleCacheConfiguration() { } @Bean ConcurrentMapCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers cacheManagerCustomizers) { ConcurrentMapCacheManager cacheManager
= new ConcurrentMapCacheManager(); List<String> cacheNames = cacheProperties.getCacheNames(); if (!cacheNames.isEmpty()) { cacheManager.setCacheNames(cacheNames); } return (ConcurrentMapCacheManager)cacheManagerCustomizers.customize(cacheManager); } }

使用快取註解的前提是:

配置檔案:

spring.datasource.url=jdbc:mysql://192.168.1.102:3306/mybatis
spring.datasource.username=root
spring.datasource.password=1997
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver


#開啟駝峰命名
mybatis.configuration.map-underscore-to-camel-case=true

logging.level.root=debug

開啟debug模式可以檢視更加細節的日誌

加入依賴:

    <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

建立資料庫表:

CREATE TABLE `employee` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `lastName` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `gender` int(2) DEFAULT NULL,
  `d_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

實體類:

public class Employee {

    private Integer id;
    private String lastName;
    private Integer gender;
    private String email;
    private Integer dId;

    public Employee() {
        super();
    }

    public Employee(Integer id, String lastName, Integer gender, String email, Integer dId) {
        super();
        this.id = id;
        this.lastName = lastName;
        this.gender = gender;
        this.email = email;
        this.dId = dId;
    }

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

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public void setdId(Integer dId) {
        this.dId = dId;
    }

    public Integer getId() {
        return id;
    }

    public String getLastName() {
        return lastName;
    }

    public Integer getGender() {
        return gender;
    }

    public String getEmail() {
        return email;
    }

    public Integer getdId() {
        return dId;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", lastName='" + lastName + '\'' +
                ", gender=" + gender +
                ", email='" + email + '\'' +
                ", dId=" + dId +
                '}';
    }
}

mapper介面

@Mapper
public interface EmployeeMapper {
    @Select("select * from employee where id = #{id}")
    public Employee getEmpById(Integer id);

    @Update("update employee set lastName =#{lastName},email=#{email},gender=#{gender},d_id=#{dId}")
    public void updateEmp(Employee employee);

    @Delete("delete from employee where id =#{id}")
    public void deleteEmpById(Integer id);

    @Insert("insert into employee(lastName,email,gender,d_id) values(#{lastName},#{email},#{gender},#{dId})")
    public void insertEmp(Employee employee);

    @Select("select * from employee where lastName = #{lastname}")
    Employee getEmpByLastName(String lastname);
}

controller層:

@RestController
public class EmplloyeeController {

    @Autowired
    EmployeeService employeeService;

    @RequestMapping("/emp/{id}")
    public Employee getEmployee(@PathVariable("id") Integer id){
       return employeeService.getEmp(id);
    }

    @RequestMapping("/emp")
    public Employee update(Employee employee){
        Employee employee1 =employeeService.updateEmp(employee);
        return employee1;
    }

    @RequestMapping("/delemp")
    public String deleteEMp(Integer id){
        employeeService.deleteEmp(id);
        return "success";
    }

}

在服務層我們使用快取註解:

先開啟快取註解@EnableCaching,,在啟動類中

@Cacheable

 @Cacheable(cacheNames = "emp",keyGenerator = "myKeyGenerator")
    public Employee getEmp(Integer id){
        System.out.println("chanxun"+id+"員工");
        Employee emp = employeeMapper.getEmpById(id);
        return emp;
    }
  @Cacheable標註的方法執行之前先來檢查快取中有沒有這個資料,預設按照引數的值作為key去查詢快取
     如果有就不需要執行函式
     如果沒有就執行函式
     */

@Cacheable執行流程:

  執行的流程:
        1方法執行之前,先去查詢Cache元件,安裝cacheNames指定的名字獲取
            (CacheManager先獲取相應的快取)第一次獲取快取,回自動創建出來,以後就能用了
        2去Cache中查詢快取的內容弄給,使用一個key,預設是方法的引數
            key是按照某個規則生成的,預設是keyGenerator生成,預設使用simplekeyGenerator
                simplekeyGenerator策略:
                    如果沒有引數,key= new SimpleKey
                    如果一個:使用它
                    如果多個,SimpleKey(params)
        3 沒有查到快取就呼叫目標方法
        4將目標方法返回的結果,放進快取中

@Cacheable的屬性和作用:

    /**
     * 將方法的允許結果進行快取,以後如果要相同的資料,直接從快取中獲取,不用呼叫方法
     *CacheManager 管理多個Cache元件,對快取的真正CRUD操作是在Cache元件中,
     * 每一個快取元件有自己的唯一名字
     * 幾個屬性:
     *  cacheNames/value:指定快取元件的名字,將方法的返回結果放在哪個快取中,陣列,可自定多個快取
     *  key:快取資料使用的key,可以用它來指定,預設是使用方法引數的值 1
     *          可以使用SpEl格式
     *  keyGenerator:key的生成器,可以自己指定key的生成器元件id
     *      key和keyGenerator二選一,!!可以自己指定
     *  CacheManager:指定快取管理器
     *  condition,指定符合條件的情況菜快取  condiction ="#id>0"id的值大於0才快取
     *  unless :否定快取,當unless指定的條件為true,返回值不會被快取,可以獲取到結果進行判斷
     *          unless = ”#result == null“如果結果為null 不快取
     *  sync:是否使用非同步模式

@CachePut:

/**
 * @CachePut 既呼叫方法,又跟新快取資料
 * 場景:修改資料庫的某個資料,同時跟新快取
 * 執行實際:1先呼叫目標方法
 *          2將目標方法的結果快取起來
    測試:
        1查詢1好員工,,查到的結果回放到快取當中
            儲存方式:key:1  value:員工資訊
        2以後查詢還是之前的結果
        3更新1號員工http://localhost:8080/emp?id=1&lastName=quanzhiqiang&gender=2
              儲存方式:key:傳入的物件emloyee,value: 返回的employee物件
        4查詢1號員工??
            理論上查詢的應該是更新後的員工資訊
            但是結果是之前的資訊,原因可以看看上面的快取儲存的兩種方式就知道了

            解決方法, @CachePut(value = "emp" ,key = "#employee.id"),指定修改的key

 */

改進後:

    @CachePut(value = "emp" ,key = "#result.id")
    public Employee updateEmp(Employee employee){
        System.out.println("updateEmp"+employee);
        employeeMapper.updateEmp(employee);
        return employee;
    }

}
//注意:你取快取的key和我們更新快取的key應該一致

@CacheEvict

    /**
     * @CacheEvict 快取請除
     * key:通過key來指定清楚的資料
     * allEntries = true:指定清除這個快取中的所有的資料
     * beforeInvocation = false:快取的清楚是否在方法之前執行
     *      預設代表方法執行之後執行,出現異常快取不會清除。
     */

    @CacheEvict(value = "emp",key = "#id")
    public void deleteEmp(Integer id){
        System.out.println("deleteEmp:"+id);
        employeeMapper.deleteEmpById(id);
    }

@Caching:

  可以同時定義多個快取註解:

  

    @Caching(
            cacheable = {
                    @Cacheable(value = "emp",key = "#lastname")
            },
            put = {
                    @CachePut(value = "emp",key = "#result.id"),
                    @CachePut(value = "emp",key = "#result.lastName")
            }
            )
    public Employee getEmpByLastName(String lastname){
        return employeeMapper.getEmpByLastName(lastname);
    }

}

@CacheConfig

/*
因為每個快取註解都要寫value =”emp"
所以我們可以通過@CacheConfig註解統一設定
 */
@CacheConfig(cacheNames = "emp")


加在類上就可以了,裡面的方法的快取註解都不需要指定快取元件名i在