springboot之mysql、mybatis、SpringCache、redis缓存

需要了解

mybatis二级缓存默认开启,需要设置二级缓存介质才可生效,二级缓存底层是管理一级缓存,
将每个本地一级缓存集合化管理

二级缓存介质

Ehcache、SpringCache、Redis

SpringCache缓存介质的不同实现

在这里插入图片描述

代码

项目结构
在这里插入图片描述

创建database

name :demo
table :user(id,name,age)
statement:insert into user values(1,"admin",23);

pom
多加如下依赖

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.1.1</version>
    </dependency>
    <!-- mysql 依赖 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!--默认SpringCache缓存,SpringCache可以有多种缓存实现,比如redis-->
    <!--<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

yml

server:
  servlet:
    context-path: /
  port: 8088
spring:
  application:
    name: springboot-mysql-mybatis-springcache-redis
  redis:
      #表示连接redis 0表示数据库index
      database: 0
      host: 127.0.0.1
      port: 6379
      password: root
  datasource:
    url: jdbc:mysql://localhost:3306/demo?characterEncoding=UTF-8
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
  #设置SpringCache类型为redis实现
  cache:
    type: redis
#mybatis配置
mybatis:
  mapper-locations: classpath:mybatis/mapper/*.xml
  config-location: classpath:mybatis/mybatis-config.xml
#指定某个包发生日志操作就在后台打印,不设置无法打印预编译SQL
logging:
  level:
    com:
      whotw: debug

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
    </typeAliases>
</configuration>

userMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.whotw.mapper.UserMapper">

    <resultMap id="BaseResultMap" type="com.whotw.User">
        <result column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="age" property="age"/>
    </resultMap>
    <sql id="Base_Column_List">
                `id`,
                `name`,
                `age`
    </sql>
    <select id="load" resultMap="BaseResultMap">
        SELECT
        <include refid="Base_Column_List"/>
        FROM user
        WHERE `id` = #{id}
    </select>
    <insert id="insert" useGeneratedKeys="true" keyColumn="id" parameterType="com.whotw.User">
        INSERT INTO user(name,age) values (#{user.name},#{user.age})
    </insert>
    <!--此处一定要配置,否则缓存不起效,mybatis底层会读取该标签设置缓存,此标签有部分属性和默认值,文章下面会详解该标签-->
    <cache/>
    <!--每个mapper文件都有一个自己的txCache,引用其他txCache缓存-->
    <!--<cache-ref namespace=""></cache-ref>-->
</mapper>

UserMapper

@Mapper
@Repository
public interface UserMapper {
    int insert(@Param("user") User user);
    User load(@Param("id") int id);
}

UserService

public interface UserService {
    public User load(int id);

    public boolean add(User user);

}

UserServiceImpl

@Service
public class UserServiceImpl implements UserService {
    @Resource
    private UserMapper userMapper;
	//文章下面会讲解@Cacheable、@CacheEvict、@CachePut使用和区别
    @Cacheable(cacheNames = {CacheConfiguration.USER_CACHE}, key = "#root.methodName+#id")
    @Override
    public User load(int id) {
        return userMapper.load(id);
    }

    @Override
    public boolean add(User user) {
        int insert = userMapper.insert(user);
        if (insert > 0) {
            return true;
        }
        return false;
    }
}

UserController

@RestController
public class UserController {
    @Resource
    private UserService userService;

    @RequestMapping("/load")
    public User load(int id) {
        return userService.load(id);
    }

    @RequestMapping("/add")
    public boolean add() {
        User user = new User();
        user.setName("李四");
        user.setAge(23);
        return userService.add(user);
    }
}

User

@Data
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private Integer id;
    private String name;
    private Integer age;
}

CacheConfiguration

@Configuration
public class CacheConfiguration {
    /**
     * 用户搜素缓存
     */
    public static final String USER_CACHE = "user_cache";

    @Primary
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
        redisCacheConfiguration = redisCacheConfiguration
                //设置缓存的默认超时时间:30 minutes
                .entryTtl(Duration.ofMinutes(30L))
                //如果是空值,不缓存
                .disableCachingNullValues()
                //设置key序列化器
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
                //设置value序列化器
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()));
        return RedisCacheManager
                .builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
                .cacheDefaults(redisCacheConfiguration)
                .build();
    }

    /**
     * key序列化器
     */
    private RedisSerializer<String> keySerializer() {
        return new StringRedisSerializer();
    }

    /**
     * value序列化器
     */
    private RedisSerializer<Object> valueSerializer() {
        return new GenericJackson2JsonRedisSerializer();
    }
}

