MyBaits-Plus使用redis作为缓存的另外一种方法

文章写于2023-06-30,里面包的版本尽量都是用的当前日期下最新的,读者如果阅读的时间据此较远的话,应注意包和插件的版本.

不喜欢废话,直接放码过来.

一.引入包

需要引入的包有:reids,jedis,cache,thymeleaf,spring web,mysql,lombok

pom代码如下:



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        3.1.1
         
    
    com.flamelp
    demo
    0.0.1-SNAPSHOT
    MP_Redis
    MP_Redis
    
        17
    
    

        
            org.springframework.boot
            spring-boot-starter-data-redis
        
        
            redis.clients
            jedis
        
        
            org.springframework.boot
            spring-boot-starter-cache
        
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            com.mysql
            mysql-connector-j
            runtime
        
        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        

        
            com.baomidou
            mybatis-plus-generator
            3.5.3.1
        

        
            com.baomidou
            mybatis-plus-boot-starter
            3.5.3.1
        

        
            org.apache.velocity
            velocity
            1.7
        

        
            io.springfox
            springfox-swagger2
            3.0.0
        
        
            io.springfox
            springfox-swagger-ui
            3.0.0
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                
                    
                        
                            org.projectlombok
                            lombok
                        
                    
                
            
        

        
            
                src/main/resources
                
                    mapper/*.xml
                    static/*.*
                    templates/*.html

                    *.yml
                
            
        
    


二.编写redis

创建一个utils包,在包下面创建一个RedisConfig来,用于管理redis缓存.代码如下.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

@Configuration
@EnableCaching//驱动缓存
public class RedisConfig extends CachingConfigurerSupport {
    @Bean("redisPoolConfig")
    public JedisPoolConfig poolConfig(){
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        //最大空闲数
        poolConfig.setMaxIdle(50);
        //最大连接数
        poolConfig.setMaxTotal(100);
        //最大等待时间,毫秒
        poolConfig.setMaxWaitMillis(200000);
        //poolConfig.setMaxWait(Duration.ofMillis(200000));
        return poolConfig;
    }

    @Bean("redisConnectionFactory")
    public RedisConnectionFactory redisConnectionFactory(@Autowired JedisPoolConfig jedisPoolConfig){
        RedisStandaloneConfiguration rsc = new RedisStandaloneConfiguration();
        //设置Redis服务器
        rsc.setHostName("127.0.0.1");
        //设置密码
        rsc.setPassword("123456");
        //端口
        rsc.setPort(6379);
        //获得默认连接池构造器
        JedisClientConfiguration.JedisClientConfigurationBuilder jpcb = JedisClientConfiguration.builder();
        //设置Redis连接池
        jpcb.usePooling().poolConfig(jedisPoolConfig);
        //获取构建器
        JedisClientConfiguration jedisClientConfiguration = jpcb.build();
        //创建工厂
        return new JedisConnectionFactory(rsc,jedisClientConfiguration);
    }

    /**
     * 配置redis数据存储模板
     * @param connectionFactory
     * @return
     */
    @Bean("redisTemplate")
    public RedisTemplate redisTemplate(@Autowired RedisConnectionFactory connectionFactory){
        //创建redis模板
        RedisTemplate redisTemplate = new RedisTemplate<>();
        //字符串和JDK序列化器
        RedisSerializer strSerializer = RedisSerializer.string();
        RedisSerializer jdkSerializer = RedisSerializer.java();
        //设置键值序列化器
        redisTemplate.setKeySerializer(strSerializer);
        redisTemplate.setValueSerializer(jdkSerializer);
        //设置好哈希字段和值序列化器
        redisTemplate.setHashKeySerializer(strSerializer);
        redisTemplate.setHashValueSerializer(jdkSerializer);
        //设置redisTemplate的连接工厂
        redisTemplate.setConnectionFactory(connectionFactory);
        return redisTemplate;
    }

    /**
     * 设置字符串连接模板
     * @param connectionFactory
     * @return
     */
    @Bean("stringRedisTemplate")
    public StringRedisTemplate stringRedisTemplate(@Autowired RedisConnectionFactory connectionFactory){
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
        stringRedisTemplate.setConnectionFactory(connectionFactory);
        return stringRedisTemplate;
    }

    /**
     * 初始化缓存管理器
     * @param redisConnectionFactory
     * @return
     */
    @Bean(name="redisCacheManager")
    public CacheManager initRedisCacheManager(@Autowired RedisConnectionFactory redisConnectionFactory){
        //获得redis默认配置
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        //创建redis缓存管理器
        RedisCacheManager cacheManager = RedisCacheManager.RedisCacheManagerBuilder
                .fromConnectionFactory(redisConnectionFactory)
                //定义缓存管理器名称和配置,以便后续使用
                .withCacheConfiguration("redisCacheManager",config)
                .build();
        return cacheManager;
    }
}
 
  

