最近由于手头项目不多,闲来无事,想去学习下redis。也可能是之前实习(其实现在也是在实习期)找工作很多公司招聘公告上会提及redis,所以兴趣也随之而起。
网上也有许多教学博客,但大多数都是没有贴出项目或者都是需要下载资源去下载的,所以这里给出github的地址,希望大家可以一起学习https://github.com/wx744197705/ssm-redis,话不多说,开始吧。
pom.xml,关键就是spring-data-redis和redis-client包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sl.user</groupId>
<artifactId>redis-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>redis-demo Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- spring版本号 -->
<spring.version>4.2.5.RELEASE</spring.version>
<!-- mybatis版本号 -->
<mybatis.version>3.2.8</mybatis.version>
<!-- mysql驱动版本号 -->
<mysql-driver.version>5.1.29</mysql-driver.version>
<!-- log4j日志包版本号 -->
<slf4j.version>1.7.18</slf4j.version>
<log4j.version>1.2.17</log4j.version>
<kotlin.version>1.2.10</kotlin.version>
</properties>
<dependencies>
<!-- spring mvc related.....start --> <!-- TODO: replace jackson with fastjson -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.1</version>
</dependency>
<!-- spring mvc related.....end -->
<!-- mybatis orm related.....start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.36</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<!-- mybatis orm related.....end -->
<!-- project log related.....start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- project log related.....end -->
<!-- redis cache related.....start -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.6.0.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.7.3</version>
</dependency>
<!-- redis cache related.....end -->
</dependencies>
<build>
<finalName>redis-demo</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
applicationContent.xml ssm、redis配置文件
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="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/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<!-- 扫描dao,service -->
<context:component-scan base-package="com.wxx.jedis.service" />
<context:component-scan base-package="com.wxx.jedis.service.*" />
<context:component-scan base-package="com.wxx.jedis.redis" />
<!-- 启用注解 -->
<context:annotation-config/>
<!-- 启动缓存注解 -->
<cache:annotation-driven/>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:config/jdbc.properties</value>
<value>classpath:config/redis.properties</value>
</list>
</property>
</bean>
<!-- MyBatis start -->
<!-- 配置dataSource DriverManagerDataSource-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test" />
<property name="username" value="root" />
<property name="password" value="5415143" />
</bean>
<!-- MyBatis配置 SqlSessionFactoryBean -->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:config/mybatis.xml" />
<property name="mapperLocations" value="classpath:mapper/UserMapper.xml" />
</bean>
<!-- mybatis自动扫描加载Sql映射文件/接口 : MapperScannerConfigurer
sqlSessionFactory
basePackage:指定sql映射文件/接口所在的包(自动扫描) -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactory" ref="sessionFactory" />
<property name="basePackage" value="com.wxx.jedis.dao" />
</bean>
<!-- 事务管理 DataSourceTransactionManager-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 使用声明式事务 transaction-manager:引用上面定义的事务管理器-->
<tx:annotation-driven transaction-manager="txManager" />
<!-- MyBatis end -->
<!-- 配置redis部分 start -->
<!-- 配置redis连接池 JedisPoolConfig-->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxTotal" value="${redis.maxActive}" />
</bean>
<!-- 配置CoonnectionFactory JedisConnectionFactory-->
<bean id="connFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis.host}" />
<property name="port" value="${redis.port}" />
<property name="poolConfig" ref="poolConfig" />
</bean>
<!-- 配置redisTemplate StringRedisTemplate-->
<bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
<property name="connectionFactory" ref="connFactory"/>
</bean>
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="com.wxx.jedis.redis.RedisCacheConfig">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="User"/>
<!-- User名称要在类或方法的注解中使用 -->
</bean>
</set>
</property>
</bean>
</beans>
mybatis.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 实体类,简称 -设置别名 -->
<typeAliases>
<typeAlias alias="User" type="com.wxx.jedis.domain.User" />
</typeAliases>
</configuration>
springMVC.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:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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-4.0.xsd">
<mvc:annotation-driven/>
<!-- 启用spring mvc 注解 -->
<context:annotation-config/>
<!-- 设置使用注解的类所在的jar包 -->
<context:component-scan base-package="com.wxx.jedis.controller" />
<!-- 对模型视图名称的解析,即在模型视图名称添加前后缀 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<!-- JSON转换器 -->
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=utf-8</value>
<value>text/json;charset=utf-8</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
</beans>
log4j.properties
# Set root category priority to INFO and its only appender to CONSOLE.
log4j.rootCategory=ALL, CONSOLE
#log4j.rootCategory=INFO, CONSOLE, LOGFILE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH\:mm\:ss} %p - %m%n
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
redis.properties
# Redis settings
redis.host=127.0.0.1
redis.port=6379
redis.dbIndex=0
redis.expiration=3000
redis.maxIdle=300
redis.maxActive=600
redis.maxWait=1000
redis.testOnBorrow=true
User.java 实体类,必须要实现Serializable接口,因为这个坑,纠结了好久,一直抛java.io.StreamCorruptedException异常
package com.wxx.jedis.domain;
import java.io.Serializable;
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private Long id;
private String username;
private String password;
private int age;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
userMapper.xml 写sql的配置文件
<?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.wxx.jedis.dao.UserMapper" >
<resultMap id="userResult" type="User">
<result column="id" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="age" property="age"/>
</resultMap>
<insert id="addUser" parameterType="User">
insert into t_user(username,password,age) values(#{username},#{password},#{age})
</insert>
<select id="getUser" parameterType="java.lang.Integer" resultMap="userResult" >
select * from t_user where 1 = 1
<if test="username != null and username != ''">
AND username = #{username}
</if>
</select>
</mapper>
userMapper.java 数据库接口
package com.wxx.jedis.dao;
import com.wxx.jedis.domain.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface UserMapper {
void addUser(User user);
List<User> getUser(@Param("username") String username);
}
UserService.java 服务类
package com.wxx.jedis.service;
import com.wxx.jedis.domain.User;
import java.util.List;
public interface UserService {
void addUser(User user);
List<User> getUser(String username);
}
UserServiceImpl.java 服务实现类,关键的redis缓存就是在这个类里面执行的
package com.wxx.jedis.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.wxx.jedis.dao.UserMapper;
import com.wxx.jedis.service.UserService;
import com.wxx.jedis.domain.User;
import java.util.List;
@Service("userService")
public class UserServiceImpl implements UserService{
@Autowired
private UserMapper userMapper;
/**
* 新增数据直接进入缓存
*
* */
@Override
@Cacheable(value = "User",key = "'addUser'")
public void addUser(User user){
userMapper.addUser(user);
}
/**
* 第一次查询会从数据库取数据,随后进入redis缓存
* 这里的value的我们在xml文件里面定义的name
*
* */
@Override
@Cacheable(value="User",key = "'getUser'")
public List<User> getUser(String username) {
return userMapper.getUser(username);
}
}
UserController.java 控制层
package com.wxx.jedis.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.wxx.jedis.service.UserService;
import com.wxx.jedis.domain.User;
@Controller
@RequestMapping("/userCtrl")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/addUser")
@ResponseBody
public String addUser(User user){
userService.addUser(user);
return "success";
}
@ResponseBody
@RequestMapping("/getUser")
public List<User> getUser(String username){
return userService.getUser(username);
}
}
RedisCacheConfig.java applicationContent.xml文件里面可以找到次类,执行redis缓存的中间类,实现了Spring的缓存接口
package com.wxx.jedis.redis;
import java.io.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
public class RedisCacheConfig implements Cache{
private final Logger logger = LoggerFactory.getLogger(getClass());
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;
}
@Override
public String getName() {
return this.name;
}
@Override
public Object getNativeCache() {
return this.redisTemplate;
}
/**
* 从缓存中获取key
*/
@Override
public ValueWrapper get(Object key) {
logger.info("-----------------------------从redis缓存中读取数据-----------------------------");
final String keyf = key.toString();
Object object;
object = redisTemplate.execute((RedisCallback<Object>) connection -> {
byte[] key1 = keyf.getBytes();
byte[] value = connection.get(key1);
if (value == null) {
return null;
}
return toObject(value);
});
return (object != null ? new SimpleValueWrapper(object) : null);
}
@Override
public <T> T get(Object key, Class<T> type){
logger.info("-----------------------------从redis缓存中读取数据-----------------------------");
final String keyf = key.toString();
T object;
object = redisTemplate.execute((RedisCallback<T>) connection -> {
byte[] key1 = keyf.getBytes();
byte[] value = connection.get(key1);
if (value == null) {
return null;
}
return readToObject(value,type);
});
return object;
}
private ObjectMapper objectMapper = new ObjectMapper();
private <T> byte[] writeToByte(T object) {
try {
return objectMapper.writeValueAsBytes(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
return null;
}
}
private <T> T readToObject(byte[] bytes, Class<T> clazz) {
try {
return objectMapper.readValue(bytes, clazz);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* 将一个新的key保存到缓存中
* 先拿到需要缓存key名称和对象,然后将其转成ByteArray
*/
@Override
public void put(Object key, Object value) {
logger.info("-----------------------------将数据放入redis缓存-----------------------------");
final String keyf = key.toString();
final Object valuef = value;
final long liveTime = 86400;
redisTemplate.execute((RedisCallback<Long>) connection -> {
byte[] keyb = keyf.getBytes();
byte[] valueb = toByteArray(valuef);
connection.set(keyb, valueb);
connection.expire(keyb, liveTime);
return 1L;
});
}
private 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 ex) {
ex.printStackTrace();
}
return bytes;
}
private 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 (IOException | ClassNotFoundException ex) {
ex.printStackTrace();
}
return obj;
}
/**
* 删除key
*/
@Override
public void evict(Object key) {
System.out.println("del key");
final String keyf = key.toString();
redisTemplate.execute((RedisCallback<Long>) connection -> connection.del(keyf.getBytes()));
}
/**
* 清空key
*/
@Override
public void clear() {
System.out.println("clear key");
redisTemplate.execute((RedisCallback<String>) connection -> {
connection.flushDb();
return "ok";
});
}
@Override
public ValueWrapper putIfAbsent(Object key, Object value) {
return null;
}
}
index.jsp
<html>
<body>
<h2>
<form action="${pageContext.request.contextPath}/userCtrl/getUser">
<input type="submit" value="getUser">
</form>
<hr>
<form action="${pageContext.request.contextPath}/userCtrl/addUser" method="post">
username:<input type="text" name="username">
password:<input type="password" name="password">
age:<input type="text" name="age">
<input type="submit" value="addUser">
</form>
</h2>
</body>
</html>
最后,来测试一下把
以查询为例,第一次执行会从数据库读取
![](https://i-blog.csdnimg.cn/blog_migrate/9881231f19a8bd9f9af007c7a15f4e1c.png)
执行后,再次刷新当前页面
![](https://i-blog.csdnimg.cn/blog_migrate/306b4e532ad6b94660a1887c0bb92011.png)
可以看到,没有再执行sql了,说明缓存起到了作用
最后,补充下注解:
@Cacheable 参数 ->value:必须,是我们配置在配置文件里面的那么,我这里配置了User。
key:非必须,指定此方法或者类的缓存的key
condition:触发缓存的条件,只有满足此条件才会返回缓存的结果
@CacheEvict 参数 ->value,key,condition同上
allEntries:默认false,只清除key的值,调用evict方法,为true时,清除所有缓存,忽略key,调用clear 方法。
一般@CacheEvict用在需要对数据库有写操作,恰巧此这部分数据又在缓存中的时候,更新缓存
初学者,有错多包涵