1. Redis入門案例
1.1 Redis常見用法
1.1.1 setex學習
/**
* 2.需求:
* 1.向redis中插入資料 k-v
* 2.為key設定超時時間 60秒后失效.
* 3.執行緒sleep 3秒
* 4.獲取key的剩余的存活時間.
*
* 問題描述: 資料一定會被洗掉嗎??????
* 問題說明: 如果使用redis 并且需要添加超時時間時 一般需要滿足原子性要求.
* 原子性: 操作時要么成功 要么失敗.但是必須同時完成.
*/
@Test
public void test02() throws InterruptedException {
Jedis jedis = new Jedis("192.168.126.129",6379);
jedis.setex("寶可夢", 60, "小火龍 妙蛙種子");
System.out.println(jedis.get("寶可夢"));
/* Jedis jedis = new Jedis("192.168.126.129",6379);
jedis.set("寶可夢", "小火龍 妙蛙種子");
int a = 1/0; //可能會出例外
jedis.expire("寶可夢", 60);
Thread.sleep(3000);
System.out.println(jedis.ttl("寶可夢"));*/
}
1.1.2 setnx
/**
* 3.需求如果發現key已經存在時 不修改資料.如果key不存在時才會修改資料.
*
*/
@Test
public void test03() throws InterruptedException {
Jedis jedis = new Jedis("192.168.126.129", 6379);
jedis.setnx("aaaa", "測驗nx的方法");
/*if(jedis.exists("aaa")){
System.out.println("key已經存在 不做修改");
}else {
jedis.set("aaa", "測驗資料");
}*/
System.out.println(jedis.get("aaaa"));
}
1.1.3 set 超時時間原子性操作
/**
* 需求:
* 1.要求用戶賦值時,如果資料存在則不賦值. setnx
* 2.要求在賦值操作時,必須設定超時的時間 并且要求滿足原子性 setex
*/
@Test
public void test04() throws InterruptedException {
Jedis jedis = new Jedis("192.168.126.129", 6379);
SetParams setParams = new SetParams();
setParams.nx().ex(20);
jedis.set("bbbb", "實作業務操作AAAA", setParams);
System.out.println(jedis.get("bbbb"));
}
1.1.4 list集合練習
@Test
public void testList() throws InterruptedException {
Jedis jedis = new Jedis("192.168.126.129", 6379);
jedis.lpush("list", "1","2","3");
System.out.println(jedis.rpop("list"));
}
1.1.5 redis事務控制
@Test
public void testTx() throws InterruptedException {
Jedis jedis = new Jedis("192.168.126.129", 6379);
//1.開啟事務
Transaction transaction = jedis.multi();
try {
transaction.set("aa", "aa");
//提交事務
transaction.exec();
}catch (Exception e){
e.printStackTrace();
//回滾事務
transaction.discard();
}
}
2.秒殺業務邏輯—分布式鎖機制
6988 —1塊 1部手機 20顯示搶購成功 并且支付了1塊錢…
問題:
1.tomcat服務器有多臺
2.資料庫資料只有1份
3.必然會出現高并發的現象.
如何實作搶購…
2.1常規鎖操作
2.1.1 超賣的原因

2.1.2 同步鎖的問題
說明:同步鎖只能解決tomcat內部的問題,不能解決多個tomcat并發問題

2.1.3 分布式鎖機制
思想:
1.鎖應該使用第三方操作 ,鎖應該公用.
2.原則:如果鎖被人正在使用時,其他的用戶不能操作.
3.策略: 用戶向redis中保存一個key,如果redis中有key表示有人正在使用這把鎖 其他用戶不允許操作.如果redis中沒有key ,則表示我可以使用這把鎖.
4.風險: 如何解決死鎖問題. 設定超時時間.

3. SpringBoot整合Redis
3.1 編輯組態檔 redis.pro
說明:由于該配置被其他的專案共同使用,則應該寫到jt-common中.

