SpringBoot整合ehcache和redis实现二级缓存

简要说明:ehcache是内存缓存,在本地jvm内存中,十分高效,但是如果缓存数据都存在jvm中,内存是不够用的,于是使用到了redis数据库缓存,redis是键值对数据库,也比较高效,如果仅用redis做缓存,则存在频繁的网络IO读写,因为一般的会将redis部署在一个单独的服务器上,或者是集群部署。所以我们结合两者的特性,优先使用ehcache缓存,当ehcache中没有数据时,再向redis中取,redis中取到数据后,并把数据再次存到ehcache缓存中。总体的设计就是讲ehcache的失效时间设置比较短,将redis缓存失效时间设置的比较长,这样就可以充分发挥两者的特性了。

废话不说上代码:

1.redis 集群配置

@Configuration
@PropertySource(value = "classpath:/redis.properties")
@EnableCaching
@Primary
public class RedisConfig {
	
	//正则表达式
	private Pattern p = Pattern.compile("^.+[:]\\d{1,5}\\s*$");
	
	//配置jedisPool,访问redis服务客户端用的是jedis
	@Bean(name = "jedisPoolConfig") 
	@Primary
	public JedisPoolConfig poolCofig(@Value(value = "${redis.pool.max-idle}") int maxIdle,
			@Value(value = "${redis.pool.max-total}") int maxTotal,
			@Value(value = "${redis.pool.max-waitMillis}") long maxWaitMillis,
			@Value(value = "${redis.pool.testOnBorrow}") boolean testOnBorrow) {

		JedisPoolConfig poolCofig = new JedisPoolConfig();
		poolCofig.setMaxIdle(maxIdle);//最大空闲连接数
		poolCofig.setMaxTotal(maxTotal);//最大连接数
		poolCofig.setMaxWaitMillis(maxWaitMillis);//最大等待时间毫秒
		poolCofig.setTestOnBorrow(testOnBorrow);//是否创建instance
		return poolCofig;
	}
	
	//RedisClusterConfiguration  是在spring-data-redis包下
	@Bean(name = "redisClusterConfiguration")
	@Primary
	public RedisClusterConfiguration redisClusterConfiguration(@Value(value = "${redis.addressConfig}") String addressConfig,
			@Value(value = "${redis.maxRedirects}") int maxRedirects){
		List<RedisNode> redislist = new ArrayList<RedisNode>();
		String[] ipList = addressConfig.split(",");
		for(String ip : ipList){
			 boolean isIpPort = p.matcher(ip).matches();
             if (!isIpPort) {
                 throw new IllegalArgumentException("ip 或 port 不合法");
             }
             String[] ipAndPort = ip.split(":");
             RedisNode redisNode = new RedisNode(ipAndPort[0],StringUtil.stringToInteger(ipAndPort[1]));
             redislist.add(redisNode);
		}
		RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
		redisClusterConfiguration.setMaxRedirects(maxRedirects);
		redisClusterConfiguration.setClusterNodes(redislist);
		return redisClusterConfiguration;
	}
	

	//将jedisPool和redisClusterConfiguration注入到jedisConnectionFactory
	@Bean(name = "jedisConnectionFactory")
	@Primary
	public JedisConnectionFactory jedisConnectionFactory(@Qualifier("redisClusterConfiguration") RedisClusterConfiguration clusterConfig,
			@Qualifier("jedisPoolConfig") JedisPoolConfig poolConfig) {

		JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(clusterConfig);
		jedisConnectionFactory.setPoolConfig(poolConfig);
		return jedisConnectionFactory;
	}
	
	
	@Bean(name = "redisTemplate")
	@Primary
	public RedisTemplate<String, String> redisTemplate(
			@Qualifier("jedisConnectionFactory") RedisConnectionFactory factory) {
		//指定redis模板
		StringRedisTemplate template = new StringRedisTemplate(factory);
		Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
		ObjectMapper om = new ObjectMapper();
		om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
		jackson2JsonRedisSerializer.setObjectMapper(om);
		template.setValueSerializer(jackson2JsonRedisSerializer);
		template.setKeySerializer(jackson2JsonRedisSerializer);
		template.afterPropertiesSet();
		return template;
	}
	
