Spring+Redis整合

来源:互联网 发布:天才琪露诺软件 编辑:程序博客网 时间:2024/05/25 01:34

一:目录

  • redis的安装和启动
  • jedis的使用
    • Hello World
    • JedisPool的使用
  • Spring整合

二:Redis下载、安装和启动

1、下载和安装redis
Windows x64下载地址:https://github.com/ServiceStack/redis-windows
下载完直接解压就好

2、启动Redis服务
使用终端切换到redis的目录下,然后 使用命令启动 redis-server.exe redis.windows.conf

3、启动客户端

使用终端切换到redis的目录下,然后 使用命令启动 redis-cli.exe


三:jedis的使用

1、在pom.xml 中引入spring(需要用到spring-test来测试)和jedis相关的依赖

  <properties>    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>    <spring.version>4.2.3.RELEASE</spring.version>  </properties>  <dependencies>    <dependency>      <groupId>junit</groupId>      <artifactId>junit</artifactId>      <version>4.10</version>      <scope>test</scope>    </dependency>    <dependency>         <groupId>org.springframework</groupId>         <artifactId>spring-test</artifactId>         <version>${spring.version}</version>         <scope>test</scope>     </dependency>     <!-- springframework -->    <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-core</artifactId>        <version>${spring.version}</version>    </dependency>    <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-context</artifactId>        <version>${spring.version}</version>    </dependency>    <dependency>        <groupId>redis.clients</groupId>        <artifactId>jedis</artifactId>        <version>2.9.0</version>    </dependency>       </dependencies>

2、测试Jedis相关的方法

这里只是列举出jedis常用的一些方法,jedis的方法名和redis的命令是一样的,了解了命令就自然知道jedis中相关的方法了,这里并不介绍redis中的每个命令

SpringTestCase

package com.mengdee.manager.redis;import org.junit.runner.RunWith;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@ContextConfiguration(locations = {"classpath:conf/spring/spring-base.xml"})@RunWith(SpringJUnit4ClassRunner.class)public class SpringTestCase extends AbstractJUnit4SpringContextTests{}

JedisTest

