日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

springboot配置mybatis redis缓存

發布時間:2024/1/18 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springboot配置mybatis redis缓存 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、概述

首先來了解下mybatis 緩存,mybatis緩存分為一級緩存和二級緩存。一級緩存是默認開啟的,無需其他配置操作,二級緩存則需要手動設置開啟。

一級緩存原理:

Mybatis的一級緩存是指同一個SqlSession中的操作。一級緩存的作用域是一個SqlSession。
在同一個SqlSession中,執行相同的查詢SQL,第一次會去查詢數據庫,并寫到緩存中;第二次直接從緩存中取。當執行SQL時兩次查詢中間發生了增刪改操作,則SqlSession的緩存清空。

二級緩存原理:

Mybatis的二級緩存是指mapper映射文件。二級緩存是多個sqlSession共享的,其作用域是mapper下的同一個namespace。
在不同的sqlSession中,相同的namespace下,相同的查詢sql語句并且參數也相同的情況下,會命中二級緩存。如果調用相同namespace下的mapper映射文件中的增刪改SQL,并執行了commit操作。此時會清空該namespace下的二級緩存。

二、代碼實現

了解一些基本原理后,我們開始在springboot集成mybatis的情況下,開啟二級緩存。

  • 在pom.xml文件中引入mybatis和redis的依賴 <!--mybatis 依賴包--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--redis lettuce--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency>

  • 在application.yml文件中配置mybatis相關設置時,開啟二級緩存 ### mybatis相關配置 mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl#開啟MyBatis的二級緩存cache-enabled: truemapper-locations: classpath*:mappers/*Mapper.xml### Redis 相關配置 redis:host: localhostport: 6379timeout: 10000database: 0lettuce:pool:max-active: 8max-wait: -1max-idle: 8min-idle: 0

  • 實體類實現序列化
  • 我們采用的redis序列化方式是默認的jdk序列化。所以數據庫的查詢對象(比如Student類)需要實現Serializable接口。

    public class Student implements Serializable {//采用的redis序列化方式是默認的jdk序列化。所以數據庫的查詢對象實體需要實現Serializable接口。private static final long serialVersionUID = 1L;private int id;private String name;private int age;private String position;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getPosition() {return position;}public void setPosition(String position) {this.position = position;}@Overridepublic String toString() {return "Student{" +"id=" + id +", name='" + name + '\'' +", age=" + age +", position='" + position + '\'' +'}';} }

    ?

    4、先看一下Redis的配置類(這里用的是lettuce)

    @Configuration public class RedisConfig {@Autowiredprivate LettuceConnectionFactory connectionFactory;@Beanpublic RedisTemplate<String,Object> redisTemplate() {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();initDomainRedisTemplate(redisTemplate, connectionFactory);return redisTemplate;}/*** 設置數據存入 redis 的序列化方式* @param template* @param factory*/private void initDomainRedisTemplate(RedisTemplate<String, Object> template,LettuceConnectionFactory factory) {// 定義 key 的序列化方式為 string// 需要注意這里Key使用了 StringRedisSerializer,那么Key只能是String類型的,不能為Long,Integer,否則會報錯拋異常。StringRedisSerializer redisSerializer = new StringRedisSerializer();template.setKeySerializer(redisSerializer);// 定義 value 的序列化方式為 json@SuppressWarnings({"rawtypes", "unchecked"})Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);template.setValueSerializer(jackson2JsonRedisSerializer);//hash結構的key和value序列化方式template.setHashKeySerializer(jackson2JsonRedisSerializer);template.setHashValueSerializer(jackson2JsonRedisSerializer);template.setEnableTransactionSupport(true);template.setConnectionFactory(factory);} }

    5、緩存配置類

    public class MybatisRedisCache implements Cache {private static final Logger log = LoggerFactory.getLogger(MybatisRedisCache.class);private String id;private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();//private static final long EXPIRE_TIME_IN_MINUTES = 30; // redis過期時間public MybatisRedisCache(String id) {this.id = id;}private RedisTemplate<Object, Object> getRedisTemplate(){return ApplicationContextHolder.getBean("redisTemplate");}@Overridepublic String getId() {return id;}@Overridepublic void putObject(Object key, Object value) {RedisTemplate redisTemplate = getRedisTemplate();redisTemplate.boundHashOps(getId()).put(key, value);log.info("[結果放入到緩存中: " + key + "=" + value+" ]");}@Overridepublic Object getObject(Object key) {RedisTemplate redisTemplate = getRedisTemplate();Object value = redisTemplate.boundHashOps(getId()).get(key);log.info("[從緩存中獲取了: " + key + "=" + value+" ]");return value;}@Overridepublic Object removeObject(Object key) {RedisTemplate redisTemplate = getRedisTemplate();Object value = redisTemplate.boundHashOps(getId()).delete(key);log.info("[從緩存刪除了: " + key + "=" + value+" ]");return value;}@Overridepublic void clear() {RedisTemplate redisTemplate = getRedisTemplate();redisTemplate.delete(getId());log.info("清空緩存!!!");}@Overridepublic int getSize() {RedisTemplate redisTemplate = getRedisTemplate();Long size = redisTemplate.boundHashOps(getId()).size();return size == null ? 0 : size.intValue();}@Overridepublic ReadWriteLock getReadWriteLock() {return readWriteLock;} }

    ?ps:
    重點部分就是重寫這個mybatis的cache類,它只會對配置文件類型的映射文件起作用。
    該接口共有以下五個方法:
    String getId():mybatis緩存操作對象的標識符。一個mapper對應一個mybatis的緩存操作對象。
    void putObject(Object key, Object value):將查詢結果塞入緩存。
    Object getObject(Object key):從緩存中獲取被緩存的查詢結果。
    Object removeObject(Object key):從緩存中刪除對應的key、value。只有在回滾時觸發。
    void clear():發生更新時,清除緩存。
    int getSize():可選實現。返回緩存的數量。
    ReadWriteLock getReadWriteLock():可選實現。用于實現原子性的緩存操作。

    上述重寫cache類中有幾個關鍵點:

    • 自定義實現的二級緩存,必須要有一個帶id的構造函數,否則會報錯。
    • 此處使用Spring封裝的redisTemplate來操作Redis。很多都是直接用jedis庫,但是現在springboot2.x 以上對lettuce的兼容更好。RedisTemplate封裝了底層的實現,使用redisTemplate會更加方便,無論是使用jedis還是使用lettuce,我們可以直接更換底層的庫,無需修改上層代碼。
    • 這里不能通過@Autowire的方式引用redisTemplate,因為RedisCache并不是Spring容器里的bean。所以我們需要手動地去調用容器的getBean方法來拿到這個bean,那么這樣,我們就需要引入ApplicationContextHolder這個類。
  • ApplicationContextHolder.java (我們需要通過這個類得到RedisTemplate)
  • ?

    @Component public class ApplicationContextHolder implements ApplicationContextAware{private static ApplicationContext applicationContext;/*** 實現ApplicationContextAware接口的context注入函數, 將其存入靜態變量.*/public void setApplicationContext(ApplicationContext applicationContext) {ApplicationContextHolder.applicationContext = applicationContext; // NOSONAR}/*** 取得存儲在靜態變量中的ApplicationContext.*/public static ApplicationContext getApplicationContext() {checkApplicationContext();return applicationContext;}/*** 從靜態變量ApplicationContext中取得Bean, 自動轉型為所賦值對象的類型.*/@SuppressWarnings("unchecked")public static <T> T getBean(String name) {checkApplicationContext();return (T) applicationContext.getBean(name);}/*** 從靜態變量ApplicationContext中取得Bean, 自動轉型為所賦值對象的類型.*/@SuppressWarnings("unchecked")public static <T> T getBean(Class<T> clazz) {checkApplicationContext();return (T) applicationContext.getBeansOfType(clazz);}/*** 清除applicationContext靜態變量.*/public static void cleanApplicationContext() {applicationContext = null;}private static void checkApplicationContext() {if (applicationContext == null) {throw new IllegalStateException("applicaitonContext未注入,請在applicationContext.xml中定義SpringContextHolder");}} }

    7、然后再映射文件中開啟二級緩存(使用二級緩存)

    <mapper namespace="com.example.demo.dao.StudentDao"><!-- 開啟基于redis的二級緩存 --><cache type="com.example.demo.redis.cache.MybatisRedisCache"/><cache/><insert id="insert" parameterType="com.example.demo.entity.Student" useGeneratedKeys="true" keyProperty="id">insert intostudents(name,age,position)values(#{name},#{age},#{position})</insert><insert id="batchInsert" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">insert intostudents(name,age,position)values<foreach collection="studentList" item="item" index="index" open="" close="" separator=",">(#{item.name},#{item.age},#{item.position})</foreach></insert><delete id="delete" parameterType="java.lang.String">delete from students where name = #{name}</delete><!--并且在update語句中,設置flushCache為true,這樣在更新信息時,能夠自動失效緩存(本質上調用的是clear方法)--><update id="update" parameterType="com.example.demo.entity.Student" flushCache="true">update studentsset students.position = #{position}where name = #{name}</update><select id="findByName" resultMap="BaseResultMap">select *from studentswhere name = #{name}</select><select id="findAll" resultMap="BaseResultMap">select *from students</select><resultMap id="BaseResultMap" type="com.example.demo.entity.Student"><result column="name" property="name"/><result column="age" property="age"/><result column="position" property="position"/></resultMap> </mapper>

    下面是我在實現二級緩存過程中一些報錯問題:

  • 在我修改了序列化問題后,報錯消失。
  • 總結

    以上是生活随笔為你收集整理的springboot配置mybatis redis缓存的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。