Redis学习


一、Redis介绍


Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型。内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区。


官网:http://www.redis.io/ 中文官网:http://www.redis.cn/


优点:1.性能极高 – Redis能支持超过 100K+ 每秒的读写频率。2.丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。3.原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。4.丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

二、Redis安装


忽略。。。。。。


我用的是解压版redis。
修改redis数据库配置文件对应修改redis.windows.conf
启动命令redis-server.exe.
命令添加测试数据启动redis-cli.exe

 


1、首先需要再pom.xml中配置Jedis依赖,Jedis是Redis官方首选的Java客户端开发包 ,使用Jedis提供的Java API对Redis进行操作。


<!-- spring-redis实现 -->
   <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-redis</artifactId>
        <version>1.8.7.RELEASE</version>
   </dependency>
<!-- redis客户端jar -->
   <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.9.0</version>
</dependency>


注意:如果报错
nested exception is java.lang.NoClassDefFoundError: org/apache/commons/pool2/impl/GenericObjectPoolConfig
加入这两个jar包 
<dependency>
 <groupId>commons-pool</groupId>
 <artifactId>commons-pool</artifactId>
 <version>1.6</version>
</dependency>
<dependency>
 <groupId>org.apache.commons</groupId>
  <artifactId>commons-pool2</artifactId>
  <version>2.4.2</version>
</dependency>


2、在application.xml配置JedisPoolconfig及JedisPool,存储key,value序列化方式



<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans" 
xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
        http://www.springframework.org/schema/util

        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/task
        http://www.springframework.org/schema/task/spring-task.xsd">
    <!--读取数据库配置 -->
    <context:component-scanbase-package="com.panku.web.*"/>
    <!-- <context:annotation-config /> -->
    <context:property-placeholderlocation="classpath:jdbc.properties,classpath:redis.properties"/>
    <beanid="dataSource"class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
        <propertyname="driverClassName"value="${jdbc.driverClass}"/>
        <propertyname="url"value="${jdbc.jdbcUrl}"/>
        <propertyname="username"value="${jdbc.user}"/>
        <propertyname="password"value="${jdbc.password}"/>
           <!-- 连接池启动时的初始化 -->
         <!-- 连接池启动时的初始化 -->
         <property name="initialSize"value="5"/>
         <!-- 连接池的最大值 -->
        <propertyname="maxActive"value="1000"/>

        <!-- 最小空闲值,当空闲的连接数少于阀值时,连接池就会预申请去一些链接,以免洪峰来时来不及申请-->

        <propertyname="minIdle"value="10"/>

        <!--最大等待连接中的数量,设置为0时,表示没有限制。如果最大空闲值,当经过一个高峰时间后,连接池可以慢慢将已经用不到的链接慢慢释放一部分,一直减少到maxle为止-->

      

<propertyname="maxIdle"value="20"/>
        <!--最大等待秒数,单位为毫秒, 超过时间会报出错误信息 -->
        <propertyname="maxWait"value="10000"/>
        <propertyname="timeBetweenEvictionRunsMillis"value="200"/>
        <!--是否自我中断,默认是 false -->
        <propertyname="removeAbandoned"value="false"/>
        <!--几秒后数据连接会自动断开 -->
        <propertyname="removeAbandonedTimeout"value="600"/>
        <!--是否记录中断事件 默认false -->
        <propertyname="logAbandoned"value="false"/> 
    </bean>

   