	//生成缓存的管理类
	@Bean(name = "redisCacheManager")
	@Primary
	public CacheManager cacheManager(@Qualifier("redisTemplate") RedisTemplate redisTemplate) {
		RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
		// 设置缓存过期时间
		//rcm.setDefaultExpiration(60);//秒
		return rcm;
	}

	@Bean
	public KeyGenerator keyGenerator() {
		return new KeyGenerator() {
			public Object generate(Object target, Method method, Object... params) {
				StringBuilder sb = new StringBuilder();
				sb.append(target.getClass().getName());
				sb.append(method.getName());
				for (Object obj : params) {
					sb.append(obj.toString());
				}
				return sb.toString();
			}
		};
	}
	

其中redis.properties的内容,其中的注释是对上一行的配置说明,至于redis如何集群部署,请参考连接

redis.addressConfig=127.0.01:6380,127.0.01:6381,127.0.01:6382
redis.maxRedirects=6
#redis.timeout=3000
redis.pool.max-idle=100  
#最大空闲连接数
redis.pool.max-total=2000 
#最大连接数
redis.pool.max-waitMillis=-1  
#没有限制
redis.pool.testOnBorrow=true 
#建立instance

2.ehcache配置,为ehcache2.xml,下文中会使用到

<ehcache updateCheck="false">

    <!-- Sets the path to the directory where cache .data files are created.
        If the path is a Java System Property it is replaced by its value in the
        running VM. The following properties are translated: user.home - User's home
        directory user.dir - User's current working directory java.io.tmpdir - Default
        temp file path -->
    <diskStore path="java.io.tmpdir"/>


    <!--Default Cache configuration. These will applied to caches programmatically
        created through the CacheManager. The following attributes are required:
        maxElementsInMemory - Sets the maximum number of objects that will be created
        in memory eternal - Sets whether elements are eternal. If eternal, timeouts
        are ignored and the element is never expired. overflowToDisk - Sets whether
        elements can overflow to disk when the in-memory cache has reached the maxInMemory
        limit. The following attributes are optional: timeToIdleSeconds - Sets the
        time to idle for an element before it expires. i.e. The maximum amount of
        time between accesses before an element expires Is only used if the element
        is not eternal. Optional attribute. A value of 0 means that an Element can
        idle for infinity. The default value is 0. timeToLiveSeconds - Sets the time
        to live for an element before it expires. i.e. The maximum time between creation
        time and when an element expires. Is only used if the element is not eternal.
        Optional attribute. A value of 0 means that and Element can live for infinity.
        The default value is 0. diskPersistent - Whether the disk store persists
        between restarts of the Virtual Machine. The default value is false. diskExpiryThreadIntervalSeconds-
        The number of seconds between runs of the disk expiry thread. The default
        value is 120 seconds. -->

    <defaultCache maxElementsInMemory="100000" eternal="false"
                  overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120"
                  diskPersistent="false" diskExpiryThreadIntervalSeconds="120"
                  memoryStoreEvictionPolicy="LFU"/>
    <cache name="L3_EHCAHCE" maxElementsInMemory="100000" eternal="false"
           overflowToDisk="false" timeToIdleSeconds="0" timeToLiveSeconds="259200">
    </cache>
    <cache name="HealthRedis" maxElementsInMemory="20" eternal="false"
           overflowToDisk="false" timeToIdleSeconds="0" timeToLiveSeconds="1200" />
           
