前言:
本次是在mybatis与spring集成的基础上,加上二级缓存。
二级缓存分为两种,ehcache,redis。
mybatis的ehcache缓存可以参考一下hibernate之二级缓存
OK,本章会把两种缓存方式都给讲一遍,
ehcache缓存机制
ehcache的介绍
Ehcache 是现在最流行的纯Java开源缓存框架。
为什么要用?
配置简单
结构清晰
功能强大
它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序
特点:
够快
Ehcache的发行有一段时长了,经过几年的努力和不计其数的性能测试,Ehcache终被设计于large, high concurrency systems.
够简单
开发者提供的接口非常简单明了,从Ehcache的搭建到运用运行仅仅需要的是你宝贵的几分钟。其实很多开发者都不知道自己用在用Ehcache,Ehcache被广泛的运用于其他的开源项目
够袖珍
关于这点的特性,官方给了一个很可爱的名字small foot print ,一般Ehcache的发布版本不会到2M,V 2.2.3 才 668KB。
够轻量
核心程序仅仅依赖slf4j这一个包,没有之一!
好扩展
Ehcache提供了对大数据的内存和硬盘的存储,最近版本允许多实例、保存对象高灵活性、提供LRU、LFU、FIFO淘汰算法,基础属性支持热配置、支持的插件多
监听器
缓存管理器监听器 (CacheManagerListener)和 缓存监听器(CacheEvenListener),做一些统计或数据一致性广播挺好用的
分布式缓存
从Ehcache 1.2开始,支持高性能的分布式缓存,兼具灵活性和扩展性
先把相关的依赖包给导入,当然为了大家方便我是直接放好了pom.xml的
当然如果要理解是多了那些文件的话,那就可以看一看“其他”依赖包下面
1.增加pom.xml所需依赖包
4.0.0
com.thf
ssm
1.0-SNAPSHOT
war
ssm Maven Webapp
http://www.example.com
UTF-8
1.8
1.8
3.7.0
5.0.2.RELEASE
3.4.5
5.1.44
5.1.2
1.3.1
2.1.1
2.4.3
2.9.1
3.2.0
1.7.13
4.12
4.0.0
1.18.2
2.9.0
1.7.1.RELEASE
2.9.3
org.springframework
spring-context
${spring.version}
org.springframework
spring-orm
${spring.version}
org.springframework
spring-tx
${spring.version}
org.springframework
spring-aspects
${spring.version}
org.springframework
spring-web
${spring.version}
org.springframework
spring-test
${spring.version}
org.mybatis
mybatis
${mybatis.version}
mysql
mysql-connector-java
${mysql.version}
com.github.pagehelper
pagehelper
${pagehelper.version}
org.mybatis
mybatis-spring
${mybatis.spring.version}
org.apache.commons
commons-dbcp2
${commons.dbcp2.version}
org.apache.commons
commons-pool2
${commons.pool2.version}
org.slf4j
slf4j-api
${slf4j.version}
org.slf4j
jcl-over-slf4j
${slf4j.version}
runtime
org.apache.logging.log4j
log4j-api
${log4j2.version}
org.apache.logging.log4j
log4j-core
${log4j2.version}
org.apache.logging.log4j
log4j-slf4j-impl
${log4j2.version}
org.apache.logging.log4j
log4j-web
${log4j2.version}
runtime
com.lmax
disruptor
${log4j2.disruptor.version}
junit
junit
${junit.version}
test
javax.servlet
javax.servlet-api
${servlet.version}
provided
org.projectlombok
lombok
${lombok.version}
provided
org.springframework
spring-context-support
${spring.version}
org.mybatis.caches
mybatis-ehcache
1.1.0
net.sf.ehcache
ehcache
2.10.0
redis.clients
jedis
${redis.version}
org.springframework.data
spring-data-redis
${redis.spring.version}
com.fasterxml.jackson.core
jackson-databind
${jackson.version}
com.fasterxml.jackson.core
jackson-core
${jackson.version}
com.fasterxml.jackson.core
jackson-annotations
${jackson.version}
ssm
src/main/java
**/*.xml
src/main/resources
*.properties
*.xml
org.apache.maven.plugins
maven-compiler-plugin
${maven.compiler.plugin.version}
${maven.compiler.target}
${project.build.sourceEncoding}
org.mybatis.generator
mybatis-generator-maven-plugin
1.3.2
mysql
mysql-connector-java
${mysql.version}
true
2.增加ehcache.xml文件
直接创好xml文件,然后考入就行,不用修改
3.修改applicationContext.mybatis.xml文件
true
false
true
helperDialect=mysql
然后我们是与mybatis整合的,所以在applicationContext-mybatis.xml中加入ehcache的配置
这是具体需要加入的配置
true
false
true
4.为需要缓存的映射文件加入cache
然后我们的Mapper映射的xml中开启二级缓存,这里是BookMapper.xml
加在mapper标签下面第一个即可
然后我们还能改变useCache的值来开启和关闭缓存
开始测试
然后我们一样用JUnit测试一个方法查询同一个数据,开启了后通过日志看到第二次没有执行sql语句了,而是进入缓存取的值
package com.thf.service;
import com.thf.SpringBaseTest;
import com.thf.model.Book;
import com.thf.util.StringUtils;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.*;
/**
* @author tanhaifang
* @site www.thf.com
* @company
* @create 2019-10-18 5:00
*/
public class BookServiceImplTest extends SpringBaseTest {
@Autowired
private BookService bookService;
/*测是单个数据是否有缓存*/
@Test
public void testCacheOne() {
System.out.println(this.bookService.selectByPrimaryKey(2));
System.out.println(this.bookService.selectByPrimaryKey(2));
}
/*测试查多个*/
@Test
public void testCacheMany() {
Map map = new HashMap();
map.put("bname", StringUtils.toLikeStr("圣墟"));
pageBean.setPage(3);
List
Redis和ehcache大致不同:
ehcache直接在jvm虚拟机中缓存,速度快,效率高;但是缓存共享麻烦,集群分布式应用不方便。
redis是通过socket访问到缓存服务,效率比ecache低,比数据库要快很多,处理集群和分布式缓存方便,有成熟的方案。
所以在数据量比较大的时候显然redis比较吃香
redis常用类
1.1 Jedis
jedis就是集成了redis的一些命令操作,封装了redis的java客户端
1.2 JedisPoolConfig
Redis连接池
1.3 ShardedJedis
基于一致性哈希算法实现的分布式Redis集群客户端
redis的搭建
1.所需pom.xml的依赖包的前面已经导入
2.然后导入我们的applicationContext-redis.xml文件,因为我们需要在文件中引入我们redis.properties文件又要引入jdbc.properties文件,还有我们桥接redis的工具类
所以需要在我们的applicationContext.xml中添加引入两个或多个属性文件的写法
3.导入必要的资源文件(需改内容)
applicationContext-redis.xml:
redis.properties
因为redis是NoSql(非关系型数据库),所以需要我们的连接文件,然后把redis.properties导入
redis.hostName=192.168.25.130
redis.port=6379
redis.password=123456
redis.timeout=10000
redis.maxIdle=300
redis.maxTotal=1000
redis.maxWaitMillis=1000
redis.minEvictableIdleTimeMillis=300000
redis.numTestsPerEvictionRun=1024
redis.timeBetweenEvictionRunsMillis=30000
redis.testOnBorrow=true
redis.testWhileIdle=true
3.第三方的CacheUtil
RidesCache.java
package com.thf.util;
import org.apache.ibatis.cache.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class RedisCache implements Cache //实现类
{
private static final Logger logger = LoggerFactory.getLogger(RedisCache.class);
private static RedisTemplate redisTemplate;
private final String id;
/**
* The {@code ReadWriteLock}.
*/
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
@Override
public ReadWriteLock getReadWriteLock()
{
return this.readWriteLock;
}
public static void setRedisTemplate(RedisTemplate redisTemplate) {
RedisCache.redisTemplate = redisTemplate;
}
public RedisCache(final String id) {
if (id == null) {
throw new IllegalArgumentException("Cache instances require an ID");
}
logger.debug("MybatisRedisCache:id=" + id);
this.id = id;
}
@Override
public String getId() {
return this.id;
}
@Override
public void putObject(Object key, Object value) {
try{
logger.info(">>>>>>>>>>>>>>>>>>>>>>>>putObject: key="+key+",value="+value);
if(null!=value)
redisTemplate.opsForValue().set(key.toString(),value,60, TimeUnit.SECONDS);
}catch (Exception e){
e.printStackTrace();
logger.error("redis保存数据异常!");
}
}
@Override
public Object getObject(Object key) {
try{
logger.info(">>>>>>>>>>>>>>>>>>>>>>>>getObject: key="+key);
if(null!=key)
return redisTemplate.opsForValue().get(key.toString());
}catch (Exception e){
e.printStackTrace();
logger.error("redis获取数据异常!");
}
return null;
}
@Override
public Object removeObject(Object key) {
try{
if(null!=key)
return redisTemplate.expire(key.toString(),1,TimeUnit.DAYS);
}catch (Exception e){
e.printStackTrace();
logger.error("redis获取数据异常!");
}
return null;
}
@Override
public void clear() {
Long size=redisTemplate.execute(new RedisCallback() {
@Override
public Long doInRedis(RedisConnection redisConnection) throws DataAccessException {
Long size = redisConnection.dbSize();
//连接清除数据
redisConnection.flushDb();
redisConnection.flushAll();
return size;
}
});
logger.info(">>>>>>>>>>>>>>>>>>>>>>>>clear: 清除了" + size + "个对象");
}
@Override
public int getSize() {
Long size = redisTemplate.execute(new RedisCallback() {
@Override
public Long doInRedis(RedisConnection connection)
throws DataAccessException {
return connection.dbSize();
}
});
return size.intValue();
}
}
RedisCacheTransfer.java
package com.thf.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
public class RedisCacheTransfer {
@Autowired
public void setRedisTemplate(RedisTemplate redisTemplate) {
RedisCache.setRedisTemplate(redisTemplate);
}
}
4.配置相关的映射文件
package com.thf.service;
import com.thf.SpringBaseTest;
import com.thf.model.Book;
import com.thf.util.StringUtils;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.*;
/**
* @author tanhaifang
* @site www.thf.com
* @company
* @create 2019-10-18 5:00
*/
public class BookServiceImplTest extends SpringBaseTest {
@Autowired
private BookService bookService;
/*测是单个数据是否有缓存*/
@Test
public void testCacheOne() {
System.out.println(this.bookService.selectByPrimaryKey(2));
System.out.println(this.bookService.selectByPrimaryKey(2));
}
/*测试查多个*/
@Test
public void testCacheMany() {
Map map = new HashMap();
map.put("bname", StringUtils.toLikeStr("圣墟"));
pageBean.setPage(3);
List aaaa = this.bookService.listPager(map, pageBean);
for (Map m : aaaa) {
System.out.println(m);
}
List aaaa1 = this.bookService.listPager(map, pageBean);
for (Map m : aaaa1) {
System.out.println(m);
}
}
}
OK!!