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";
}
-----搞定