package com.mengdee.manager.redis;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Map.Entry;import java.util.Set;import org.junit.Before;import org.junit.Test;import org.springframework.beans.factory.annotation.Autowired;import redis.clients.jedis.Jedis;public class JedisTest extends SpringTestCase{    private Jedis jedis;    @Before    public void setup(){        jedis = new Jedis("127.0.0.1", 6379);    }     /**      * redis 字符串string      *       * 常用操作:添加键值对 、获取键对应的值、删除键、批量添加键值对、对数字型的值+1或者-1      */      @Test      public void testString() {          //-----添加数据----------            String key = "name";          jedis.set(key,"mengdee");          System.out.println(jedis.get(key));          jedis.append(key, " is good");           System.out.println(jedis.get(key));           jedis.del(key);            System.out.println(jedis.get(key));          // 批量添加键值对,注意值都是字符串类型,注意这里是一次性添加三个键值对,他们的关系是并列关系(即使三个键值对而不是一个键值对的值是三个值)          jedis.mset("name","mengdee","age","23","nickname","mengday");          jedis.incr("age"); //进行加1操作          System.out.println(jedis.get(key) + "-" + jedis.get("age") + "-" + jedis.get("nickname"));      }      /**       * redis map       * map 包含多个键值对,通常存储Java中的对象使用map数据类型存储       */      @Test      public void testMap() {          //-----添加数据----------            Map<String, String> userMap = new HashMap<String, String>();          userMap.put("id", "1");          userMap.put("username", "mengdee");          userMap.put("age", "20");          String key = "user:1";          jedis.hmset(key, userMap);          // 一次获取多个字段的值          List<String> values = jedis.hmget(key, "id", "username", "age");          System.out.println(values);            // 通常使用hgetAll获取到的Map转换成Java中的对象          Map<String, String> userMap2 = jedis.hgetAll(key);          Set<Entry<String, String>> entrySet = userMap2.entrySet();          for (Entry<String, String> entry : entrySet) {            System.out.println(entry.getKey() + ":" + entry.getValue());          }          System.out.println(jedis.hmget(key, "age"));           System.out.println(jedis.hlen(key));           System.out.println(jedis.exists(key));            System.out.println(jedis.hkeys(key));          System.out.println(jedis.hvals(key));          jedis.hdel(key,"age");      }      /**        * jedis list(一般存储像Java中的数组或者List这样的数据类型)       */        @Test        public void testList(){            //开始前,先移除所有的内容            String key = "java";          jedis.del(key);            jedis.lpush(key, "gradle");            jedis.lpush(key, "springmvc");            jedis.lpush(key, "mybatis");            jedis.rpush(key, "spring boot");          System.out.println(jedis.lrange(key, 0, -1));            jedis.del(key);          jedis.rpush(key, "spring");            jedis.rpush(key, "struts");            jedis.rpush(key, "hibernate");           System.out.println(jedis.lrange(key, 0, -1));      }       /**       * jedis set      *       * 注意set操作是无须的      */       @Test       public void testSet(){           //添加           String key = "users";         jedis.sadd(key,"zhangsan");           jedis.sadd(key,"lisi");           jedis.sadd(key,"mengdee");           jedis.sadd(key,"mengday");         jedis.sadd(key,"X");           jedis.srem(key,"X");           System.out.println(jedis.smembers(key));         System.out.println(jedis.sismember(key, "mengdee"));         System.out.println(jedis.srandmember(key));           System.out.println(jedis.scard(key));     }  }

3、JedisPool的使用

上面示例是没有使用线程池的,在实际开发中肯定要使用线程池,要不然每次都要建立连接,下面只是简单的实现方式,demo版,不能实际在项目中使用,在项目中实际使用还需要使用更优的实现

package com.mengdee.manager.utils;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig;public final class RedisUtil {    //Redis服务器IP    private static String ADDR = "127.0.0.1";    //Redis的端口号    private static int PORT = 6379;    //访问密码    private static String AUTH = "admin";    //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。    private static int MAX_IDLE = 200;    private static int TIMEOUT = 10000;    //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;    private static boolean TEST_ON_BORROW = true;    private static JedisPool jedisPool = null;    /**     * 初始化Redis连接池     */    static {        try {            JedisPoolConfig config = new JedisPoolConfig();            config.setMaxIdle(MAX_IDLE);            config.setTestOnBorrow(TEST_ON_BORROW);            jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);        } catch (Exception e) {            e.printStackTrace();        }    }    /**     * 获取Jedis实例     * @return     */    public synchronized static Jedis getJedis() {        try {            if (jedisPool != null) {                Jedis resource = jedisPool.getResource();                return resource;            } else {                return null;            }        } catch (Exception e) {            e.printStackTrace();            return null;        }    }    /**     * 释放jedis资源     * @param jedis     */    public static void returnResource(final Jedis jedis) {        if (jedis != null) {            jedisPool.returnResource(jedis);        }    }}

使用JedisUtil获取Jedis对象,操作缓存

@Testpublic void testRedisPool() {      JedisUtil.getJedis().set("newname", "中文测试");      System.out.println(RedisUtil.getJedis().get("newname"));}

第二部分:Spring整合


开发中可以单独使用Jedis中相关的方法操作缓存,也可以使用spring提供的相关的注解

1、 在pom.xml中引入相关依赖

<properties>    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>    <spring.version>4.2.3.RELEASE</spring.version>  </properties>  <dependencies>    <dependency>      <groupId>junit</groupId>      <artifactId>junit</artifactId>      <version>4.10</version>      <scope>test</scope>    </dependency>    <dependency>         <groupId>org.springframework</groupId>         <artifactId>spring-test</artifactId>         <version>${spring.version}</version>         <scope>test</scope>     </dependency>     <!-- springframework -->    <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-core</artifactId>        <version>${spring.version}</version>    </dependency>    <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-context</artifactId>        <version>${spring.version}</version>    </dependency>    <dependency>        <groupId>org.springframework.data</groupId>        <artifactId>spring-data-redis</artifactId>        <version>1.8.1.RELEASE</version>    </dependency>    <dependency>        <groupId>redis.clients</groupId>        <artifactId>jedis</artifactId>        <version>2.9.0</version>    </dependency>  </dependencies>

2、在src/main/resources/conf/settings/application.properties下配置redis相关配置

redis.master.ip=localhostredis.master.port=6379redis.pool.maxActive=1024redis.pool.maxIdle=200redis.pool.maxWait=1000redis.pool.testOnBorrow=trueredis.pool.testOnReturn=true

3、在src/main/resources/conf/spring 下配置spring-base.xml和spring-redis.xml

spring-base.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util"       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">    <!-- 加载配置文件数据库连接文件 -->    <context:property-placeholder location="classpath:conf/settings/*.properties" />    <context:component-scan base-package="com.mengdee.**.dao,com.mengdee.**.service"/></beans>

spring-redis.xml

<?xml version="1.0" encoding="UTF-8"?><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:c="http://www.springframework.org/schema/c"       xmlns:cache="http://www.springframework.org/schema/cache"       xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans.xsd       http://www.springframework.org/schema/cache       http://www.springframework.org/schema/cache/spring-cache.xsd">    <!-- 以前项目中的配置,注意需要添加Spring Data Redis等jar包 -->    <description>redis配置</description>    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">        <property name="maxIdle" value="${redis.pool.maxIdle}"/>        <property name="maxTotal" value="${redis.pool.maxActive}"/>        <property name="maxWaitMillis" value="${redis.pool.maxWait}"/>        <property name="testOnBorrow" value="${redis.pool.testOnBorrow}"/>        <property name="testOnReturn" value="${redis.pool.testOnReturn}"/>    </bean>    <!-- JedisConnectionFactory -->    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">        <property name="hostName" value="${redis.master.ip}"/>        <property name="port" value="${redis.master.port}"/>        <property name="poolConfig" ref="jedisPoolConfig"/>    </bean>    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"          p:connectionFactory-ref="jedisConnectionFactory">        <property name="keySerializer">            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>        </property>        <property name="valueSerializer">            <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>        </property>        <property name="hashKeySerializer">            <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>        </property>        <property name="hashValueSerializer">            <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>        </property>    </bean>    <!--spring cache-->    <bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager"          c:redisOperations-ref="redisTemplate">        <!-- 默认缓存10分钟 -->        <property name="defaultExpiration" value="600"/>        <property name="usePrefix" value="true"/>        <!-- cacheName 缓存超时配置,半小时,一小时,一天 -->        <property name="expires">            <map key-type="java.lang.String" value-type="java.lang.Long">                <entry key="halfHour" value="1800"/>                <entry key="hour" value="3600"/>                <entry key="oneDay" value="86400"/>                <!-- shiro cache keys -->                <entry key="authorizationCache" value="1800"/>                <entry key="authenticationCache" value="1800"/>                <entry key="activeSessionCache" value="1800"/>            </map>        </property>    </bean>    <!-- cache注解,和spring-ehcache.xml中的只能使用一个 -->    <cache:annotation-driven cache-manager="cacheManager" proxy-target-class="true"/></beans>

4、Service 类

User

package com.mengdee.manager.entity;import java.io.Serializable;// 一定要实现Serializable,否则报错public class User implements Serializable {    private static final long serialVersionUID = 1L;    private Long id;    private String username;    private int age;    public User() {        super();    }    public User(Long id, String username, int age) {        super();        this.id = id;        this.username = username;        this.age = age;    }    @Override    public String toString() {        return "User [id=" + id + ", username=" + username + ", age=" + age + "]";    }    // getter && setter}

UserService

package com.mengdee.manager.service;import com.mengdee.manager.entity.User;public interface UserService {    public User getUserInfo(String username);    public void deleteUser(String username);    public User updateUser(User user);}

UserServiceImpl

package com.mengdee.manager.service;import org.springframework.cache.annotation.CacheEvict;import org.springframework.cache.annotation.CachePut;import org.springframework.cache.annotation.Cacheable;import org.springframework.stereotype.Service;import com.mengdee.manager.entity.User;@Servicepublic class UserServiceImpl implements UserService {    @Cacheable("users")    @Override    public User getUserInfo(String username) {        System.out.println("从数据库中查询用户信息。。。");        long id = (int)((Math.random()*9+1)*100000);        return new User(id, username, 20);    }    @CacheEvict("users")    @Override    public void deleteUser(String username) {        System.out.println("删除用户:"+username);    }    // 使用@CachePut比许返回要缓存的对象,使用value作为键的前缀(users),使用冒号作为分隔符(:),使用key的值追加到前面的组合,如"users:mengdee"    // 方法的返回值作为键值对的值缓存起来,如果方法没有返回值,那么就相当于没有更新缓存    @CachePut(value="users", key="#user.getUsername()")    @Override    public User updateUser(User user) {        System.out.println("更新用户");        return user;    }}

5、测试

UserServiceTest

package com.mengdee.manager.redis;import org.junit.Test;import org.springframework.beans.factory.annotation.Autowired;import com.mengdee.manager.service.UserService;public class UserServiceTest extends SpringTestCase{    @Autowired    private UserService userService;    @Test    public void testGetUserInfo(){        String username = "mengdee";        // 第一次执行了方法体        userService.getUserInfo(username);        // 第二次没有执行方法体,直接从缓存中获取的        User userInfo = userService.getUserInfo(username);        System.out.println(userInfo); // User [id=565857, username=mengdee, age=20]    }    @Test    public void testDeleteUser(){        String username = "mengdee";        User userInfo = userService.getUserInfo(username);        System.out.println(userInfo);        userService.getUserInfo(username);        userService.deleteUser(username);    }    @Test    public void testUpdateUser(){        String username = "mengdee";        User userInfo = userService.getUserInfo(username);        System.out.println(userInfo);        userInfo.setAge(200);        userInfo.setId(10L);        userService.updateUser(userInfo);        User userInfo2 = userService.getUserInfo(username);        System.out.println(userInfo2);    }}

使用redis-cli可以看到User对象缓存的键是“users:mengdee”, 从中可以看出key的默认规则是@Cacheable中的value值跟冒号分隔,然后跟参数的实际值

这里写图片描述


注意

1、注意配置key的失效时间,既可以野数据的存在,也最大化利用内存,一般不要失效时间配置为永久

2、在使用redis的时候,对于键的命名规则非常重要,常用的做法是实体名字符串跟冒号跟ID值,如“user:1”, “user:2”, 或者其他命名规则在使用Spring的 @Cacheable 的时候更要注意,因为当两个方法的key相同时,两个方法的返回值会相互覆盖,例如以下两个方法

@Cacheable("user")User getUser(String id);@Cacheable("user")User getUserDetail(String id);

当执行第一个方法后换成user对象,再执行第二个方法还会换成user对象,因为这两个方法的key最终生成的是完全一样的,所以第二个方法其实会更新缓存,这两个方法返回虽然都是User对象,很可能返回user对象的字段是不同的,这样在使用user对象时很可能拿不到值,解决方法就是key的生成规则一定不能一样,可以在key的生成规则中加入方法名作为区分,当然这不是一个很好的方式,因为方法名往往是比较长的,key越长越占内存,key应该尽可能的简短来节省内存

原创粉丝点击