springboot-cache缓存

    本节主要介绍ehcaches使用,缓存在项目开发中使用较多,比如我们项目中使用操作hbase数据存储集群,每天有上亿数据,如果普通的查询,那就没得玩了,一个查询客户要等几分钟,那这个项目就没戏,所以在操作大数据访问时,一个查询上百万、千万、上亿条数据结果时就比较慢,我们使用缓存将第一次查询的结果缓存起来,当再次同样的查询条件时就会从缓存中取出数据,这样给服务器压力就很小,页面响应速度很快,给用户的体验效果也比较好。下面介绍ehcache具体使用:

 
 

创建项目

在pom.xml引入ehcache依赖包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example.springboot</groupId>
    <artifactId>springboot-cache</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>springboot-cache</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.7</java.version>
        <!--mybatis版本-->
        <mybatis-spring.version>1.3.2</mybatis-spring.version>
        <!--mybatis 分页插件版本-->
        <mybatis-pagehelper.version>4.1.0</mybatis-pagehelper.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- mybatis依赖包 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${mybatis-spring.version}</version>
        </dependency>
        <!-- mysql 驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- cache 依赖包 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <!-- ehcache -->
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
在application.properties配置文件配置数据库连接
#服务端口
server.port=8088
#server.context-path=/springboot

#mysql数据连接
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
#spring.datasource.max-active=20
#spring.datasource.max-idle=8
#spring.datasource.min-idle=8
#spring.datasource.initial-size=20

#mybatis 配置
# 配置映射文件加载
mybatis.mapper-locations=classpath*:mapper/*.xml
# 实体类通过别名使用
#mybatis.type-aliases-package=com.example.springboot.mybatis.entity

创建缓存配置

在src/main/resources目录下创建ehcache.xml文件

<?xml version="1.0" encoding="UTF-8"?>

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">

    <!-- 磁盘缓存位置 -->
    <diskStore path="java.io.tmpdir/ehcache" />

    <!-- 默认缓存 -->
    <defaultCache
            maxEntriesLocalHeap="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxEntriesLocalDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </defaultCache>

    <!-- department 缓存 -->
    <cache name="user"
           maxElementsInMemory="1000"
           eternal="false"
           timeToIdleSeconds="60"
           timeToLiveSeconds="60"
           overflowToDisk="false"
           memoryStoreEvictionPolicy="LRU"/>
</ehcache>

创建数据库

-- ----------------------------
-- Table structure for `m_user`
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
  `id` varchar(50) NOT NULL DEFAULT '0',
  `username` varchar(50) DEFAULT NULL,
  `password` varchar(50) DEFAULT NULL,
  `email` varchar(50) DEFAULT NULL,
  `useable` int(11) DEFAULT NULL,
  `addtime` varchar(50) DEFAULT NULL,
  `logintime` varchar(50) DEFAULT NULL,
  `loginip` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of m_user
-- ----------------------------
INSERT INTO `t_user` VALUES ('1', '1111', '1111', '1111', '11', '1111', '111', '111');

编写user实体类

package com.example.springboot.cache.entity;

public class User {
   private String id;

   private String username;

   private String password;

   private String email;

   /**
    * 是否可用(0禁用,1可用)
    */
   private Integer useable;

   /**
    * 创建时间
    */
   private String addtime;

   /**
    * 登陆时间
    */
   private String logintime;

   /**
    * 登陆IP
    */
   private String loginip;

编写dao层类

package com.example.springboot.cache.dao;

import com.example.springboot.cache.entity.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;

/**
 * 基于接口编程,通过mybatis与spring整合注入,在xml中编写sql语句
 */
@Mapper
public interface UserMapper {

   List<User> queryList();

   void save(User user);

   void batchDelete(String[] ids);

   void update(User user);

   User getUserById(String id);
}

编写mapper.xml配置文件