	<cache name="cacheTest" maxElementsInMemory="200" eternal="false"
		overflowToDisk="false" timeToIdleSeconds="10" timeToLiveSeconds="20"
		memoryStoreEvictionPolicy="LFU" />
	<cache name="cacheTest2" maxElementsInMemory="200" eternal="false"
		overflowToDisk="false" timeToIdleSeconds="10" timeToLiveSeconds="20"
		memoryStoreEvictionPolicy="LFU" />
</ehcache>

3,整合redis和ehcache

spring 中关于cache的注解主要为@CacheAble,@CachePut,@CacheEvit这三个注解,依次为放入,刷新,失效缓存,而核心的两个接口是CacheManager与Cache,这里实现cache接口,也是整合的核心实现类


package songhq.com.cache.ehcacherediscache;

import java.util.concurrent.Callable;
import net.sf.ehcache.Element;
import org.springframework.cache.Cache;
import org.springframework.cache.ehcache.EhCacheCache;
import org.springframework.data.redis.cache.RedisCache;

public class ACacheCore
    implements Cache
{

    public ACacheCore()
    {
        name = "L2";
    }

    public String getName()
    {
        return name;
    }

    public Object getNativeCache()
    {
        return null;
    }

    public org.springframework.cache.Cache.ValueWrapper get(Object key)
    {
        org.springframework.cache.Cache.ValueWrapper value = ehCacheCache.get(key);
        if(value != null)
            return value;
        if(checkA())
        {
            value = redisCacheA.get(key);
            if(null != value)
                ehCacheCache.put(key, value.get());
        }
        return value;
    }

    public Object get(Object key, Class type)
    {
        Object value = null;
        try
        {
            value = ehCacheCache.get(key, type);
        }
        catch(IllegalStateException e)
        {
            ehCacheCache.evict(key);
        }
        if(value != null)
            return value;
        if(checkA())
            try
            {
                value = redisCacheA.get(key, type);
                if(value != null)
                    ehCacheCache.put(key, value);
                return value;
            }
            catch(Exception e)
            {
                return null;
            }
        else
            return null;
    }

    public Object get(Object key, Callable valueLoader)
    {
        org.springframework.cache.Cache.ValueWrapper valueWrapper = ehCacheCache.get(key);
        Element element = (Element)valueWrapper.get();
        if(element != null)
            return element.getObjectValue();
        if(checkA())
        {
            try
            {
                Object value = redisCacheA.get(key, valueLoader);
                if(value != null)
                    ehCacheCache.get(key, valueLoader);
                return value;
            }
            catch(Exception e)
            {
                return null;
            }
        } else
        {
            Object value = ehCacheCache.get(key, valueLoader);
            return value;
        }
    }

    public void put(Object key, Object value)
    {
        ehCacheCache.put(key, value);
        if(checkA())
            try
            {
                redisCacheA.put(key, value);
            }
            catch(Exception exception) { }
    }

    public org.springframework.cache.Cache.ValueWrapper putIfAbsent(Object key, Object value)
    {
        org.springframework.cache.Cache.ValueWrapper valueWra = ehCacheCache.putIfAbsent(key, value);
        if(checkA())
            redisCacheA.putIfAbsent(key, value);
        return valueWra;
    }

    public void evict(Object key)
    {
        ehCacheCache.evict(key);
        if(checkA())
            try
            {
                redisCacheA.evict(key);
            }
            catch(Exception exception) { }
    }

    public void clear()
    {
        ehCacheCache.clear();
        if(checkA())
            try
            {
                redisCacheA.clear();
            }
            catch(Exception exception) { }
    }

    public boolean checkA()
    {
        return enabledA && isAlive("HealthRedis_aliveA");
    }

    private boolean isAlive(String key)
    {
        org.springframework.cache.Cache.ValueWrapper alive = healthCache.get(key);
        if(null != alive)
        {
            return false;
        } else
        {
            return true;
        }
    }

    public EhCacheCache getEhCacheCache()
    {
        return ehCacheCache;
    }

    public void setEhCacheCache(EhCacheCache ehCacheCache)
    {
        this.ehCacheCache = ehCacheCache;
    }

    public RedisCache getRedisCacheA()
    {
        return redisCacheA;
    }

    public void setRedisCacheA(RedisCache redisCacheA)
    {
        this.redisCacheA = redisCacheA;
    }

    public EhCacheCache getHealthCache()
    {
        return healthCache;
    }

    public void setHealthCache(EhCacheCache healthCache)
    {
        this.healthCache = healthCache;
    }

    public boolean isEnabledA()
    {
        return enabledA;
    }

    public void setEnabledA(boolean enabledA)
    {
        this.enabledA = enabledA;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    private String name;
    private EhCacheCache ehCacheCache;
    private RedisCache redisCacheA;
    private EhCacheCache healthCache;
    private boolean enabledA;
    
    
}

接着我们使用CacheManager的一个实现类SimpleCacheManager来实现管理我们上一步整合的cache

package songhq.com.cache.ehcacherediscache;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.ehcache.EhCacheCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;

@Component
public class EhcacheRedisCacheManager {
	
	
	
	@Autowired
	private RedisFactory redisFactory;
	
	
	
	public SimpleCacheManager getSimpleCacheManager(String ehcacheName, long longValue) {
		
		SimpleCacheManager ehRedisCacheManager = new SimpleCacheManager();
		//List<EhredisCache> caches = new ArrayList<EhredisCache>();
		
		List<ACacheCore> aCaches = new ArrayList<ACacheCore>();
		ACacheCore aCacheCore = new ACacheCore();
		//EhredisCache ehredisCache = new EhredisCache();
		RedisTemplate<String, String> redisTemplate = redisFactory.getRedisTemplate();
		RedisCache redisCacheA = new RedisCache("AB@", "AB@".getBytes(), redisTemplate, longValue);
		//ehredisCache.setRedisCacheA(redisCacheA);
		aCacheCore.setRedisCacheA(redisCacheA);
		//将Ehcache原生的cache管理者转换一下
		CacheManager cacheManager = CacheManager.create(this.getClass().getClassLoader().getResource("ehcacheRedisCache/ehcache2.xml"));
		Cache ehcache = cacheManager.getCache(ehcacheName);
		Cache healCache = cacheManager.getCache("HealthRedis");
		EhCacheCache ehCacheCache = new EhCacheCache(ehcache);
		EhCacheCache ehhealthCache = new EhCacheCache(healCache);
		
		aCacheCore.setEnabledA(true);
		aCacheCore.setHealthCache(ehhealthCache);
		aCacheCore.setEhCacheCache(ehCacheCache);
		aCacheCore.setName(ehcacheName);
		aCaches.add(aCacheCore);
		//ehredisCache.setEhCacheCache(ehCacheCache);
		//caches.add(ehredisCache);
		//ehRedisCacheManager.setCaches(caches);
		ehRedisCacheManager.setCaches(aCaches);
		return ehRedisCacheManager;
	}

}
package songhq.com.cache.ehcacherediscache;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

/**
 * 实例化出EhcacheReids的缓存Manager
 * @author Administrator
 *
 */

@Configuration
@PropertySource(value = { "classpath:/ehcacheRedisCache/ehredis.properties"})
@EnableCaching
public class CacheBeanManager {
	
	
	
	
	@Autowired
	private EhcacheRedisCacheManager ehcacheRedisCacheManager;
	

	@Bean("testManager")
	public SimpleCacheManager getSimpleCacheManager(@Value("${test.ehcache.name}")String ehcacheName, @Value("${test.redis.expiration}")Long expiration){ 
		
		return ehcacheRedisCacheManager.getSimpleCacheManager(ehcacheName, expiration);
	}
	

}

这里我们使用到了新的配置文件,ehredis.properties,也是根据这个配置文件,我们可以实例化出多个SimpleCacheManager 

test.ehcache.name=cacheTest
test.redis.expiration=60  

这里的60指的是redis中TTL为60秒,关于ehcache的失效时间在ehcache2.xml中有配置

还贴一下获取redisTemplate的类吧

package songhq.com.cache.ehcacherediscache;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

@Component
public class RedisFactory {
	
	@Autowired
	private  RedisTemplate<String, String> redisTemplate;
	
	
	
    public void setRedisTemplate(RedisTemplate<String, String> redisTemplate) {
		this.redisTemplate = redisTemplate;
	}

	public RedisTemplate<String, String> getRedisTemplate()
    {
        return this.redisTemplate;
    }

}

至此,关于配置我们全部完成了。

应用和测试

写一个controller

package songhq.com.cache.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import songhq.com.cache.service.EhredisService;
import songhq.com.cache.vo.MiguSession;

/**
 * 测试组合缓存
 * @author Administrator
 *
 */
@RestController
@RequestMapping("/ehredis")
public class EhredisController {
	
	@Autowired
	private EhredisService ehredisService;
	
	@RequestMapping("/getSession")
	public MiguSession getMiguSession(){
		
		return ehredisService.getSession("user001", "token001");
	
	
	}
}

相应的service

package songhq.com.cache.service;

import java.util.Date;

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import songhq.com.cache.vo.MiguSession;

@Service
public class EhredisService {

	
	
	@Cacheable( value="cacheTest",cacheManager="testManager", key="'ehredis_migusession_'+#userId+'_'+#userToken")
	public MiguSession getSession(String userId, String userToken) {
		
		MiguSession miguSession = new MiguSession();
		miguSession.setDate(new Date());
		miguSession.setSessionId(userId+userToken);
		miguSession.setUserId(userId);
		miguSession.setUserToken(userToken);
		return miguSession;
	
	}

}

这里我们为了检查是不是从缓存中获取的值,我们使用了setDate(new Date());如果是从缓存中获取的,则date值不变

启动项目,执行main方法

package songhq.com.cache;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CacheApplication {
	
	
	public static void main(String[] args) {
		SpringApplication.run(CacheApplication.class, args);
	}

	
}

使用Chrome插件Advanced Rest Client插件发送请求,结果如下

再次访问,发现date不变,即使用到了缓存

利用Redis Desktop Manager工具访问redis ,使用flushAll清楚所有的数据

再次访问http://127.0.0.1:9044/ehredis/getSession ,结果如下

由于是集群部署,在三个redis只会有一个存入数据,另一个备份,有负载均衡的的作用,至于到底会存到那个redis中,一般的是轮询的方式,本博客不做详细说明,有兴趣的可以参见

觉得本文有帮助的请点个赞,对了把pom.xml也贴出来吧,

<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>songhq.com.cache</groupId>
	<artifactId>cache</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>cache</name>
	<description>常见的缓存的demo</description>
	<parent>
		<!--SpringBoot相关的组件版本都受控制 -->
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.9.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<!-- springCloud对应的版本 -->
		<spring-cloud.version>Edgware.SR1</spring-cloud.version>
	</properties>

	<dependencies>

	<dependency>
		   	<groupId>org.bouncycastle</groupId>
		   	<artifactId>bcprov-jdk15on</artifactId>
		   	<version>1.47</version>
	  </dependency>
	
	<dependency>
		   	<groupId>org.apache.httpcomponents</groupId>
		   	<artifactId>httpclient</artifactId>
		   	<version>4.5.2</version>
	   </dependency>

	<!--引入commons-httpclient  -->
	<dependency>
		   	<groupId>commons-httpclient</groupId>
		   	<artifactId>commons-httpclient</artifactId>
		   	<version>3.1</version>
	   </dependency>
	
	
		<!-- 引入common-lang包 -->
	   <dependency>
		   	<groupId>commons-lang</groupId>
		   	<artifactId>commons-lang</artifactId>
		   	<version>2.6</version>
	   </dependency>
	    <!--引入redis依赖  -->
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-redis</artifactId>
		</dependency>
		
		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<!-- <version>2.7.3</version> --><!--spring boot里面已经对他进行了版本控制  -->
		</dependency>
		<!-- ehcache spring 自带的EhcacheManager是在spring-context 和spring-context-support模块中 -->
		<dependency>
			<groupId>net.sf.ehcache</groupId>
			<artifactId>ehcache</artifactId>
			<!-- <version>2.10.3</version> -->
		</dependency>
		<!-- 引入mongo相关依赖 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-mongodb</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!--读取配置文件 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
		</dependency>
	</dependencies>
	<dependencyManagement>
		<dependencies>
			<!-- spring Cloud相关的组件版本控制 -->
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<!--maven插件 -->
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugin</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.1</version>
				<configuration>
					<skip>true</skip>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

如要完整代码请参见本人github地址,里面还有其他关于Spring Cloud的学习项目,不要忘记点赞

 https://github.com/songhq211949/springCloud.git  里面的cache项目,如有问题请多多指教

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,下面是Spring Boot整合Ehcache解决Mybatis二级缓存数据脏读的详细步骤: 1. 添加依赖 首先,需要在pom.xml文件中添加Ehcache和Spring Boot的相关依赖: ``` <!-- Ehcache依赖 --> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.10.6</version> </dependency> <!-- Spring Boot依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency> ``` 2. 配置Ehcache 在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" updateCheck="false"> <!-- 默认缓存配置 --> <defaultCache maxEntriesLocalHeap="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="30" maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" statistics="true"> </defaultCache> <!-- Mybatis二级缓存配置 --> <cache name="com.example.demo.mapper.UserMapper" maxEntriesLocalHeap="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="30" maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" statistics="true"> </cache> </ehcache> ``` 在配置文件中,我们定义了默认缓存配置和针对UserMapper的缓存配置。 3. 配置Mybatis 在application.properties中添加Mybatis相关配置: ``` # Mybatis配置 mybatis.type-aliases-package=com.example.demo.entity mybatis.mapper-locations=classpath:mapper/*.xml mybatis.configuration.cache-enabled=true mybatis.configuration.local-cache-scope=session mybatis.configuration.cache-ref=ehcache ``` 注意,cache-enabled属性设置为true,local-cache-scope属性设置为session,并指定了使用的缓存提供者为Ehcache。 4. 配置缓存管理器 在启动类中配置缓存管理器: ``` @Configuration @EnableCaching public class CacheConfig { @Bean public CacheManager cacheManager() { EhCacheCacheManager cacheManager = new EhCacheCacheManager(); cacheManager.setCacheManager(ehCacheManagerFactoryBean().getObject()); return cacheManager; } @Bean public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() { EhCacheManagerFactoryBean cacheManagerFactoryBean = new EhCacheManagerFactoryBean(); cacheManagerFactoryBean.setConfigLocation(new ClassPathResource("ehcache.xml")); cacheManagerFactoryBean.setShared(true); return cacheManagerFactoryBean; } } ``` 在这里,我们通过EhCacheCacheManagerEhCacheManagerFactoryBean来配置缓存管理器。 5. 开启缓存 最后,在Mapper接口中开启缓存: ``` @CacheNamespace(implementation = net.sf.ehcache.Cache.class, eviction = FifoPolicy.class) public interface UserMapper { @Select("SELECT * FROM user WHERE id = #{id}") @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 10000) User selectById(Integer id); @Update("UPDATE user SET name = #{name} WHERE id = #{id}") void updateNameById(@Param("id") Integer id, @Param("name") String name); } ``` 使用@CacheNamespace注解来指定缓存实现类和缓存策略,在每个查询方法上使用@Options注解来开启缓存。 至此,Spring Boot整合Ehcache解决Mybatis二级缓存数据脏读的配置就完成了。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值