StartApp

@SpringBootApplication
/** 开启SpringCache*/
@EnableCaching
@Slf4j
public class StartApp {
    public static void main(String[] args) {
        SpringApplication.run(StartApp.class, args);
    }
}

测试

先要启动redis
多次调用此接口会发现控制台只调用了一次SQL
http://localhost:8088/load?id=1
在这里插入图片描述
redis生成相应缓存数据
在这里插入图片描述

cache与cache-ref标签

<cache eviction="LRU" flushInterval="10000" size="1024" readOnly="true"/>

这句配置中大部分属性都有默认配置,不用配置也可使用,即直接<cache />就可使用缓存
下面讨论下 <cache />的属性

eviction回收策略

LRU,  最近最少使用的,移除最长时间不用的对象。
FIFO,先进先出,按对象进入缓存的顺序来移除他们
SOFT, 软引用,移除基于垃圾回收器状态和软引用规则的对象。
WEAK,若引用,更积极的移除基于垃圾收集器状态和若引用规则的对象

flushInterval刷新间隔

可以被设置为任意的正整数,而且它们代表一个合理的毫秒 形式的时间段。默认情况是不设置,
也就是没有刷新间隔,缓存仅仅调用语句时【增、删、改】刷新。


<select ... flushCache="false" useCache="true"/>
<insert ... flushCache="true"/>
<update ... flushCache="true"/>
<delete ... flushCache="true"/>

size(引用数目)

可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的 可用内存资源数目。默认值是 1024。

readOnly(只读)

可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓 存对象的相同实例。
因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存 会返回缓存对象的拷贝(通过序列化) 。
这会慢一些,但是安全,因此默认是 false。

size引用数目

一个正整数,代表缓存最多可以存储多少对象,不宜设置过大,过大会造成内存溢出。

参照缓存
即引用其他本地缓存,用法如下:

<cache-ref namespace="com.someone.application.data.SomeMapper"/>
namespace为其他mapper文件的namespace

@Cacheable、@CacheEvict、@CachePut使用和区别