3.2 編輯配置類
說明: 編輯redis配置類.將Jedis物件交給Spring容器進行管理.
@Configuration
@PropertySource("classpath:/properties/redis.properties")
public class JedisConfig {
@Value("${redis.host}")
private String host;
@Value("${redis.port}")
private Integer port;
@Bean
public Jedis jedis(){
return new Jedis(host,port);
}
}
3.3 物件與JSON轉化 ObjectMapper介紹
3.3.1 簡單物件轉化
/**
* 測驗簡單物件的轉化
*/
@Test
public void test01() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
ItemDesc itemDesc = new ItemDesc();
itemDesc.setItemId(100L).setItemDesc("商品詳情資訊")
.setCreated(new Date()).setUpdated(new Date());
//物件轉化為json
String json = objectMapper.writeValueAsString(itemDesc);
System.out.println(json);
//json轉化為物件
ItemDesc itemDesc2 = objectMapper.readValue(json, ItemDesc.class);
System.out.println(itemDesc2.getItemDesc());
}
3.3.2 集合物件轉化
/**
* 測驗集合物件的轉化
*/
@Test
public void test02() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
ItemDesc itemDesc = new ItemDesc();
itemDesc.setItemId(100L).setItemDesc("商品詳情資訊1")
.setCreated(new Date()).setUpdated(new Date());
ItemDesc itemDesc2 = new ItemDesc();
itemDesc2.setItemId(100L).setItemDesc("商品詳情資訊2")
.setCreated(new Date()).setUpdated(new Date());
List<ItemDesc> lists = new ArrayList<>();
lists.add(itemDesc);
lists.add(itemDesc2);
//[{key:value},{}]
String json = objectMapper.writeValueAsString(lists);
System.out.println(json);
//將json串轉化為物件
List<ItemDesc> list2 = objectMapper.readValue(json, lists.getClass());
System.out.println(list2);
}
3.4 編輯工具API
package com.jt.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jt.pojo.ItemDesc;
import org.springframework.util.StringUtils;
public class ObjectMapperUtil {
/**
* 1.將用戶傳遞的資料轉化為json串
* 2.將用戶傳遞的json串轉化為物件
*/
private static final ObjectMapper MAPPER = new ObjectMapper();
//1.將用戶傳遞的資料轉化為json串
public static String toJSON(Object object){
if(object == null) {
throw new RuntimeException("傳遞的資料為null.請檢查");
}
try {
String json = MAPPER.writeValueAsString(object);
return json;
} catch (JsonProcessingException e) {
//將檢查例外,轉化為運行時例外
e.printStackTrace();
throw new RuntimeException(e);
}
}
//需求: 要求用戶傳遞什么樣的型別,我回傳什么樣的物件 泛型的知識
public static <T> T toObj(String json,Class<T> target){
if(StringUtils.isEmpty(json) || target ==null){
throw new RuntimeException("引數不能為null");
}
try {
return MAPPER.readValue(json, target);
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
3.5 商品分類的快取實作
3.5.1 實作步驟
1.定義Redis中的key key必須唯一不能重復. 存 取 key = “ITEM_CAT_PARENTID::70”
2.根據key 去redis中進行查詢 有資料 沒有資料
3.沒有資料 則查詢資料庫獲取記錄 之后將資料保存到redis中 方便后續使用.
4.有資料 表示用戶不是第一次查詢 可以將快取資料直接回傳即可.
3.5.2 編輯ItemCatController

3.5.3 編輯ItemCatService
@Override
public List<EasyUITree> findItemCatListCache(Long parentId) {
//0.定義公共的回傳值物件
List<EasyUITree> treeList = new ArrayList<>();
//1.定義key
String key = "ITEM_CAT_PARENTID::"+parentId;
//2.檢索redis服務器,是否含有該key
//記錄時間
Long startTime = System.currentTimeMillis();
if(jedis.exists(key)){
//資料存在
String json = jedis.get(key);
Long endTime = System.currentTimeMillis();
//需要將json串轉化為物件
treeList = ObjectMapperUtil.toObj(json,treeList.getClass());
System.out.println("從redis中獲取資料 耗時:"+(endTime-startTime)+"毫秒");
}else{
//3.資料不存在 查詢資料庫
treeList = findItemCatList(parentId);
Long endTime = System.currentTimeMillis();
//3.將資料保存到快取中
String json = ObjectMapperUtil.toJSON(treeList);
jedis.set(key, json);
System.out.println("查詢資料庫 耗時:"+(endTime-startTime)+"毫秒");
}
return treeList;
}
3.5.4 使用Redis的速度差

4. AOP實作Redis快取
4.1 如何理解AOP
名稱: 面向切面編程
作用: 降低系統中代碼的耦合性,并且在不改變原有代碼的條件下對原有的方法進行功能的擴展.
公式: AOP = 切入點運算式 + 通知方法
4.2 通知型別
1.前置通知 目標方法執行之前執行
2.后置通知 目標方法執行之后執行
3.例外通知 目標方法執行程序中拋出例外時執行
4.最終通知 無論什么時候都要執行的通知
特點: 上述的四大通知型別 不能干預目標方法是否執行.一般用來做程式運行狀態的記錄.監控
5.環繞通知 在目標方法執行前后都要執行的通知方法 該方法可以控制目標方法是否運行.joinPoint.proceed(); 功能作為強大的.
4.3 切入點運算式
理解: 切入點運算式就是一個程式是否進入通知的一個判斷(IF)
作用: 當程式運行程序中 ,**滿足了切入點運算式時才會去執行通知方法,**實作業務的擴展.
種類(寫法):
1. bean(bean的名稱 bean的ID) 只能攔截具體的某個bean物件 只能匹配一個物件
lg: bean(“itemServiceImpl”)
2. within(包名.類名) within(“com.jt.service.*”) 可以匹配多個物件
粗粒度的匹配原則 按類匹配
3. execution(回傳值型別 包名.類名.方法名(引數串列)) 最為強大的用法
lg : execution(* com.jt.service..*.*(..))
回傳值型別任意 com.jt.service包下的所有的類的所有的方法都會被攔截.
4.@annotation(包名.注解名稱) 按照注解匹配.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/173272.html
標籤:其他