<!--配置myBATIS -->
    <beanid="sqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean">
        <propertyname="dataSource">
            <refbean="dataSource"/>
        </property>
        <!--该配置文件用来指定Mapper映射文件的位置 ,映射文件名必须与接口同名 -->
         <propertyname="mapperLocations"value="classpath:com/panku/web/mapper/*.xml"/>
        <!--configLocation属性指定mybatis的核心配置文件-->
         <property name="configLocation"value="classpath:SqlMapConfig.xml"/>
    </bean> 
    <!--Redis和缓存配置开始 -->
     <!-- 配置JedisPool -->
    <beanid="poolConfig"class="redis.clients.jedis.JedisPoolConfig">
        <propertyname="maxIdle"value="${redis.maxIdle}"/> 
         <property name="maxTotal"value="${redis.maxActive}"/>  
         <property name="maxWaitMillis"value="${redis.maxWaitMillis}"/>  
         <property name="testOnBorrow"value="${redis.testOnBorrow}"/>  
    </bean>
    
  <!--  连接池配置,类似数据库连接池 -->
    <beanid="redisConnectionFactory"class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <propertyname="hostName"value="${redis.host}"></property>
        <propertyname="port"value="${redis.port}"></property>
        <propertyname="password"value="${redis.pass}"></property>
        <propertyname="timeout"value="${redis.timeout}"></property>
        <propertyname="poolConfig" ref="poolConfig"></property>
    </bean>
    
    <!--缓存序列化方式 -->
    <!--对key的默认序列化器。默认值是StringSerializer 调用连接池工厂配置-->
     <beanid="redisTemplate"name="redisTemplate"class="org.springframework.data.redis.core.RedisTemplate">
        <propertyname="connectionFactory"ref="redisConnectionFactory"/>
        <propertyname="keySerializer"ref="stringRedisSerializer"/>
        <propertyname="valueSerializer"ref="stringRedisSerializer"/>
        <propertyname="hashKeySerializer"ref="stringRedisSerializer"/>
        <propertyname="hashValueSerializer"ref="jackson2JsonRedisSerializer"/>
         <!-- <propertyname="enableTransactionSupport" value="true"/> -->
    </bean>
    
    <beanid="jdkredisTemplate"name="jdkredisTemplate"class="org.springframework.data.redis.core.RedisTemplate">
        <propertyname="connectionFactory"ref="redisConnectionFactory"/>
        <propertyname="keySerializer"ref="jdkSerializationRedisSerializer"/>
        <propertyname="valueSerializer"ref="jdkSerializationRedisSerializer"/>
        <propertyname="hashKeySerializer"ref="stringRedisSerializer"/>
        <propertyname="hashValueSerializer"ref="jackson2JsonRedisSerializer"/>
    </bean>
    
    <beanid="jacksonredisTemplate"name="jacksonredisTemplate"class="org.springframework.data.redis.core.RedisTemplate">
        <propertyname="connectionFactory"ref="redisConnectionFactory"/>
        <propertyname="keySerializer"ref="jackson2JsonRedisSerializer"/>
        <propertyname="valueSerializer"ref="jackson2JsonRedisSerializer"/>
        <propertyname="hashKeySerializer"ref="stringRedisSerializer"/>
        <propertyname="hashValueSerializer"ref="jackson2JsonRedisSerializer"/>
    </bean>
    
    <beanid="stringRedisSerializer"class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
    <beanid="jackson2JsonRedisSerializer"class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>
    <beanid="jdkSerializationRedisSerializer"class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
   
    <!--Redis和缓存配置结束 -->
    
    <!--自动查找package下的类为它 们 创 建 成 MapperFactoryBean。 -->
    <beanclass="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <propertyname="basePackage"value="com.panku.web.mapper"/>
        <propertyname="sqlSessionFactoryBeanName"value="sqlSessionFactory"></property>
    </bean>
    
    <!--    方便执行自定义的 sql
    <beanid="sqlSession"class="org.mybatis.spring.SqlSessionTemplate"scope="prototype">
        <constructor-argindex="0"ref="sqlSessionFactory"/>
        <constructor-argindex="1"value="BATCH"/>
    </bean>
 
        <!--配置事务管理器 -->
    <beanid="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <propertyname="dataSource"ref="dataSource"/>
    </bean>
 
    <tx:annotation-driventransaction-manager="transactionManager"/>
 
    <!--配置事务的传播特性 -->
    <tx:adviceid="txAdvice"transaction-manager="transactionManager">
        <tx:attributes>
            <tx:methodname="add*"propagation="REQUIRED"isolation="READ_COMMITTED"rollback-for="java.lang.Exception"/>
            <tx:methodname="insert*"propagation="REQUIRED"isolation="READ_COMMITTED"rollback-for="java.lang.Exception"/>
            <tx:methodname="delete*"propagation="REQUIRED"isolation="READ_COMMITTED"rollback-for="java.lang.Exception"/>
            <tx:methodname="remove*"propagation="REQUIRED"isolation="READ_COMMITTED"rollback-for="java.lang.Exception"/>
            <tx:methodname="modify*"propagation="REQUIRED"isolation="READ_COMMITTED"rollback-for="java.lang.Exception"/>
            <tx:methodname="update*"propagation="REQUIRED"isolation="READ_COMMITTED"rollback-for="java.lang.Exception"/>
            <tx:methodname="save*"propagation="REQUIRED"isolation="READ_COMMITTED"rollback-for="java.lang.Exception"/>
            <tx:methodname="get*"propagation="NEVER"read-only="true"/>
            <tx:methodname="find*"propagation="NEVER"read-only="true"/>
            <tx:methodname="*"propagation="NEVER"read-only="true"/>
        </tx:attributes>
    </tx:advice>
 
    <!--那些类的哪些方法参与事务 -->
    <aop:configproxy-target-class="true">
        <aop:pointcutid="allManagerMethod"
