<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.learn</groupId>
<artifactId>springboot-ehcache</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.12.RELEASE</version>
</parent>
<dependencies>
<!-- SpringBoot 对lombok 支持 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- SpringBoot web 核心组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<!-- SpringBoot 外部tomcat支持 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!-- springboot-log4j -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
<version>1.3.8.RELEASE</version>
</dependency>
<!-- springboot-aop 技术 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-lang/commons-lang -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</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>
<version>2.9.1</version><!--$NO-MVN-MAN-VER$ -->
</dependency>
<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>
</dependencies>
</project>
<?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-rmi-5000" />
<!-- 多台机器配置 -->
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,rmiUrls=//127.0.0.1:4000/userCache">
</cacheManagerPeerProviderFactory>
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=127.0.0.1,port=5000,socketTimeoutMillis=120000" />
<!-- 多播方式配置 搜索某个网段上的缓存 timeToLive 0是限制在同一个服务器 1是限制在同一个子网 32是限制在同一个网站 64是限制在同一个region
128是限制在同一个大洲 255是不限制 <cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=224.1.1.1, multicastGroupPort=40000,
timeToLive=32" /> -->
<!-- 默认缓存 -->
<defaultCache maxElementsInMemory="1000" eternal="true"
timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
diskPersistent="true" diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
<!-- demo缓存 -->
<cache name="userCache" maxElementsInMemory="1000" eternal="false"
timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
diskPersistent="false" diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
<!-- 用于在初始化缓存,以及自动设置 -->
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />
</cache>
</ehcache>
###端口号配置
server:
port: 8080
###数据库配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
test-while-idle: true
test-on-borrow: true
validation-query: SELECT 1 FROM DUAL
time-between-eviction-runs-millis: 300000
min-evictable-idle-time-millis: 1800000
# 缓存配置读取
cache:
type: ehcache
ehcache:
config: classpath:app2_ehcache.xml
package com.learn.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import com.learn.entity.Users;
// @CacheConfig配置缓存基本信息cacheNames缓存名称
@CacheConfig(cacheNames = "userCache")
public interface UserMapper {
@Select("SELECT id ,name,age FROM users where id=#{id}")
@Cacheable // 该方法查询数据库完毕之后,存到缓存
List<Users> getUser(@Param("id") Long id);
}
package com.learn.entity;
public class Users {
private Long id;
private String name;
private Integer age;
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @param id
* the id to set
*/
public void setId(Long id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name
* the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the age
*/
public Integer getAge() {
return age;
}
/**
* @param age
* the age to set
*/
public void setAge(Integer age) {
this.age = age;
}
}
package com.learn.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.learn.entity.Users;
import com.learn.mapper.UserMapper;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public List<Users> getUser(Long id) {
return userMapper.getUser(id);
}
}
package com.learn.api.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.learn.entity.Users;
import com.learn.service.UserService;
@RestController
public class IndexControoller {
@Autowired
private UserService userService;
@Autowired
private CacheManager cacheManager;
@RequestMapping("/remoKey")
public void remoKey() {
cacheManager.getCache("userCache").clear();
}
@RequestMapping("/getUser")
public List<Users> getUser(Long id) {
return userService.getUser(id);
}
}
package com.learn;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@MapperScan(basePackages = { "com.learn.mapper" })
@EnableCaching // @EnableCaching 开启缓存
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
@EnableCaching 开启ehcache缓存模式
@Cacheable 加了该注解的方法表示可以缓存
@CacheConfig 表示创建缓存配置,Key为userCache
1、diskStore :指定数据(.data and .index)存储位置,可指定磁盘中的文件夹位置期 The diskStore element is optional. It must be configured if you have overflowToDisk or diskPersistent enabled for any cache. If it is not configured, a warning will be issues and java.io.tmpdir will be used.
2、defaultCache : 默认的管理策略
Ehcache 使用Map集合实现的 element 其实就是 key 和value
一、以下属性是必须的:
1、name: Cache的名称,必须是唯一的(ehcache会把这个cache放到HashMap里)。
2、maxElementsInMemory:在内存中缓存的element的最大数目。
3、maxElementsOnDisk:在磁盘上缓存的element的最大数目,默认值为0,表示不限制。
4、eternal:设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断。
5、overflowToDisk: 如果内存中数据超过内存限制,是否要缓存到磁盘上。
二、以下属性是可选的:
1、timeToIdleSeconds: 对象空闲时间,指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直可以访问。
2、timeToLiveSeconds: 对象存活时间,指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值0,表示一直可以访问。
3、diskPersistent: 是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false。
4、diskExpiryThreadIntervalSeconds: 对象检测线程运行时间间隔。标识对象状态的线程多长时间运行一次。
5、diskSpoolBufferSizeMB: DiskStore使用的磁盘大小,默认值30MB。每个cache使用各自的DiskStore。
6、memoryStoreEvictionPolicy: 如果内存中数据超过内存限制,向磁盘缓存时的策略。默认值LRU,可选FIFO、LFU。
由于 EhCache 是进程中的缓存系统,一旦将应用部署在集群环境中,每一个节点维护各自的缓存数据,当某个节点对缓存数据进行更新,这些更新的数据无法在其它节点中共享,这不仅会降低节点运行的效率,而且会导致数据不同步的情况发生。例如某个网站采用 A、B 两个节点作为集群部署,当 A 节点的缓存更新后,而 B 节点缓存尚未更新就可能出现用户在浏览页面的时候,一会是更新后的数据,一会是尚未更新的数据,尽管我们也可以通过 Session Sticky 技术来将用户锁定在某个节点上,但对于一些交互性比较强或者是非 Web 方式的系统来说,Session Sticky 显然不太适合。
EhCache从1.7版本开始,支持五种集群方案,分别是:
Terracotta、RMI、JMS、JGroups、EhCache Server
你如何知道集群环境中的其他缓存?
• 分布式传送的消息是什么形式?
• 什么情况需要进行复制?增加(Puts),更新(Updates)或是失效(Expiries)?
• 采用什么方式进行复制?同步还是异步方式?
1、正确的元素类型:只有可序列化的元素可以进行复制。一些操作,比如移除,只需要元素的键值而不用整个元素;在这样的操作中即使元素不是可序列化的但键值是可序列化的也可以被复制。
2、成员发现(Peer Discovery):Ehcache进行集群的时候有一个cache组的概念。每个cache都是其他cache的一个peer,没有主cache的存在。成员发现(Peer Discovery)正是用来解决 “你如何知道集群环境中的其他缓存?” 这个问题的。Ehcache提供了两种机制用来进行成员发现,即:自动成员发现和手动成员发现。要使用一个内置的成员发现机制要在ehcache的配置文件中指定cacheManagerPeerProviderFactory元素的class属性为
net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory。
使用纯java的ehcache作为本地缓存
Reids 作为远程分布式缓存
解决redis缓存压力过大,提高缓存速度,以及缓存性能。
create table `users` (
`id` int,
`name` varchar(64),
`age` int
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
localhost:8080/getUser?id=1
[
{
id: 1,
name: "zs",
age: 18
}
]