开发者社区> 贪挽懒月> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

spring及springboot整合redis

简介: 前言: redis是一种nosql数据库,以的形式存储数据,其速度相比于MySQL之类的数据库,相当于内存读写与硬盘读写的差别,所以常常用作缓存。接下来就分别看看在spring项目和springboot项目中如何使用redis(项目都基于SSM)。
+关注继续查看

前言:

redis是一种nosql数据库,以<key,value>的形式存储数据,其速度相比于MySQL之类的数据库,相当于内存读写与硬盘读写的差别,所以常常用作缓存。接下来就分别看看在spring项目和springboot项目中如何使用redis(项目都基于SSM)。

一、整合前提:

前提是你已经安装redis且支持远程连接,redis的安装这里不再赘述,有需要的可以参考我的另一篇文章:centos 7.3上安装redis这里主要讲讲如何判断及设置redis支持远程连接。

1、判断你的redis是否支持远程连接:
①:在centos中输入如下命令找到redis-cli:
whereis redis-cli

②:根据返回的目录找到redis-cli,再执行如下命令:
redis-cli -h 192.168.1.100

③:192.168.1.100就是你的虚拟机ip地址。若这一步报错connect refused,可能是防火墙没有开放6379端口。执行如下命令查看开放的端口:
firewall-cmd --zone=public --list-ports

④:若确实没有6379,那就执行如下命令添加:
firewall-cmd --zone=public --add-port=6379/tcp --permanent

⑤:然后重启防火墙:
firewall-cmd --reload

⑥:开放了6379端口后再次执行:
redis-cli -h 192.168.1.100
出现如下结果:

img_cf4b656584beefba499f98ccdd16138d.png
image.png

⑦:这样并不能说明支持远程连接,我们输入ping,如果返回pong,说明才是支持远程连接的。

img_17cdd2724268b87f9b23a21a090d3fe1.png
image.png

2、设置支持远程连接:
如果没有返回pong,而是报错了,执行如下操作:
①:先关闭redis:
redis-cli shutdown

②:找到redis的配置文件:
whereis redis.conf

③:根据返回的目录,用vim打开redis.conf:
vim redis.conf
bind 127.0.0.1改成bind 0.0.0.0,
再把protected-mode=yesyes改为no,

img_0bc820ffa391c886475e13e86b6cc99e.png
image.png

④:然后保存退出,重启redis,再用redis-cli连接,输入ping,就能返回pong了。

二、spring整合redis:

下载源码。
1、引依赖:
pom.xml:

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.7.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>

除了ssm整合以及mysql数据库需要的依赖,引入以上两个即可。
注意:
注意这两个jar包的版本搭配,有些版本搭配可能会报错,这两个版本搭配亲测可用。

2、编写RedisUtil工具类:

package com.zhu.redis.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.concurrent.Callable;

import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;

public class RedisUtil implements Cache {

    private RedisTemplate<String, Object> redisTemplate;
    private String name;

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

    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

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

    public String getName() {
        return this.name;
    }

    public byte[] toByteArray(Object obj) {
        byte[] bytes = null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            oos.flush();
            bytes = bos.toByteArray();
            oos.close();
            bos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bytes;
    }