expression="execution(*com.panku.*.service..*.*(..))"/>
        <aop:advisorpointcut-ref="allManagerMethod"advice-ref="txAdvice"/>
    </aop:config>
   <!--新增mvc json的支持  hsi6-->
   <mvc:annotation-driven/>
   
    <!--文件上传 -->
    <beanid="multipartResolver" 
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 
        <!-- set the max upload size100MB --> 
        <propertyname="maxUploadSize"> 
            <value>104857600</value> 
        </property> 
        <propertyname="maxInMemorySize"> 
            <value>1638400</value> 
        </property> 
    </bean> 
 
     <beanid="springContextUtil"class="com.panku.web.lisener.ApplicationContextHolder"/>
    <!--定时器 任务配置 -->
    <context:component-scanbase-package="com.panku.web.timer"/>
    <task:executorid="executor"pool-size="5"/>  
    <task:schedulerid="scheduler"pool-size="10"/>  
    <task:annotation-drivenexecutor="executor"scheduler="scheduler"/>
 
</ 
beans 
>

3、在resources中添加redis.properties.配置相关属性

#redisConnectionFactory
redis.host=127.0.0.1
redis.port=6379
redis.pass=
redis.timeout=10000
 
 
#jedisPoolConfig
redis.maxIdle=500
redis.maxActive=50000
redis.maxWaitMillis=10000
redis.testOnBorrow=true
————————————————


IUserMapper.java
package com.panku.web.mapper;
 import org.springframework.stereotype.Repository;
 import com.panku.web.entity.User;
 /**
  * 用户管理dao
  * 
  * @author ccx
  */
 @Repository("userMapper")
 public interface IUserMapper {
     public User getUserById(int id);
     public User updateUser(User user);
     public void deleteUser(int id);
 }
UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.panku.web.mapper.IUserMapper">
     <select id="getUserById" parameterType="int" resultType="user" useCache="true">
         select * from user where id = #{id}
     </select>
 </mapper>


dao层   IRedisUserDao

package com.panku.web.dao;
 import com.panku.web.entity.User;
 public interface IRedisUserDao {
     public User getUserById(int id);
     
     public void setUser(int id,User value);
     
     public void delUser(int id);
     
     public void addDelKey(int id);
     
     public boolean isDeletedKey(int id);
     
     public void addUpdateKey(int id);
     
     //同步缓存至数据库
     public void redisSync();
 }



RedisUserDaoImpl.java(主要处理与redis数据库缓存交互)