在src/main/resources/mapper/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.example.springboot.cache.dao.UserMapper">

    <select id="queryList" resultType="com.example.springboot.cache.entity.User">
      SELECT u.id, u.username, u.password, u.email, u.useable, u.addtime, u.logintime, u.loginip FROM t_user u
   </select>
   
   <select id="queryById" resultType="com.example.springboot.cache.entity.User">
      SELECT u.id, u.username, u.password, u.email, u.useable, u.addtime, u.logintime, u.loginip FROM t_user u where u.id = #{id}
   </select>
   
   <insert id="save">
      insert into t_user(id,username, password, email, useable, addtime)
      values(#{id},#{username}, #{password}, #{email}, #{useable}, now())
   </insert>
   
   <update id="update">
      update t_user set password = #{password}, email = #{email}, useable = #{useable} where id = #{id}
   </update>
   
   <delete id="batchDelete">
      delete from m_user where id in
      <foreach collection="array" item="item" open="(" separator="," close=")">
         #{item}
      </foreach>
   </delete>
   
   <!-- <delete id="delUsers">
      delete from m_user where id in
      <foreach collection="list" item="item" open="(" separator="," close=")">
         #{item}
      </foreach>
   </delete> -->
</mapper>

编写service类

package com.example.springboot.cache.service;

import com.example.springboot.cache.dao.UserMapper;
import com.example.springboot.cache.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @desc 通过mybatis xml配置文件读取数据
 * @Author wangsh
 * @date 2018/5/6 14:16
 * @return
 */
@Service
public class UserService {

   @Autowired
   private UserMapper userMapper;

   @Cacheable
   public List<User> queryList() {
      List<User> queryList = userMapper.queryList();
      return queryList;
   }

   @Cacheable(key = "#id")
   public User getUserById(String id) {
      return userMapper.getUserById(id);
   }
   @CacheEvict(key = "#ids")
   public void batchDelete(String[] ids) {
      userMapper.batchDelete(ids);
   }

   // REQUIRED:表示必须又事物管理,如果没有事物,就创建一个事物
   @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
   @CachePut(key = "#user.id")
   public void update(User user) {
      userMapper.update(user);
   }

   // REQUIRED:表示必须又事物管理,如果没有事物,就创建一个事物
   @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
   @CachePut(key = "#user.id")
   public void save(User user) {
      userMapper.save(user);
   }
}

创建conroller类

package com.example.springboot.cache.web;

import com.example.springboot.cache.entity.User;
import com.example.springboot.cache.service.UserService;
import com.example.springboot.cache.util.UUIDUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

/**
 * @desc 操作数据库查询示例
 * @Author wangsh
 * @date 2018/5/6 15:01
 * @return
 */
@RestController
@RequestMapping("/user")
public class UserController {

   /**
    * 通过mybatis xml配置文件读取数据
    */
   @Autowired
   private UserService userService;

   @RequestMapping("/getUserById")
   @ResponseBody
   public User getUserById(String id) {
      User User = userService.getUserById(id);
      return User;
   }

   @RequestMapping("/save")
   @ResponseBody
   public User save() {
      User user = new User();
      user.setId(UUIDUtil.getUUID());
      user.setUsername("lisi");
      user.setPassword("lisi");
      userService.save(user);
      return user;
   }

   @RequestMapping("/queryList")
   @ResponseBody
   public List<User> queryList() {
      List<User> queryList = userService.queryList();
      return queryList;
   }
}

创建启动服务类

package com.example.springboot.cache;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

//开启ehcache缓存
@EnableCaching
@SpringBootApplication
public class SpringbootCacheApplication {

   public static void main(String[] args) {
      SpringApplication.run(SpringbootCacheApplication.class, args);
   }
}

缓存注解详解

参考:https://www.cnblogs.com/m4tech/p/6641110.html

@CacheConfig:主要用于配置该类中会用到的一些共用的缓存配置。在这里@CacheConfig(cacheNames = "users"):配置了该数据访问对象中返回的内容将存储于名为users的缓存对象中,我们也可以不使用该注解,直接通过@Cacheable自己配置缓存集的名字来定义。
@Cacheable:配置了findByName函数的返回值将被加入缓存。同时在查询时,会先从缓存中获取,若不存在才再发起对数据库的访问。该注解主要有下面几个参数:
value、cacheNames:两个等同的参数(cacheNames为Spring 4新增,作为value的别名),用于指定缓存存储的集合名。由于Spring 4中新增了@CacheConfig,因此在Spring 3中原本必须有的value属性,也成为非必需项了
key:缓存对象存储在Map集合中的key值,非必需,缺省按照函数的所有参数组合作为key值,若自己配置需使用SpEL表达式,比如:@Cacheable(key = "#p0"):使用函数第一个参数作为缓存的key值,更多关于SpEL表达式的详细内容可参考官方文档
condition:缓存对象的条件,非必需,也需使用SpEL表达式,只有满足表达式条件的内容才会被缓存,比如:@Cacheable(key = "#p0", condition = "#p0.length() < 3"),表示只有当第一个参数的长度小于3的时候才会被缓存,若做此配置上面的AAA用户就不会被缓存,读者可自行实验尝试。
unless:另外一个缓存条件参数,非必需,需使用SpEL表达式。它不同于condition参数的地方在于它的判断时机,该条件是在函数被调用之后才做判断的,所以它可以通过对result进行判断。
keyGenerator:用于指定key生成器,非必需。若需要指定一个自定义的key生成器,我们需要去实现org.springframework.cache.interceptor.KeyGenerator接口,并使用该参数来指定。需要注意的是:该参数与key是互斥的
cacheManager:用于指定使用哪个缓存管理器,非必需。只有当有多个时才需要使用
cacheResolver:用于指定使用那个缓存解析器,非必需。需通过org.springframework.cache.interceptor.CacheResolver接口来实现自己的缓存解析器,并用该参数指定。
除了这里用到的两个注解之外,还有下面几个核心注解:
@CachePut:配置于函数上,能够根据参数定义条件来进行缓存,它与@Cacheable不同的是,它每次都会真是调用函数,所以主要用于数据新增和修改操作上。它的参数与@Cacheable类似,具体功能可参考上面对@Cacheable参数的解析
@CacheEvict:配置于函数上,通常用在删除方法上,用来从缓存中移除相应数据。除了同@Cacheable一样的参数之外,它还有下面两个参数:
allEntries:非必需,默认为false。当为true时,会移除所有数据
beforeInvocation:非必需,默认为false,会在调用方法之后移除数据。当为true时,会在调用方法之前移除数据。


启动服务错误

Exception in thread "main" java.lang.UnsupportedClassVersionError: org/springframework/boot/SpringApplication : Unsupported major.minor version 52.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
at com.example.springboot.cache.SpringbootCacheApplication.main(SpringbootCacheApplication.java:11)

Process finished with exit code 1

解决办法:修改jdk版本



我的是jdk1.8编译的,所以启动是将jdk修改为同样版本即可。


启动服务测试


查询测试:http://localhost:8088//user/queryList




猜你喜欢

转载自blog.csdn.net/seashouwang/article/details/80214297