redis與ssm整合方法(mybatis二級(jí)緩存)
SSM+redis整合
ssm框架之前已經(jīng)搭建過(guò)了,這里不再做代碼復(fù)制工作。
這里主要是利用redis去做mybatis的二級(jí)緩存,mybaits映射文件中所有的select都會(huì)刷新已有緩存,如果不存在就會(huì)新建緩存,所有的insert,update操作都會(huì)更新緩存。
redis的好處也顯而易見(jiàn),可以使系統(tǒng)的數(shù)據(jù)訪問(wèn)性能更高。本節(jié)只是展示了整合方法和效果,后面會(huì)補(bǔ)齊redis集群、負(fù)載均衡和session共享的文章。
下面就開(kāi)始整合工作:
后臺(tái)首先啟動(dòng)redis-server(后臺(tái)啟動(dòng)與遠(yuǎn)程連接linux服務(wù)的方法都需要改redis.conf文件),啟動(dòng)命令“./src/redis-server ./redis.conf”
我這里是windows系統(tǒng)下開(kāi)發(fā)的,推薦一個(gè)可視化工具“Redis Desktop manager”,需要遠(yuǎn)程連接linux下的redis,需要linux下開(kāi)啟端口對(duì)外開(kāi)放(具體方法是修改/etc/sysconfig/iptables文件,增加對(duì)外端口開(kāi)發(fā)命令)。
以上操作都完成后,即可遠(yuǎn)程連接成功了,如圖:
現(xiàn)在還沒(méi)有緩存記錄,下面進(jìn)入代碼階段,首先在pom.xml中增加需要的redis jar包
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.6.2.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.0.0</version> </dependency> <!-- 添加druid連接池包 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.24</version> </dependency>
pom.xml寫(xiě)好后,還需要新增兩個(gè)配置文件:redis.properties
redis.host=192.168.0.109 redis.port=6379 redis.pass=123456 redis.maxIdle=200 redis.maxActive=1024 redis.maxWait=10000 redis.testOnBorrow=true
其中字段也都很好理解,再加入配置文件:spring-redis.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <!-- 連接池基本參數(shù)配置,類似數(shù)據(jù)庫(kù)連接池 --> <context:property-placeholder location="classpath*:redis.properties" /> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="${redis.maxActive}"/> <property name="maxIdle" value="${redis.maxIdle}" /> <property name="testOnBorrow" value="${redis.testOnBorrow}"/> </bean> <!-- 連接池配置,類似數(shù)據(jù)庫(kù)連接池 --> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" > <property name="hostName" value="${redis.host}"></property> <property name="port" value="${redis.port}"></property> <property name="password" value="${redis.pass}"></property> <property name="poolConfig" ref="poolConfig"></property> </bean> <!-- 調(diào)用連接池工廠配置 --> <!-- <bean id="redisTemplate" class=" org.springframework.data.redis.core.RedisTemplate"> <property name="jedisConnectionFactory" ref="jedisConnectionFactory"></property> 如果不配置Serializer,那么存儲(chǔ)的時(shí)候智能使用String,如果用User類型存儲(chǔ),那么會(huì)提示錯(cuò)誤User can't cast to String?。?! <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /> </property> </bean> --> <bean id="redisCacheTransfer" class="com.cjl.util.RedisCacheTransfer"> <property name="jedisConnectionFactory" ref="jedisConnectionFactory" /> </bean> </beans>
配置文件寫(xiě)好后,就開(kāi)始java代碼的編寫(xiě):
JedisClusterFactory.java
package com.cjl.util; import java.util.HashSet; import java.util.Properties; import java.util.Set; import java.util.regex.Pattern; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.Resource; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; public class JedisClusterFactory implements FactoryBean<JedisCluster>, InitializingBean { private Resource addressConfig; private String addressKeyPrefix; private JedisCluster jedisCluster; private Integer timeout; private Integer maxRedirections; private GenericObjectPoolConfig genericObjectPoolConfig; private Pattern p = Pattern.compile("^.+[:]\\d{1,5}\\s*$"); public JedisCluster getObject() throws Exception { return jedisCluster; } public Class<? extends JedisCluster> getObjectType() { return (this.jedisCluster != null ? this.jedisCluster.getClass() : JedisCluster.class); } public boolean isSingleton() { return true; } private Set<HostAndPort> parseHostAndPort() throws Exception { try { Properties prop = new Properties(); prop.load(this.addressConfig.getInputStream()); Set<HostAndPort> haps = new HashSet<HostAndPort>(); for (Object key : prop.keySet()) { if (!((String) key).startsWith(addressKeyPrefix)) { continue; } String val = (String) prop.get(key); boolean isIpPort = p.matcher(val).matches(); if (!isIpPort) { throw new IllegalArgumentException("ip 或 port 不合法"); } String[] ipAndPort = val.split(":"); HostAndPort hap = new HostAndPort(ipAndPort[0], Integer.parseInt(ipAndPort[1])); haps.add(hap); } return haps; } catch (IllegalArgumentException ex) { throw ex; } catch (Exception ex) { throw new Exception("解析 jedis 配置文件失敗", ex); } } public void afterPropertiesSet() throws Exception { Set<HostAndPort> haps = this.parseHostAndPort(); jedisCluster = new JedisCluster(haps, timeout, maxRedirections, genericObjectPoolConfig); } public void setAddressConfig(Resource addressConfig) { this.addressConfig = addressConfig; } public void setTimeout(int timeout) { this.timeout = timeout; } public void setMaxRedirections(int maxRedirections) { this.maxRedirections = maxRedirections; } public void setAddressKeyPrefix(String addressKeyPrefix) { this.addressKeyPrefix = addressKeyPrefix; } public void setGenericObjectPoolConfig(GenericObjectPoolConfig genericObjectPoolConfig) { this.genericObjectPoolConfig = genericObjectPoolConfig; } }
RedisCache.java
package com.cjl.util; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.ibatis.cache.Cache; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.connection.jedis.JedisConnection; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; import redis.clients.jedis.exceptions.JedisConnectionException; public class RedisCache implements Cache { private static final Logger logger = LoggerFactory.getLogger(RedisCache.class); private static JedisConnectionFactory jedisConnectionFactory; private final String id; private final ReadWriteLock rwl = new ReentrantReadWriteLock(); public RedisCache(final String id) { if (id == null) { throw new IllegalArgumentException("Cache instances require an ID"); } logger.debug("MybatisRedisCache:id=" + id); this.id = id; } /** * 清空所有緩存 */ public void clear() { rwl.readLock().lock(); JedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); connection.flushDb(); connection.flushAll(); } catch (JedisConnectionException e) { e.printStackTrace(); } finally { if (connection != null) { connection.close(); } rwl.readLock().unlock(); } } public String getId() { return this.id; } /** * 獲取緩存總數(shù)量 */ public int getSize() { int result = 0; JedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); result = Integer.valueOf(connection.dbSize().toString()); logger.info("添加mybaits二級(jí)緩存數(shù)量:" + result); } catch (JedisConnectionException e) { e.printStackTrace(); } finally { if (connection != null) { connection.close(); } } return result; } public void putObject(Object key, Object value) { rwl.writeLock().lock(); JedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); connection.set(SerializeUtil.serialize(key), SerializeUtil.serialize(value)); logger.info("添加mybaits二級(jí)緩存key=" + key + ",value=" + value); } catch (JedisConnectionException e) { e.printStackTrace(); } finally { if (connection != null) { connection.close(); } rwl.writeLock().unlock(); } } public Object getObject(Object key) { // 先從緩存中去取數(shù)據(jù),先加上讀鎖 rwl.readLock().lock(); Object result = null; JedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); result = serializer.deserialize(connection.get(serializer.serialize(key))); logger.info("命中mybaits二級(jí)緩存,value=" + result); } catch (JedisConnectionException e) { e.printStackTrace(); } finally { if (connection != null) { connection.close(); } rwl.readLock().unlock(); } return result; } public Object removeObject(Object key) { rwl.writeLock().lock(); JedisConnection connection = null; Object result = null; try { connection = jedisConnectionFactory.getConnection(); RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer(); result = connection.expire(serializer.serialize(key), 0); } catch (JedisConnectionException e) { e.printStackTrace(); } finally { if (connection != null) { connection.close(); } rwl.writeLock().unlock(); } return result; } public static void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) { RedisCache.jedisConnectionFactory = jedisConnectionFactory; } public ReadWriteLock getReadWriteLock() { // TODO Auto-generated method stub return rwl; } }
RedisCacheTransfer.java
package com.cjl.util; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; /** * 靜態(tài)注入中間類 */ public class RedisCacheTransfer { @Autowired public void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) { RedisCache.setJedisConnectionFactory(jedisConnectionFactory); } }
SerializeUtil.java
package com.cjl.util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; /** * * @author cjl * */ public class SerializeUtil { /** * 序列化 */ public static byte[] serialize(Object object) { ObjectOutputStream oos = null; ByteArrayOutputStream baos = null; try { // 序列化 baos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(baos); oos.writeObject(object); byte[] bytes = baos.toByteArray(); return bytes; } catch (Exception e) { e.printStackTrace(); } return null; } /** *反序列化 */ public static Object unserialize(byte[] bytes) { if (bytes !=null) { ByteArrayInputStream bais = null; try { // 反序列化 bais = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(bais); return ois.readObject(); } catch (Exception e) { } } return null; } }
所有東西準(zhǔn)備齊全后還需要修改映射文件
要使mybaits緩存生效,還需如上圖這樣開(kāi)啟二級(jí)緩存。配置文件還需要在web.xml中加載生效
一切準(zhǔn)備就緒后,啟動(dòng)服務(wù)
啟動(dòng)成功后,點(diǎn)擊員工表單可以觸發(fā)查詢所有員工的方法,第一次進(jìn)行查詢語(yǔ)句可以看到mybatis打印了查詢語(yǔ)句,并在redis服務(wù)器中更新了一條緩存
我們清空控制臺(tái)再次點(diǎn)擊查詢員工按鈕執(zhí)行查詢方法,可以看到?jīng)]有執(zhí)行查詢語(yǔ)句,證明第二次查詢直接從緩存中取值,沒(méi)有連接mysql進(jìn)行查詢。
總結(jié)
以上所述是小編給大家介紹的redis與ssm整合方法(mybatis二級(jí)緩存),希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- 如何利用Redis作為Mybatis的二級(jí)緩存
- MyBatis整合Redis實(shí)現(xiàn)二級(jí)緩存的示例代碼
- Mybatis-plus基于redis實(shí)現(xiàn)二級(jí)緩存過(guò)程解析
- mybatis plus使用redis作為二級(jí)緩存的方法
- Spring Boot基礎(chǔ)學(xué)習(xí)之Mybatis操作中使用Redis做緩存詳解
- SpringBoot+Mybatis項(xiàng)目使用Redis做Mybatis的二級(jí)緩存的方法
- springboot+mybatis+redis 二級(jí)緩存問(wèn)題實(shí)例詳解
- 詳解Spring boot使用Redis集群替換mybatis二級(jí)緩存
- MyBatis緩存和二級(jí)緩存整合Redis的解決方案
相關(guān)文章
Java同步鎖synchronized用法的最全總結(jié)
這篇文章主要介紹了Java同步鎖synchronized用法的最全總結(jié),需要的朋友可以參考下,文章詳細(xì)講解了Java同步鎖Synchronized的使用方法和需要注意的點(diǎn),希望對(duì)你有所幫助2023-03-03Elasticsearch學(xué)習(xí)之Terms?set?查詢
這篇文章主要為大家介紹了Elasticsearch學(xué)習(xí)Terms?set?查詢示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02使用java實(shí)現(xiàn)BBS論壇發(fā)送郵件過(guò)程詳解
這篇文章主要介紹了使用java發(fā)送郵件過(guò)程詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04java中重寫(xiě)父類方法加不加@Override詳解
這篇文章主要介紹了java中重寫(xiě)父類方法加不加@Override詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06spring boot 配置動(dòng)態(tài)刷新實(shí)現(xiàn)詳解
這篇文章主要介紹了spring boot 配置動(dòng)態(tài)刷新實(shí)現(xiàn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09SpringBoot中的定時(shí)任務(wù)和異步調(diào)用詳解
這篇文章主要介紹了SpringBoot中的定時(shí)任務(wù)和異步調(diào)用詳解,SpringBoot 定時(shí)任務(wù)是一種在SpringBoot應(yīng)用中自動(dòng)執(zhí)行任務(wù)的機(jī)制,通過(guò)使用Spring框架提供的@Scheduled注解,我們可以輕松地創(chuàng)建定時(shí)任務(wù),需要的朋友可以參考下2023-10-10java過(guò)濾html標(biāo)簽獲取純文本信息的實(shí)例
今天小編就為大家分享一篇java過(guò)濾html標(biāo)簽獲取純文本信息的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05SpringBoot實(shí)現(xiàn)接口等冪次校驗(yàn)的示例代碼
本文主要介紹了SpringBoot實(shí)現(xiàn)接口等冪次校驗(yàn)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01Springboot?定時(shí)任務(wù)分布式下冪等性解決方案
這篇文章主要介紹了Springboot定時(shí)任務(wù)分布式下冪等性如何解決,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07