package com.panku.web.dao.impl;
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 import javax.annotation.Resource;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.ListOperations;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.core.ValueOperations;
 import org.springframework.stereotype.Service;
 import com.panku.web.dao.IRedisUserDao;
 import com.panku.web.entity.User;
 import com.panku.web.mapper.IUserMapper;
 @Service("redisManager")
 public class RedisUserDaoImpl implements IRedisUserDao{
     @Autowired
     private IUserMapper userMapper;
     @Autowired
     private RedisTemplate<String,Object> redisTemplate;
     //RedisTemplate还提供了对应的*OperationsEditor,用来通过RedisTemplate直接注入对应的Operation。
     @Resource(name = "redisTemplate")
     private ValueOperations<String, Object> vOps;
     
     public User getUserById(int id){
         if(id == 0){
             return null;
         }
         ValueOperations<String, Object> valueOper = redisTemplate.opsForValue();
         Object value = valueOper.get("user:"+id);
         if(value == null||!(value instanceof User)){
             return null;
         }
         return (User)value;
     }
     
     public void setUser(int id,User value){
         if(id == 0||value == null){
             return ;
         }
         ValueOperations< String, Object> valueOper = redisTemplate.opsForValue();
         valueOper.set( "user:"+String.valueOf(id) , value , 48 , TimeUnit.HOURS);//48小时失效
     }
     
     public void delUser(int id){
         redisTemplate.delete("user:"+String.valueOf(id));
     }
     
     public void addDelKey(int id){
         ListOperations<String, Object> listOper = redisTemplate.opsForList();
         listOper.rightPush("to_delete_keys", "user:"+String.valueOf(id));
     }
     
     public boolean isDeletedKey(int id) {
         ListOperations<String, Object> listOper = redisTemplate.opsForList();
         List keys = listOper.range("to_delete_keys", 0, -1);
         if(keys.contains("user:"+String.valueOf(id))){
             return true;
         }
         return false;
     }
     
     public void addUpdateKey(int id){
         ListOperations<String, Object> listOper = redisTemplate.opsForList();
         listOper.rightPush("to_update_keys", "user:"+String.valueOf(id));
     }
     
     //同步缓存至数据库
     public void redisSync(){
         ValueOperations<String, Object> valueOper = redisTemplate.opsForValue();
         ListOperations<String, Object> listOper = redisTemplate.opsForList();
         //同步更新
         List keys = listOper.range("to_update_keys", 0, -1);
         Iterator iterator = keys.iterator();
         while (iterator.hasNext()) {
             String key = (String)iterator.next();
             User user =(User)valueOper.get(key);
             userMapper.updateUser(user);
         }
         redisTemplate.delete("to_update_keys");
         //同步删除
         keys = listOper.range("to_delete_keys", 0, -1);
         iterator = keys.iterator();
         while (iterator.hasNext()) {
             String key = (String)iterator.next();
             userMapper.deleteUser(Integer.parseInt(key.split(":")[1]));
         }
         redisTemplate.delete("to_delete_keys");
         System.out.println("-----redis同步完成------");
     }
 }

service层

IUserService.java
package com.panku.web.service;
 import com.panku.web.entity.User;

 /**
  * 用户管理service
  * 
  * @author ccx
  *
  */
 public interface IUserService {
     public User getUserById(int id);
 }

UserServerImpl.java


package com.panku.web.service.impl;
 import javax.annotation.Resource;

 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.dao.DataAccessException;
 import org.springframework.stereotype.Service;

 import com.panku.web.dao.IRedisUserDao;
 import com.panku.web.entity.User;
 import com.panku.web.mapper.IUserMapper;
 import com.panku.web.service.IUserService;
 /**
  * 用户管理serviceImpl
  * 
  * @author ccx
  *
  */
 @Service("userService")
 public class UserServerImpl implements IUserService {
      @Resource(name = "userMapper")
      private IUserMapper userMapper;
      @Resource(name = "redisManager")
      private IRedisUserDao redisManager;
      @Override
      public User getUserById(int id) {
         User user = null;
         if(redisManager.isDeletedKey(id)){
             return null;
         }
         try{
             user = userMapper.getUserById(id);
             if(user == null){
                 user = userMapper.getUserById(id);
                 redisManager.setUser(id, user);
                 System.out.println("------数据库中取出!");
             }else{
                 System.out.println("------从redis数据库中取出");
             }
         }catch (DataAccessException e) {
             System.out.println(e.getLocalizedMessage());
         }
         return user;
     }
 }



controller测试层


/**
      * 加载用户页面
      * @return
      */
     @RequestMapping(value="load",method=RequestMethod.GET)
     public String load(String id,HttpServletRequest request){
         User user=userService.getUserById(Integer.parseInt(id));
         request.setAttribute("user", user);
         return "test/index";
     }

-----搞定