    public Object toObject(byte[] bytes) {
        Object obj = null;
        try {
            ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bis);
            obj = ois.readObject();
            ois.close();
            bis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

    @Override
    public Object getNativeCache() {
        return this.redisTemplate;
    }

    @Override
    public ValueWrapper get(Object key) {
        System.out.println("--------------------------- get key ----------------------------");
        final String keyf = key.toString();
        Object object = null;
        object = redisTemplate.execute(new RedisCallback<Object>() {
            public Object doInRedis(RedisConnection connection) {
                byte[] key = keyf.getBytes();
                byte[] value = connection.get(key);
                if (value == null) {
                    return null;
                }
                return toObject(value);
            }
        });
        return (object != null ? new SimpleValueWrapper(object) : null);
    }

    @Override
    public void put(Object key, Object value) {
        System.out.println("------------------- put key --------------------------");
        final String keyf = key.toString();
        final Object valuef = value;
        final long liveTime = 86400;
        redisTemplate.execute(new RedisCallback<Long>() {
            public Long doInRedis(RedisConnection connection) {
                byte[] keyb = keyf.getBytes();
                byte[] valueb = toByteArray(valuef);
                connection.set(keyb, valueb);
                if (liveTime > 0) {
                    connection.expire(keyb, liveTime);
                }
                return 1L;
            }
        });

    }

    @Override
    public void evict(Object key) {
        System.out.println("-------------------------- del key ---------------------------");
        final String keyf = key.toString();
        redisTemplate.execute(new RedisCallback<Long>() {
            public Long doInRedis(RedisConnection connection) {
                return connection.del(keyf.getBytes());
            }
        });

    }

    @Override
    public void clear() {
        System.out.println("-------------------- clear key -------------------------");
        redisTemplate.execute(new RedisCallback<String>() {
            public String doInRedis(RedisConnection connection) {
                connection.flushDb();
                return "ok";
            }
        });

    }

    @Override
    public ValueWrapper putIfAbsent(Object key, Object value) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public <T> T get(Object key, Class<T> type) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public <T> T get(Object key, Callable<T> valueLoader) {
        // TODO Auto-generated method stub
        return null;
    }

}

这个类等下要在spring-redis.xml中配置。该类继承了spring的cache,提供了对缓存的一些基本操作的方法(get、del等),还定义了一个name成员变量,在需要用缓存的地方直接用注解@Cacheable(value="name的值")即可。

3、连接参数redis.properties:
redis.properties:

redis.host=192.168.1.100
redis.port=6379
redis.dbIndex=0
redis.expiration=3000
redis.maxIdle=300
redis.maxActive=600
redis.maxWait=1000
redis.testOnBorrow=true

4、在spring-redis.xml中整合:

<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="${redis.maxIdle}" /> 
        <property name="maxTotal" value="${redis.maxActive}" />
        <property name="maxWaitMillis" value="${redis.maxWait}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>

    <bean id="jedisConnectionFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="${redis.host}" />
        <property name="port" value="${redis.port}" />
        <property name="database" value="${redis.dbIndex}" />
        <property name="poolConfig" ref="poolConfig" />
    </bean>

    <bean id="redisTemplate"
        class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="jedisConnectionFactory"></property>
    </bean>
    
    <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
        <property name="caches">
            <set>
                <!-- 自定义的RedisUtil工具类 -->
                <bean class="com.zhu.redis.util.RedisUtil">
                    <property name="redisTemplate" ref="redisTemplate"/>
                    <!-- name属性的值自己随便写,等下在注解当中用 -->
                    <property name="name" value="common"/>
                </bean>
            </set>
        </property>
    </bean>
    <!-- 开启注解,这个非常重要,否则等下使用缓存注解不生效 -->
    <cache:annotation-driven cache-manager="cacheManager"/>

注意:
我这里并没有引入redis.properties,是因为我在spring-dao.xml中引入jdbc.properties时一起引入了,所以这里无需再引入。
spring-dao.xml中引入.properties文件代码:

    <bean
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:jdbc.properties</value>
                <value>classpath:redis.properties</value>
            </list>
        </property>
    </bean>

5、在service层使用redis:

@Service
public class AreaServiceImpl implements AreaService {
    @Autowired
    private AreaDao areaDao;
    
    @Cacheable(value="common") //加入缓存
    //@CacheEvict(value="common") //清除缓存
    @Override
    public List<Area> getAreaList() {
        return areaDao.queryArea();
    }

}

注意:
要使用redis,实体类必须实现序列化接口(implements Serializable),否则会抛java.io.NotSerializableException异常。

6、测试:
首先看一下数据库:

img_b382e831347bc010a5d852c1f887a035.png
image.png

然后用junit测试:
BaseTest.java:(用来加载配置文件)

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:spring/spring-dao.xml","classpath:spring/spring-service.xml","classpath:spring/spring-redis.xml"})
public class BaseTest {

}

AreaServiceTest.java:

public class AreaServiceTest extends BaseTest {
    