三.在spring boot项目的启动类的main方法中添加如下代码:

    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(RedisConfig.class);
        SpringApplication.run(MpRedisApplication.class, args);
    }

四.修改你的application.yml文件,除了基础配置之外,主要是在执行SQL语句的时候把SQL命令打印在控制台,看看SQL语句的执行情况,或者是否有读取redis的缓存.

#server
server:
  port: 8092
  servlet:
    context-path: /

#spring
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/XXXX
    username: xxxx
    password: xxxx


#mybatis-plus
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    #开启缓存
     cache-enabled: true

五.在你的service类的增删改查方法中加上以下标签就可以实现redis的缓存

@Cacheable,@CachePut,@CacheEvict

但是我们打算偷个懒,使用mybaits plus生成项目框架,所以还得做些其它事情.

六.mybatis plus自带的方法对redis的缓存实现不够友好,所以动手修改下几个父类,官方建议将缓存放在service层实现,所以就针对这一层下手.

mybatis plus 的service层的接口和类分别实现和继承了:IService,ServiceImpl.打算自定义父类和接口.所以有以下代码:

在utils包里创建IMyService接口,具体代码如下:

import com.baomidou.mybatisplus.extension.service.IService;

import java.io.Serializable;

public interface IMyService extends IService {
    T selectById(Serializable id);
    T add(T entity);
    boolean delete(Serializable id);
    T modify(T entity);
}
IMyService中自定义增删改查的方法,用这些方法来实现redis的缓存.请注意用上面的这几个方法实现数据的增删改查就会调用缓存,其它的不会使用缓存,如果读者需要对更多的方法实现缓存,在上面这个接口增加方法就行(当然还要最下面的这个类里面实现对应的方法.)

查询所有结果,按条件查询结果这些的结果,重复使用率不高对于缓存的意义不大,所以没有做缓存.

在utils包里在创建MyServiceImpl类,代码如下:

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;

import java.io.Serializable;

public class MyServiceImpl, T> extends ServiceImpl {

    /**
     * @Cacheable:先查缓存,缓存没有对应的key值在查找数据库,找到后再进行缓存.
     * value:redisCacheManager.缓存的名称,放在同一个缓存里面,通过key值进行区分方便管理.
     * key:缓存在redis中时以键值对的形式存在.根据key查找缓存的值,所以不同类型的缓存不能仅仅依靠id进行区分.
     * 这里用实体类名+_主键id作为key,确保key的唯一性.
     * #root.target对象为调用该方法的类,获得类名后(serviceImpl类),根据命名规则去掉'ServiceImpl'后就是实体类名.
     * unless = "#result==null" 当没有查询到结果时不进行缓存.
     */
    @Cacheable(value="redisCacheManager"
            ,key ="#root.target.getClass().getSimpleName().replaceAll('ServiceImpl','_')+#id"
            ,unless = "#result==null")
    public T selectById(Serializable id){
        return this.getById(id);
    }

    //@CachePut会调用方法,并将方法的结果进行缓存.
    @CachePut(value = "redisCacheManager"
            ,key="#root.target.getClass().getSimpleName().replaceAll('ServiceImpl','_')+#entity.id")
    public T add(T entity){
        this.save(entity);
        return entity;
    }

    //@CacheEvict删除对应的缓存,再执行方法
    @CacheEvict(value="redisCacheManager"
            ,key="#root.target.getClass().getSimpleName().replaceAll('ServiceImpl','_')+#id")
    public boolean delete(Serializable id){
        return this.removeById(id);
    }

    @CachePut(value = "redisCacheManager"
            ,key="#root.target.getClass().getSimpleName().replaceAll('ServiceImpl','_')+#entity.id")
    public T modify(T entity){
        this.updateById(entity);
        return entity;
    }
}