@Cacheable可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略,这个稍后会进行说明。需要注意的是当一个支持缓存的方法在对象内部被调用时不会触发缓存功能的。@Cacheable可以指定三个属性,value、key和condition。

  • value属性指定Cache名称

    value属性是必须指定的,其表示当前方法的返回值是会被缓存在哪个Cache上的,对应Cache的名称。其可以是一个Cache也可以是多个Cache,当需要指定多个Cache时其是一个数组。
    
    @Cacheable("cache1")//Cache是发生在cache1上的    
    public User find(Integer id) {    
       returnnull;
    }
    
    
    @Cacheable({"cache1", "cache2"})//Cache是发生在cache1和cache2上的 
    public User find(Integer id) {    
       returnnull;    
    }
    
  • 使用key属性自定义key

    key属性是用来指定Spring缓存方法的返回结果时对应的key的。该属性支持SpringEL表达式。当我们没有指定该属性时,Spring将使用默认策略生成key。我们这里先来看看自定义策略,至于默认策略会在后文单独介绍。
    自定义策略是指我们可以通过Spring的EL表达式来指定我们的key。
    这里的EL表达式可以使用方法参数及它们对应的
    属性。使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。
    下面是几个使用参数作为key的示例。
    
    @Cacheable(value="users", key="#id")
    public User find(Integer id) {
       returnnull;
    }
    
    
    @Cacheable(value="users", key="#p0")
    public User find(Integer id) {
       returnnull;
    }
    
    
    @Cacheable(value="users", key="#user.id")
    
    public User find(User user) {
       returnnull;
    }
    
    
    @Cacheable(value="users", key="#p0.id")
    
    public User find(User user) {
       returnnull;
    }
    

    除了上述使用方法参数作为key之外,Spring还为我们提供了一个root对象可以用来生成key。通过该root对象我们可以获取到以下信息。
    在这里插入图片描述
    当我们要使用root对象的属性作为key时我们也可以将“#root”省略,因为Spring默认使用的就是root对象的属性。如:

     @Cacheable(value={"users", "xxx"}, key="caches[1].name")
        public User find(User user) {
           returnnull;
        }
    
  • condition属性指定发生的条件

    有的时候我们可能并不希望缓存一个方法所有的返回结果。
    通过condition属性可以实现这一功能。condition属性默认为空,表示将缓存所有的调用情形。
    其值是通过SpringEL表达式来指定的,当为true时表示进行缓存处理;
    当为false时表示不进行缓存处理,即每次调用该方法时该方法都会执行一次。
    如下示例表示只有当user的id为偶数时才会进行缓存。
    
     @Cacheable(value={"users"}, key="#user.id", condition="#user.id%2==0")
     public User find(User user) {
       System.out.println("find user by user " + user);
       return user;
    }
    
  • @CachePut

    在支持Spring Cache的环境下,对于使用@Cacheable标注的方法,
    Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,
    如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,
    否则才会执行并将返回结果存入指定的缓存中。@CachePut也可以声明一个方法支持缓存功能。
    与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行
    过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
    @CachePut也可以标注在类上和方法上。使用@CachePut时我们可以指定的属性跟@Cacheable是一样的。
    
     @CachePut("users")//每次都会执行方法,并将结果存入指定的缓存中
      public User find(Integer id) {
       returnnull;
    }
    
  • @CacheEvict

        @CacheEvict是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有
        的方法的执行都会触发缓存的清除操作。@CacheEvict可以指定的属性有value、key、condition、
        allEntries和beforeInvocation。其中value、key和condition的语义与@Cacheable对应的属性类似。
        即value表示清除操作是发生在哪些Cache上的(对应Cache的名称);key表示需要清除的是哪个
        key,如未指定则会使用默认策略生成的key;condition表示清除操作发生的条件。下面我们来介绍
        一下新出现的两个属性allEntries和beforeInvocation。
    
  • allEntries属性

     	allEntries是boolean类型,表示是否需要清除缓存中的所有元素。默认为false,表示不需要。当指定了allEntries为true时,Spring Cache将忽略指定的key。有的时候我们需要Cache一下清除所有的元素,这比一个一个清除元素更有效率。
        @CacheEvict(value="users", allEntries=true)
        public void delete(Integer id) {
           System.out.println("delete user by id: " + id);
        }
    
  • beforeInvocation属性

    清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不
    会触发清除操作。使用beforeInvocation可以改变触发清除操作的时间,当我们指定该属性值为true
    时,Spring会在调用该方法之前清除缓存中的指定元素。
     	@CacheEvict(value="users", beforeInvocation=true)
        public void delete(Integer id) {
           System.out.println("delete user by id: " + id);
        }
    
  • @Caching

    @Caching注解可以让我们在一个方法或者类上同时指定多个Spring Cache相关的注解。其拥有三
    个属性:cacheable、put和evict,分别用于指定@Cacheable、@CachePut和@CacheEvict。
    
    
    
     @Caching(cacheable = @Cacheable("users"), evict = { @CacheEvict("cache2"),
              @CacheEvict(value = "cache3", allEntries = true) })
        public User find(Integer id) {
           returnnull;
        }
    
  • 使用自定义注解

    Spring允许我们在配置可缓存的方法时使用自定义的注解,前提是自定义的注解上必须使用对应的
    注解进行标注。如我们有如下这么一个使用@Cacheable进行标注的自定义注解。
    
     @Target({ElementType.TYPE, ElementType.METHOD})
     @Retention(RetentionPolicy.RUNTIME)
     @Cacheable(value="users")
     public @interface MyCacheable {
     
     }
     
        那么在我们需要缓存的方法上使用@MyCacheable进行标注也可以达到同样的效果。
     
        @MyCacheable
        public User findById(Integer id) {
           System.out.println("find user by id: " + id);
           User user = new User();
           user.setId(id);
           user.setName("Name" + id);
           return user;
        }
    

原文

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

幽·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值