    @Autowired
    private AreaService areaService;
    
    @Test
    public void test() {
        List<Area> areaList = areaService.getAreaList();
        for(Area area : areaList) {
            System.out.println(area.getAreaName());
        }
        System.out.println(areaList.size());
    }

}

看运行结果:

img_4eb9c2d0586d3d632d489a2a2da49eae.png
image.png

从图中可以看到这一次是从MySQL数据库查询的,且RedisUtil已经运行,因为打印出了put key。

再运行一次:

img_df869a62af1257c9043bc68fece70555.png
image.png

可以看到这次没有打印sql语句,且打印了get key,说明缓存已经生效。

把AreaService.java中的@Cacheable(value="common")注释掉,把@CacheEvict(value="common")放开,
再次运行:

img_c7a919856b80bbacab1b56edcfdfd82d.png
image.png

可以看到又打印出了sql语句,且输出了del key,说明已经清除了缓存,再次从数据库中查找。

这样就完成了spring与redis的整合。

三、springboot整合redis:

springboot整合redis就简单了,只需要简单配置就行了。

1、引依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-redis</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

springboot整合redis,只需引入这一个依赖即可。

2、在application.properties中配置redis:

spring.redis.host=192.168.1.100
spring.redis.port=6379
#连接池最大连接数
spring.redis.jedis.pool.max-active=8
#最小空闲连接
spring.redis.jedis.pool.min-idle=0
#最大阻塞等待时间,负值表示没有限制
spring.redis.jedis.pool.max-wait=-1
#最大空闲连接
spring.redis.jedis.pool.max-idle=8
#连接超时时间(毫秒)
spring.redis.timeout=20

3、在springboot启动类上加上@EnableCaching注解,如下图:

img_156ba2aab558464e14a9f82e517d71f9.png
image.png

4、接下来就可以使用redis缓存了:
在需要使用的地方加上注解即可。
AreaServiceImpl.java:

@Service
public class AreaServiceImpl implements AreaService {

    @Autowired
    private AreaDao areaDao;


    @Override
    @Transactional
    @Cacheable(value = "common")
    //@CacheEvict(value="common")
    public List<Area> getAreaList() {
        return areaDao.queryArea();
    }

}

5、测试:
AreaServiceTest.java:

@RunWith(SpringRunner.class)
@SpringBootTest
public class AreaServiceTest {
    
    @Autowired
    private AreaService areaService;
    
    @Test
    public void test() {
        List<Area> areaList = areaService.getAreaList();
        for(Area area : areaList) {
            System.out.println(area.getAreaName());
        }
    }

}

第一次运行:

img_b5ed56afffe749a1609082b816024d84.png
image.png

打印出了sql语句,是从数据库查询的。

第二次运行:

img_c25f11f034c943c2398da891aeb4a3c6.png
image.png

没有sql语句,是从缓存中读取的。

@Cacheable(value = "common")注释掉,把@CacheEvict(value="common")放开,
再运行:

img_9d9c87d16d4f9a914fdeec901a42eeec.png
image.png

又是从数据库中读取的,说明redis清除成功。

总结:

spring整合redis:
总的来说就是引依赖、编写RedisUtil、编写redis.properties、在spring-redis.xml中配置,最后在需要使用的地方用注解就行了。
spring boot整合redis:
总的来说就是引依赖、在application.properties中配置、在启动类上加@EnableCaching注解,然后在需要使用的地方用注解就行了。
注意事项:
1、首先你的redis得支持远程连接。
2、实体类必须实现序列化接口。
3、redis的注解是@Cacheable(value = "?",key="?")这样的key、value形式,value必须自己指定,可以随便写,key可以不写,不写会自动生成。
4、如果要使用缓存的方法的参数是引用类型,比如方法是getStudent(Student stu)那么该引用类型的必须重写toString方法,即Student实体类必须重写toString方法,否则使用缓存时会报错can not convert com.zhu.entity.Student toString
5、若项目发布到服务器上,一开始redis可以正常使用,一段时间后redis不能正常使用,用redis-cli -h xx.xxx.x.xxx -p 6379命令连接显示connection timeout,访问项目中用到了redis的路由会报错could not get a resource from pool,可按如下步骤解决:
先kill掉redis的服务:
ps aux | grep redis
kill -9 redis服务的pid
换端口开启redis服务:
redis-server redis.conf --port=6000 &
这里指定的6000端口,也可以是其他的,&表示后台启动。再用redis-cli -h xx.xxx.x.xxx -p 6000就可以连接上了。然后把项目中的redis配置的端口换成6000,重新发布项目即可。
项目说明:
1、springboot是springboot2.x,springboot 1.5整合redis与这个不一样。
2、上述两个项目之所以会打印查询的sql语句,是因为在mybatis-config.xml中进行了如下配置:

    <settings>
        <!-- 打印查询语句 -->
        <setting name="logImpl" value="STDOUT_LOGGING" />
    </settings>

以上内容属于个人笔记整理,如有错误,欢迎批评指正!

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
spring session redis 实现集群session共享,SessionListener监听生效
spring session redis 实现集群session共享,SessionListener监听生效
0 0
redis 哨兵模式配置 和 spring data redis 哨兵配置 总结
redis 哨兵模式配置 和 spring data redis 哨兵配置 总结
0 0
微服务 Spring Boot 整合Redis分布式锁 实现优惠卷秒杀 一人一单
高并发集群模式下,秒杀出现问题,如何解决,Redis 分布式锁来搞定!
0 0
《Spring Boot2.0实战Redis分布式缓存》电子版地址
第10课:Spring Boot2.0实战Redis分布式缓存
0 0
利用Java来访问Redis并对Redis进行相关操作以及spring+redis集成配置与注解式注解
redis缓存的一些注意事项 只应将热数据放到缓存中 所有缓存信息都应设置过期时间 缓存过期时间应当分散以避免集中过期 缓存key应具备可读性 应避免不同业务出现同名缓存key 可对key进行适当的缩写以节省内存空间 选择合适的数据结构 确保写入缓存中的数据是完整且正确的 避免使用耗时较长的操作命令,如:keys * Redis默认配置中操作耗时超过10ms即视为慢查询 一个key对应的数据不应过大 对于string类型,一个key对应的value大小应控制在10K以内,1K左右更优hash类型,不应超过5000行
0 0
太厉害!Redis+Nginx+设计模式+Spring全家桶+Dubbo技术精选合集
最近花了很长的时间去搜罗Java核心技术好文,我把每个Java核心技术的优选文章都整理成了一个又一个的文档。昨天也是终于全部整理好了,今天就把这些东西分享给老铁们,也能为老铁们省去不少麻烦,想学什么技能了,遇到哪方面的问题了 直接打开文档学一学就好了。不多bb了,直接上干货!
0 0
如何结合spring和redis进行优雅的轮询
如何结合spring和redis进行优雅的轮询
0 0
Spring boot整合Redis(入门教程)
jedis:采用直连,多个线程操作的话,是不安全的。如果想要避免不安全的,使用jedis pool连接池!更像BIO模式 lettuce:采用netty,实例可以在多个线程中进行共享,不存在线程不安全的情况,可以减少线程数据,更像NIO模式
0 0
Spring boot整合Redis实现发布订阅(超详细)
Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收信息。微信,微博,关注系统 Redis客户端可以订阅任意数量的频道
0 0
分布式和集群的理解和redis集群及jidis连接集群和Spring控制反转
分布式: 将一个业务分割成多个子业务,然后将他们分布在不同的机器上进行相同业务的处理,这就叫做分布式
0 0
+关注
贪挽懒月
java学习者
文章
问答
文章排行榜
最热
最新
相关电子书
更多
阿里云Redis服务助力游戏行业发展--王义成
立即下载
Spring Boot2.0实战Redis分布式缓存
立即下载
国内开发者与Redis开源社区的发展
立即下载