七.使用mybatis-plus生成项目框架

到这一步redis缓存的设置和mybatis-plus自定义父类就已经完成了.接下来编写MP的代码生成器.

还是在utils包里面创建CreateFrame类,用于生成MP代码框架.具体代码如下:

import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;

import java.sql.Types;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class CreateFrame {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/XXXX";
        String username="root";
        String password = "XXXXX";

        String pkgPath = System.getProperty("user.dir")+"/src/main/java";
        String pkgXml = System.getProperty("user.dir")+"/src/main/resources/mapper";

        FastAutoGenerator.create(url, username, password)
                .globalConfig(builder -> {//全局配置
                    builder.author("flamelp. 仅用于教学使用") // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .dateType(DateType.TIME_PACK)//使用time类型转换数据库中的时间
                            .commentDate("yyyy-MM-dd")//注释日期
                            .outputDir(pkgPath); // 指定输出目录
                })
                .dataSourceConfig(builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
                    int typeCode = metaInfo.getJdbcType().TYPE_CODE;
                    if (typeCode == Types.SMALLINT) {// 自定义类型转换
                        return DbColumnType.INTEGER;
                    }
                    return typeRegistry.getColumnType(metaInfo);

                }))
                .packageConfig(builder -> {//将包都放在启动类所在的包下面.
                    builder.parent("com.flamelp") // 设置父包名
                            .moduleName("demo") // 设置父包模块名
//                            .entity("entity")//entity包名
//                            .mapper("mapper")//dao包名
//                            .service("service")//service包名
//                            .service("service.impl")//service实体类包名
//                            .controller("controller")//controller包名
//                            .xml("mapper")//xml文件包名
                            .pathInfo(Collections.singletonMap(OutputFile.xml, pkgXml)); // 设置mapperXml生成路径
                })
                .strategyConfig(builder -> {
                    builder.addInclude(getTables("all")); // 设置需要生成的表名
                    //.addTablePrefix("t_"); // 设置过滤表前缀

                    //实体类配置
                    builder.build().entityBuilder()
                            .enableLombok()//设置Lombok注解
                            //.enableFileOverride()//覆盖已生成的文件,
                            .enableTableFieldAnnotation()//开启实体类字段注解
                            .naming(NamingStrategy.underline_to_camel)//数据库表名命名规则:下划线转驼峰
                            .columnNaming(NamingStrategy.no_change)//数据表字段命名规则:不处理
//                            .logicDeletePropertyName("deleted")//逻辑删除属性名(实体)
                    ;//数据进行逻辑删除

                    //controller配置策略
                    builder.build().controllerBuilder();

                    //service配置策略
                    builder.build().serviceBuilder()
                            .superServiceClass("com.flamelp.demo.utils.IMyService")//设置服务类的父类
                            .superServiceImplClass("com.flamelp.demo.utils.MyServiceImpl");//设置服务实现类的父类.

                    //Mapper(dao)配置
                    builder.build().mapperBuilder()
                            .enableMapperAnnotation()//设置mapper注解
                            .enableBaseResultMap()//启用 BaseResultMap 生成resultMap
                            //.superClass("MPJBaseMapper")//设置mapper类的父类
                            //.enableFileOverride()//覆盖已生成的文件,
                            .enableBaseColumnList()//启用 BaseColumnList,生成列的列表
//                            .cache(MybatisRedisCache.class)//开启缓存.
                    ;
                })
                // 使用Freemarker引擎模板,默认的是Velocity引擎模板,使用Velocity模版时,需要在pom文件中配置Velocity的引用
                .templateEngine(new VelocityTemplateEngine())
                .execute();
    }
    protected static List getTables(String tables) {
        return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
    }
}

八.运行CreateFrame类中的main方法,

搞定,收工,写到第八点感觉自己写了个八股文似的.上面代码的注释比较全,所以没有用过多的语言描述.

另外使用mysql数据库时数据库表采用"_"下划线分隔单词是个好的方法,因为mysql的表名全部给你转小写了,但是没关系MP会给你在实体类等类的命名中给你改成驼峰命名法.但是表的列名就没有必要使用下划线了,MySQL可以识别列名大小写.

你可能感兴趣的:(SSM,java,spring,maven,spring,boot,intellij-idea)