Spring Boot基礎(chǔ)學(xué)習(xí)之Mybatis操作中使用Redis做緩存詳解
前言
這篇博客學(xué)習(xí)下Mybatis操作中使用Redis做緩存。這里其實(shí)主要學(xué)習(xí)幾個(gè)注解:@CachePut、@Cacheable、@CacheEvict、@CacheConfig。
下面話不多說了,來一起看看詳細(xì)的介紹吧
一、基礎(chǔ)知識
@Cacheable
@Cacheable 的作用 主要針對方法配置,能夠根據(jù)方法的請求參數(shù)對其結(jié)果進(jìn)行緩存
| 參數(shù) | 解釋 | example |
|---|---|---|
| value | 緩存的名稱,在 spring 配置文件中定義,必須指定至少一個(gè) | 例如: @Cacheable(value=”mycache”) @Cacheable(value={”cache1”,”cache2”} |
| key | 緩存的 key,可以為空,如果指定要按照 SpEL 表達(dá)式編寫,如果不指定,則缺省按照方法的所有參數(shù)進(jìn)行組合 | @Cacheable(value=”testcache”,key=”#userName”) |
| condition | 緩存的條件,可以為空,使用 SpEL 編寫,返回 true 或者 false,只有為 true 才進(jìn)行緩存 | @Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
@CachePut
@CachePut 的作用 主要針對方法配置,能夠根據(jù)方法的返回值對其結(jié)果進(jìn)行緩存,和 @Cacheable 不同的是,它每次都會觸發(fā)真實(shí)方法的調(diào)用,在其他地方寫的是根據(jù)方法的請求參數(shù)對其結(jié)果進(jìn)行緩存,實(shí)際是按方法返回值進(jìn)行緩存的,這里我就遇到了一個(gè)坑,我開始的時(shí)候是在Mybatis的Mapper層進(jìn)行緩存的,如下面的代碼。但是緩存到Redis的是Null值,今天看了一博友的博客,交流了一下,才知道它緩存的是方法的返回值,如果把下面update的返回值該為int,在redis中保存的是int類型,報(bào)的錯(cuò)誤是int無法轉(zhuǎn)換成User對象。
@CachePut(value="user",key = "#p0.id")
@Update({"UPDATE user SET name=#{name},age=#{age} WHERE id =#{id}"})
void update(User user);
| 參數(shù) | 解釋 | example |
|---|---|---|
| value | 緩存的名稱,在 spring 配置文件中定義,必須指定至少一個(gè) | @CachePut(value=”my cache”) |
| key | 緩存的 key,可以為空,如果指定要按照 SpEL 表達(dá)式編寫,如果不指定,則缺省按照方法的所有參數(shù)進(jìn)行組合 | @CachePut(value=”testcache”,key=”#userName”) |
| condition | 緩存的條件,可以為空,使用 SpEL 編寫,返回 true 或者 false,只有為 true 才進(jìn)行緩存 | @CachePut(value=”testcache”,condition=”#userName.length()>2”) |
@CachEvict
@CachEvict 的作用 主要針對方法配置,能夠根據(jù)一定的條件對緩存進(jìn)行清空
| 參數(shù) | 解釋 | example |
|---|---|---|
| value | 緩存的名稱,在 spring 配置文件中定義,必須指定至少一個(gè) | @CacheEvict(value=”my cache”) |
| key | 緩存的 key,可以為空,如果指定要按照 SpEL 表達(dá)式編寫,如果不指定,則缺省按照方法的所有參數(shù)進(jìn)行組合 | @CacheEvict(value=”testcache”,key=”#userName”) |
| condition | 緩存的條件,可以為空,使用 SpEL 編寫,返回 true 或者 false,只有為 true 才進(jìn)行緩存 | @CacheEvict(value=”testcache”,condition=”#userName.length()>2”) |
| allEntries | 是否清空所有緩存內(nèi)容,缺省為 false,如果指定為 true,則方法調(diào)用后將立即清空所有緩存 | @CachEvict(value=”testcache”,allEntries=true) |
| beforeInvocation | 是否在方法執(zhí)行前就清空,缺省為 false,如果指定為 true,則在方法還沒有執(zhí)行的時(shí)候就清空緩存,缺省情況下,如果方法執(zhí)行拋出異常,則不會清空緩存 | @CachEvict(value=”testcache”,beforeInvocation=true) |
@CacheConfig
所有的@Cacheable()里面都有一個(gè)value=“xxx”的屬性,這顯然如果方法多了,寫起來也是挺累的,如果可以一次性聲明完 那就省事了,有了@CacheConfig這個(gè)配置,@CacheConfig is a class-level annotation that allows to share the cache names,如果你在你的方法寫別的名字,那么依然以方法的名字為準(zhǔn)。
二、實(shí)例
還是在上一博客demo的基礎(chǔ)上進(jìn)行修改,原本是在Mybatis的Mapper層上增加cache注解,但由于update返回值為void,所以這里又增加了一services層,mapper層算是DAO層。這里使用了@CacheConfig注解指定類級別的value屬性,如果在方法上定義就以方法為主,就近原則。
package com.example.services;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.example.model.User;
import com.example.write.mapper.WriteUserMapper;
@Service
@CacheConfig(cacheNames="user")
public class UserServices {
@Autowired
private WriteUserMapper writeUserMapper;
public List<User> getAll()
{
return writeUserMapper.getAll();
}
@Cacheable(key = "#p0")
public User getOne(String id)
{
return writeUserMapper.getOne(id);
}
public void insert(User user)
{
writeUserMapper.insert(user);
}
@CachePut(value="user",key = "#p0.id")
public User update(User user)
{
writeUserMapper.update(user);
return user;
}
@CacheEvict(value="user",key ="#p0",allEntries=true)
public void delete(String id)
{
writeUserMapper.delete(id);
}
}
UserController
package com.example.demo;
import java.io.Serializable;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.example.model.User;
import com.example.model.UserSexEnum;
import com.example.read.mapper.ReadUserMapper;
import com.example.services.UserServices;
import com.example.write.mapper.WriteUserMapper;
import io.lettuce.core.dynamic.annotation.Param;
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private WriteUserMapper userMapperWrite;
@Autowired
private ReadUserMapper userMapperRead;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private RedisTemplate<String, Serializable> redisCacheTemplate;
@Autowired
private UserServices userServices;
@RequestMapping(value = "/alluser.do",method = RequestMethod.GET)
public String getallusers(Model model) {
List<User> users=userServices.getAll();
model.addAttribute("users", users);
// stringRedisTemplate.opsForValue().set("keytest", "cuiyw");
// final String keytest = stringRedisTemplate.opsForValue().get("keytest");
// model.addAttribute("keytest", keytest);
// String key = "1857XXXX040";
// redisCacheTemplate.opsForValue().set(key, new User(key, "cuiyw", 18, UserSexEnum.MAN));
// // TODO 對應(yīng) String(字符串)
// final User user = (User) redisCacheTemplate.opsForValue().get(key);
// model.addAttribute("user", user);
return "userlist";
}
@RequestMapping(value = "/insert.do",method = RequestMethod.GET)
public String adduser(Model model) {
User user=new User();
user.setName("cuiyw");
user.setAge(27);
userServices.insert(user);
// List<User> users=userMapperWrite.getAll();
// model.addAttribute("users", users);
return "forward:/user/alluser.do";
}
@RequestMapping(value = "/getuserbyid.do/{id}",method = RequestMethod.GET)
public ModelAndView GetUserById(@PathVariable("id") String id) {
System.out.println(id);
User user=userServices.getOne(id);
System.out.println(user.toString());
ModelAndView modelAndView = new ModelAndView("userlist");
modelAndView.addObject("user", user);
return modelAndView;
}
@RequestMapping(value = "/deleteuserbyid.do/{id}",method = RequestMethod.GET)
public String DeleteUserById(@PathVariable("id") String id) {
userServices.delete(id);
return "forward:/user/alluser.do";
}
@RequestMapping(value = "/updateuserbyid.do/{id}",method = RequestMethod.GET)
public String UpdateUserByid(@PathVariable("id") String id) {
User user=userServices.getOne(id);
System.out.println(user.toString());
user.setAge(28);
System.out.println(user.toString());
userServices.update(user);
System.out.println(user.toString());
return "forward:/user/alluser.do";
}
}
這里先輸入http://localhost:8080/user/getuserbyid.do/17通過getOne()方法在redis中緩存一個(gè)user。通過redis-cli可以看到user::17已在redis中。

然后通過update()方法輸入http://localhost:8080/user/updateuserbyid.do/17修改user,此時(shí)年齡改為了28,數(shù)據(jù)庫的值也會變了。然后多次使用http://localhost:8080/user/updateuserbyid.do/17這個(gè)url刷新瀏覽器,此時(shí)是不會報(bào)錯(cuò)的,如果是在mapper中使用@Cacheput時(shí)由于保存的是null就會導(dǎo)致報(bào)錯(cuò)。
最后通過delete()方法輸入http://localhost:8080/user/deleteuserbyid.do/17刪除redis和數(shù)據(jù)庫中的user對象.

至此,基本把這4個(gè)注解大致了解了一下,這里還有一個(gè)地方需要補(bǔ)充,就是如果按照上面運(yùn)行還是不行的,它依然找不到UserServices,在UserController中找不到這個(gè)類,還需要在main方法上面@ComponentScan注解加上掃描com.example.services。
@ComponentScan(basePackages={"com.example.config","com.example.demo","com.example.services"})
最后來一碗雞湯,記錄下今天看抖音聽到的一句話,還挺有道理。
為什么大多數(shù)人寧愿吃生活的苦,而不愿意吃學(xué)習(xí)的苦?因?yàn)閷W(xué)習(xí)的苦需要自己主動去吃,而生活的苦你躺著它就來了。
總結(jié):
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
- 如何利用Redis作為Mybatis的二級緩存
- MyBatis整合Redis實(shí)現(xiàn)二級緩存的示例代碼
- Mybatis-plus基于redis實(shí)現(xiàn)二級緩存過程解析
- mybatis plus使用redis作為二級緩存的方法
- SpringBoot+Mybatis項(xiàng)目使用Redis做Mybatis的二級緩存的方法
- redis與ssm整合方法(mybatis二級緩存)
- springboot+mybatis+redis 二級緩存問題實(shí)例詳解
- 詳解Spring boot使用Redis集群替換mybatis二級緩存
- MyBatis緩存和二級緩存整合Redis的解決方案
相關(guān)文章
IntelliJ IDEA 2020.3 重大特性(新功能一覽)
這篇文章主要介紹了IntelliJ IDEA 2020.3 重大特性(新功能一覽),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
Java實(shí)現(xiàn)發(fā)送郵件功能時(shí)碰到的坑
之前用163郵箱發(fā)郵件時(shí)明明是成功的,但是使用中國移動自己的郵箱時(shí),無論如何在linux服務(wù)器中都發(fā)送不成功。下面小編給大家說下我是怎么解決的,一起看下吧2016-06-06
java使用三層架構(gòu)實(shí)現(xiàn)電影購票系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java使用三層架構(gòu)實(shí)現(xiàn)電影購票系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01
SpringSecurity?表單登錄的實(shí)現(xiàn)
本文主要介紹了SpringSecurity?表單登錄的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12
java多線程數(shù)據(jù)分頁處理實(shí)例講解
在本篇內(nèi)容里小編給大家分享了一篇關(guān)于java多線程數(shù)據(jù)分頁處理實(shí)例講解內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。2021-01-01
java利用DFA算法實(shí)現(xiàn)敏感詞過濾功能
在最近的開發(fā)中遇到了敏感詞過濾,便去網(wǎng)上查閱了很多敏感詞過濾的資料,在這里也和大家分享一下自己的理解。下面這篇文章主要給大家介紹了關(guān)于java利用DFA算法實(shí)現(xiàn)敏感詞過濾功能的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-06-06
java基于jdbc連接mysql數(shù)據(jù)庫功能實(shí)例詳解
這篇文章主要介紹了java基于jdbc連接mysql數(shù)據(jù)庫功能,結(jié)合實(shí)例形式詳細(xì)分析了jdbc連接mysql數(shù)據(jù)庫的原理、步驟、實(shí)現(xiàn)方法及相關(guān)操作技巧,需要的朋友可以參考下2017-10-10
Java如何簡單快速入門JWT(token生成與驗(yàn)證)
這篇文章主要給大家介紹了關(guān)于Java如何簡單快速入門JWT(token生成與驗(yàn)證)的相關(guān)資料,JWT是一個(gè)加密的字符串,JWT傳輸?shù)男畔⒔?jīng)過了數(shù)字簽名,因此傳輸?shù)男畔⒖梢员或?yàn)證和信任,需要的朋友可以參考下2023-12-12

