SSM集成Redis做缓存(含完整Demo)

之前一段时间自学了Redis,进行一下总结

三个部分:

    1. Linux环境下的redis客户端操作

    2. 在java程序中使用redis:

        2.1)导入jedis.jar包
        2.2)直接 Jedis jedis = new Jedis("192.168.80.131", 6379);获取jedis对象,然后进行操作
        2.3)也可以创建jedis连接池JedisPoolUtil,然后需要的时候从连接池中get,使用完release即可

package com.ludada.redis.test;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class JedisPoolUtil {
	// 被volatile修饰的变量不会被本地线程缓存,对该变量的读写都是直接操作共享内存。
	private static volatile JedisPool jedisPool = null;

	// 私有化静态方法,不能new
	private JedisPoolUtil() {};

	//对外提供一个get方法
	public static JedisPool getJedisPoolInstance() {
		if (jedisPool == null) {
			synchronized (JedisPoolUtil.class) {
				if (jedisPool == null) {
					JedisPoolConfig poolConfig = new JedisPoolConfig();
					poolConfig.setMaxActive(1000);
					poolConfig.setMaxIdle(32);
					poolConfig.setMaxWait(100 * 1000);
					poolConfig.setTestOnBorrow(true);

					jedisPool = new JedisPool(poolConfig, "192.168.80.131",6379);
				}
			}
		}
		return jedisPool;
	}
	
	//释放回池子
	public static void release(JedisPool jedisPool,Jedis jedis){
		if(jedis != null){
			jedisPool.returnResourceObject(jedis);
		}
	}
}

    3. 然后是spring整合redis,也就是通过redisTemplate对redis进行操作(底层应该也是调用的jedis):

    3.1)导入spring-data-redis.jar和jedis.jar

    3.2)在spring的配置文件配置redisTemplate

<?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"
	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-4.3.xsd">

	<!-- 连接池配置 -->
	<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
		<!-- 最大空闲数 -->
		<property name="maxIdle" value="50"></property>
		<!-- 最大连接数 -->
		<property name="maxTotal" value="100"></property>
		<!-- 最大等待时间 -->
		<property name="maxWaitMillis" value="20000"></property>
	</bean>
	
	<!-- 配置连接工厂 -->
	<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
		<property name="hostName" value="192.168.80.131"></property>
		<property name="port" value="6379"></property>
		<!-- <property name="password" value=""></property> -->
		<property name="poolConfig" ref="poolConfig"></property>
	</bean>
	
	<!-- 配置 key 和 value 的序列化器 -->
	<bean id="jdkSerializationRedisSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
	<bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
	
	<!-- 配置Redis模板对象 -->
	<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
		<property name="connectionFactory" ref="connectionFactory"></property>
		<property name="keySerializer" ref="stringRedisSerializer"></property>
		<property name="valueSerializer" ref="jdkSerializationRedisSerializer"></property>
	</bean>
	
</beans>

    3.3)使用redisTemplate

package ldd.Spring_Redis;


import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;

public class myTest {

	RedisTemplate redisTemplate = null;
	
	@Before
	public void before(){
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		redisTemplate = ctx.getBean(RedisTemplate.class);
	}
	
	@Test
	public void Test01() {
		Role role = new Role();
		role.setId(1L);
		role.setNote("note_1");
		role.setRoleName("role_name_1");
		
		//存储到到内存中的不是map而是string,进行了序列化
		redisTemplate.opsForValue().set("role_1", role);
		Role role1 = (Role) redisTemplate.opsForValue().get("role_1");
		//上面两步不能保证每次使用RedisTemplate是操作同一个对Redis的连接
		
		System.out.println(role1.toString());
	}
	
	@Test
	public void Test02(){
		final Role role = new Role();
		role.setId(1L);
		role.setNote("note_1");
		role.setRoleName("role_name_1");
		
		SessionCallback callback = new SessionCallback<Role>(){
			public Role execute(RedisOperations ops) throws DataAccessException {
				ops.boundValueOps("role_1").set(role);
				return (Role) ops.boundValueOps("role_1").get();
			}
		};
		Role savedRole = (Role) redisTemplate.execute(callback);
		System.out.println(savedRole.getRoleName());
	}
	

}

4.最后便是今天要说的spring缓存整合redis

环境:jdk 1.8 + tomcat 7 + redis 3.0.4 + spring 4.2 + mybatis 3.3.0

先上demo(maven项目):



UserController:

处理器方法   

     对于数据一致性要求不高的数据,通过redisTemplate进行查找,添加。

    对于数据一致性要求较高的数据,直接调用service层方法。

package com.ssm.controller;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.ssm.pojo.User;
import com.ssm.service.IUserService;

/**
 * user控制器
 * 
 */

@Controller
@RequestMapping("/UserCRUD")
public class UserController {

    @Resource
    private IUserService userService;
    
    @Resource
    private RedisTemplate redisTemplate;
    

    /**
     * 统计注册用户总数
     * @param null
     * @return String
     * @throws Exception 
     */
    
    @RequestMapping("/indexMSG")
    public String getIndexMSG(Model model) throws Exception{
    	String usersCount = null;
    	
    	//尝试从缓存中取数据
    	usersCount = (String) redisTemplate.opsForValue().get("users_count");
    	
    	if(usersCount == null){
    		//redis缓存中无数据,从数据库中查询,并放入redis缓存中,设置生存时间为1小时
    		System.out.println("从数据库中取当前已注册用户数量");
    		usersCount = Integer.toString(userService.selectUsersCount());
    		redisTemplate.opsForValue().set("users_count", usersCount, 1, TimeUnit.HOURS);
    	} else {
    		System.out.println("从redis缓存中取当前已注册用户数量");
    	}
    	
    	List<Integer> ids = null;
    	ids = userService.selectNowIds();
    	
    	model.addAttribute("usersCount", usersCount);
    	model.addAttribute("ids", ids);
    	return "forward:/index.jsp";
    }
    
    /**
     * 通过ID查询User
     * 
     * @param userId
     * @param model
     * @return String
     */
    @RequestMapping(value = "/getUserById", method = RequestMethod.GET)
    public String getUserById(Model model, Integer userId) {
    	System.out.println("**********getUserById********");
    	User user = userService.getUserById(userId);
    	model.addAttribute("user", user); // 填充数据到model
    	return "showUser";
    }
    
    /**
     * 查询所有User
     * 
     * @param request
     * @param model
     * @return
     */
    @RequestMapping(value = "/showUser", method = RequestMethod.GET)
    public String showUsers(Model model) {
        System.out.println("**********showUsers********");
        List<User> userList = new ArrayList<User>();
        userList = userService.getAllUser();
        model.addAttribute("userList", userList); // 填充数据到model
        return "showUser";
    }

    /**
     * 增加一个用户
     * 
     * @param userName
     * @param sex
     * @param age
     * @throws Exception 
     */
    @RequestMapping(value = "/addUser", method = RequestMethod.POST)
    public void addUser(User user, HttpServletResponse response) throws Exception {
        System.out.println("******addUser********");
        User result = userService.insertUser(user);
        if (result.getId() != 0) {
			response.getWriter().print("OK");
		} else {
			response.getWriter().print("FAIL");
		}
    }

    /**
     * 通过userID删除用户
     * 
     * @param userID
     * @throws Exception 
     */
    @RequestMapping(value = "/delUser/{userID}", method = RequestMethod.POST)
    public void delUser(@PathVariable int userID, HttpServletResponse response) throws Exception {
        System.out.println(userID);
        int i = userService.deleteUser(userID);
        if(i == 1){
        	response.getWriter().print("OK");
        }else{
        	response.getWriter().print("删除失败!");
        }
        
    }

    /**
     * 查询用户
     * 
     * @param model
     * @param keyWords
     * @return
     */
    @RequestMapping("/search")
    public ModelAndView findUsers(String keyWords) {
        System.out.println(keyWords);
        ModelAndView mv = new ModelAndView();
        List<User> userList = new ArrayList<User>();
        userList = userService.findUsers(keyWords);
        
        mv.addObject("userList", userList);
        mv.setViewName("showUser");

        return mv;
    }
    
    /**
     * 更新用户信息
     * @param userName
     * @param sex
     * @param age
     * @param id
     * @return
     * @throws Exception 
     */
    @RequestMapping(value="/editUser",method=RequestMethod.POST)
    public void editUser(int id, String name, String sex, int age, HttpServletResponse res) throws Exception {
    	User user = new User();
    	user.setId(id);
    	user.setAge(age);
    	user.setsex(sex);
    	user.setUserName(name);
    	System.out.println(user.toString());
        int rows = userService.editUser(user);
        if(rows == 1){
        	res.getWriter().print("OK");
        } else {
        	res.getWriter().print("FAIL");
        }
    }
    
    
    
    
}






UserMapper.java

package com.ssm.dao;

import java.util.List;
import com.ssm.pojo.User;


public interface UserMapper {

    public User selectByPrimaryKey(Integer userId);

    public List<User> selectAllUser();

    public int insertUser(User user);

    public int deleteUser(int id);

    public List<User> findUsers(String keyWords);

    public int editUser(User user);

    public Integer selectUsersCount();

    public List<Integer> selectIds();
}

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.ssm.dao.UserMapper">
    <resultMap id="BaseResultMap" type="com.ssm.pojo.User">
        <id column="id" property="id" jdbcType="INTEGER" />
        <result column="userName" property="userName" jdbcType="VARCHAR" />
        <result column="sex" property="sex" jdbcType="VARCHAR" />
        <result column="age" property="age" jdbcType="INTEGER" />
    </resultMap>
    <sql id="Base_Column_List">
        id,userName,sex,age
    </sql>
    
    <select id="selectByPrimaryKey" resultMap="BaseResultMap">
    	select
    	<include refid="Base_Column_List" />
    	from tb_user
    	where id = #{userId}
    </select>
    
    <select id="findUsers" resultMap="BaseResultMap" parameterType="String">
        select
        <include refid="Base_Column_List" />
        from tb_user
        where id like #{keyWords}
        or userName like '%' #{keyWords} '%'
        or sex like '%' #{keyWords} '%'
        or age like #{keyWords}
    </select>

    <!-- 查询所有的user -->
    <select id="selectAllUser" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List" />
        from tb_user
    </select>

    <!-- 添加一个用户 -->
    <insert id="insertUser" parameterType="com.ssm.pojo.User" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO
        tb_user(userName,sex,age) VALUES
        (#{userName},#{sex},#{age})
    </insert>

    <!-- 删除用户 -->
    <delete id="deleteUser" parameterType="int">
        DELETE FROM tb_user WHERE
        id=#{id}
    </delete>

    <!-- 更新user信息 -->
    <update id="editUser" parameterType="com.ssm.pojo.User">
        UPDATE tb_user
        <set>
        	<if test="userName != null">
        		userName=#{userName},
        	</if>
        	<if test="sex != null">
        		sex=#{sex},
        	</if>
        	<if test="age != null">
        		age=#{age}
        	</if>
        </set>
        WHERE id=#{id}
    </update>
    
    <select id="selectUsersCount" resultType="Integer">
    	select count(*) from tb_user
    </select>
    
    <select id="selectIds" resultType="Integer">
    	select id from tb_user
    </select>
</mapper>

User.java

需要实现序列化接口

package com.ssm.pojo;

import java.io.Serializable;

/**
 * User实体类对应数据库中的tb_user表
 * 
 */
public class User implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = -5244288298702801619L;
    private int id;
    private String userName;
    private String sex;
    private int age;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getsex() {
        return sex;
    }

    public void setsex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", userName=" + userName + ", sex=" + sex + ", age=" + age + "]";
    }
}

IUserService.java

package com.ssm.service;

import java.util.List;
import com.ssm.pojo.User;

/**
 * user表的操作接口
 * 
 */
public interface IUserService {

	/**
	 * 通过id查询user接口方法
	 * 
	 * @param userId
	 * @return User
	 */
	public User getUserById(Integer userId);

	/**
	 * 查询所有的user
	 * 
	 * @return 返回userList
	 */
	public List<User> getAllUser();

	/**
	 * 添加一个user
	 * 
	 * @param user
	 */
	public User insertUser(User user);

	/**
	 * 通过ID删除用户
	 * 
	 * @param id
	 * @return 
	 */
	public int deleteUser(int id);

	/**
	 * 通过关键字查询用户
	 * 
	 * @param keyWords
	 * @return
	 */
	public List<User> findUsers(String keyWords);

	/**
	 * 更新用户
	 * 
	 * @param user
	 * @return int
	 */
	public int editUser(User user);

	/**
	 * 查询网站注册用户数量(一小时更新一次)
	 * @return Integer
	 */
	public Integer selectUsersCount();

	/**
	 * 查询现有ID
	 * @return List<Integer>
	 */
	public List<Integer> selectNowIds();
}

UserServiceImpl.java

最重要的便是serviceImpl类,

package com.ssm.serviceImpl;

import java.util.List;
import javax.annotation.Resource;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
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.ssm.dao.UserMapper;
import com.ssm.pojo.User;
import com.ssm.service.IUserService;

/**
 * 
 * 缓存机制说明:所有有缓存注解的查询结果都放进了缓存,也就是把MySQL查询的结果放到了redis中去,
 * 然后第二次发起该条查询时就可以从redis中去读取查询的结果,从而不与MySQL交互,从而达到优化的效果,
 * redis的查询速度之于MySQL的查询速度相当于 内存读写速度 /硬盘读写速度
 * 
 * @Cacheable(value="xxx" key="zzz")注解:标注该方法查询的结果进入缓存,再次访问时直接读取缓存中的数据
 * 1.对于有参数的方法,指定value(缓存区间)和key(缓存的key);
 * 	   对于无参数的方法,只需指定value,存到数据库中数据的key通过com.ssm.utils.RedisCacheConfig中重写的generate()方法生成。
 * 2.调用该注解标识的方法时,会根据value和key去redis缓存中查找数据,如果查找不到,则去数据库中查找,然后将查找到的数据存放入redis缓存中;
 * 3.向redis中填充的数据分为两部分:
 * 		1).用来记录xxx缓存区间中的缓存数据的key的xxx~keys(zset类型)
 * 		2).缓存的数据,key:数据的key;value:序列化后的从数据库中得到的数据
 * 4.第一次执行@Cacheable注解标识的方法,会在redis中新增上面两条数据
 * 5.非第一次执行@Cacheable注解标识的方法,若未从redis中查找到数据,则执行从数据库中查找,并:
 * 		1).新增从数据库中查找到的数据
 * 		2).在对应的zset类型的用来记录缓存区间中键的数据中新增一个值,新增的value为上一步新增的数据的key
 */
@Service("userService")
//事务注解
@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)  
public class UserServiceImpl implements IUserService {

    @Resource
    private UserMapper iUserDao;

    /**
     * 根据ID查找user
     * 查到的数据存到users缓存区间,key为user_id,value为序列化后的user对象
     * 
     */
    @Cacheable(value = "aboutUser", key="'user_'+#userId") 
    @Override
    public User getUserById(Integer userId) {
        return iUserDao.selectByPrimaryKey(userId);
    }

    /**
     * 获取所有用户信息
     * 1.对数据一致性要求较高,所以在执行增删改操作后需要将redis中该数据的缓存清空,
     * 从数据库中获取最新数据。
     * 2.若缓存中没有所需的数据,则执行该方法后:
     * 	1).在redis缓存中新增一条数据
     * 		key:getAllUser  value:序列化后的List<User>
     * 		key的值通过com.ssm.utils.RedisCacheConfig中重写的generate()方法生成
     * 	2).在用来记录aboutUser缓存区间中的缓存数据的key的aboutUser~keys(zset类型)中新添加一个value,
     * 	        值为上面新增数据的key
     */
    @Cacheable(value="aboutUser")
    @Override
    public List<User> getAllUser() {
        return iUserDao.selectAllUser();
    }
    
    /**
     * @CacheEvict()注解:移除指定缓存区间的一个或者多个缓存对象
     * @param value + key 或者 value + allEntries=true
     * 1.value + key 移除value缓存区间内的键为key的数据
     * 2.value + allEntries=true 移除value缓存区间内的所有数据
     */
    //@CacheEvict(value= "aboutUser", key="'user_'+#result.id")
    @CacheEvict(value= "aboutUser", allEntries=true)
    @Override
    public User insertUser(User user) {
        iUserDao.insertUser(user);//进行了主键回填
        return user;
    }

    /**
     * 根据id删除用户
     */
    @CacheEvict(value= "aboutUser", allEntries=true)
    @Override
    public int deleteUser(int id) {
        return iUserDao.deleteUser(id);
    }

    /**
     * 根据关键词模糊查询用户,命中率较低,不存入redis缓存中
     */
    @Override
    public List<User> findUsers(String keyWords) {
        return iUserDao.findUsers(keyWords);
    }

    @CacheEvict(value= {"aboutUser"},allEntries=true)
    @Override
    public int editUser(User user) {
        return iUserDao.editUser(user);
    }

    /**
     * 统计当前所有用户ID
     * 1.对数据一致性要求较高,所以在执行增删改操作后需要将redis中该数据的缓存清空,
     * 从数据库中获取最新数据。
     * 2.执行该方法后,在redis缓存中新增一条数据
     * 	1) selectNowIds 缓存的数据的key,可以在com.ssm.utils.RedisCacheConfig中重写generate()方法自定义
     * 3.然后在zset类型的aboutUser中添加一个值,值为上线的key
     */

	@Cacheable(value = "aboutUser")
	@Override
	public List<Integer> selectNowIds() {
		return iUserDao.selectIds();
	}
	
	/**
	 * 统计注册用户个数
	 * 	对数据一致性要求不高,所以在controller中使用redisTemplate存入redis,
	 * 并指定生存时间为1小时
	 */
	@Override
	public Integer selectUsersCount() {
		return iUserDao.selectUsersCount();
	}
}

RedisCacheConfig.java

    重写的generate()方法为那些需要将数据存入缓存的无参的方法指定存入缓存中的数据的key,可以根据需求自己设计。

package com.ssm.utils;

import java.lang.reflect.Method;

import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * 通过spring管理redis缓存配置
 * 
 * @author Administrator
 *
 */
@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {
	private volatile JedisConnectionFactory jedisConnectionFactory;
	private volatile RedisTemplate<String, String> redisTemplate;
	private volatile RedisCacheManager redisCacheManager;

	public RedisCacheConfig() {
		super();
	}

	/**
	 * 带参数的构造方法 初始化所有的成员变量
	 * 
	 * @param jedisConnectionFactory
	 * @param redisTemplate
	 * @param redisCacheManager
	 */
	public RedisCacheConfig(JedisConnectionFactory jedisConnectionFactory, RedisTemplate<String, String> redisTemplate,
			RedisCacheManager redisCacheManager) {
		this.jedisConnectionFactory = jedisConnectionFactory;
		this.redisTemplate = redisTemplate;
		this.redisCacheManager = redisCacheManager;
	}

	public JedisConnectionFactory getJedisConnecionFactory() {
		return jedisConnectionFactory;
	}

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

	public RedisCacheManager getRedisCacheManager() {
		return redisCacheManager;
	}

	@Bean
	public KeyGenerator keyGenerator() {
		return new KeyGenerator() {
			@Override
			public Object generate(Object target, Method method, Object... objects) {
				StringBuilder sb = new StringBuilder();
				//sb.append(target.getClass().getName());
				sb.append(method.getName());
				if(objects.length != 0){
					sb.append("_");
					for (Object obj : objects) {
						sb.append(obj.toString());
					}
				}
				return sb.toString();
			}
		};
	}
}

applicationContext.xml

重点在缓存区间的配置,对应缓存注解中指定value的值;如不进行配置可value可以随意写,但是如果进行了配置value只能等于已配置的值

<?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:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:cache="http://www.springframework.org/schema/cache"
	xsi:schemaLocation="http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.2.xsd
		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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
        
    <!-- class annotation related... start -->
    <context:component-scan base-package="com.ssm.serviceImpl" />
    <context:component-scan base-package="com.ssm.utils" />
    <!-- class annotation related... end -->
    <!-- mybatis related... start -->
    <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>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://${jdbc.host}:${jdbc.port}/${jdbc.database}?useUnicode=true&characterEncoding=utf8" />
        <property name="user" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="acquireIncrement" value="1" />
        <property name="initialPoolSize" value="5" />
        <property name="maxPoolSize" value="20" />
        <property name="minPoolSize" value="5" />
        <property name="maxStatements" value="100" />
        <property name="testConnectionOnCheckout" value="true" />
    </bean>

    <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!-- 自动扫描mapping.xml文件 <property name="mapperLocations" value="classpath:com/ssm/mapper/*.xml"></property> -->
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.ssm.dao" />
    </bean>
    <!-- mybatis related... end -->

    <!-- transaction config related... start -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- transaction config related... end -->

    <!-- redis config start -->
    <!-- 配置JedisPoolConfig实例 -->
    <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>

    <!-- 配置JedisConnectionFactory -->
    <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="password" value="${redis.pass}" /> -->
        <property name="database" value="${redis.dbIndex}" />
        <property name="poolConfig" ref="poolConfig" />
    </bean>

	<bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>

    <!-- 配置RedisTemplate -->
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="jedisConnectionFactory" />
        <property name="hashKeySerializer" ref="stringRedisSerializer"/>
        <property name="keySerializer" ref="stringRedisSerializer"/>
    </bean>

    <!-- 配置RedisCacheManager -->
    <bean id="redisCacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
        <constructor-arg name="redisOperations" ref="redisTemplate" />
        <property name="defaultExpiration" value="${redis.expiration}" />
        <!-- 配置缓存区间 -->
        <property name="cacheNames">
        	<list>
        		<value>aboutUser</value>
        	</list>
        </property>
    </bean>

	<!-- 配置RedisCacheConfig -->
	<bean id="redisCacheConfig" class="com.ssm.utils.RedisCacheConfig">
		<constructor-arg ref="jedisConnectionFactory"/>
		<constructor-arg ref="redisTemplate"/>
		<constructor-arg ref="redisCacheManager"/>
	</bean>

    <!-- redis config end -->
</beans>

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:p="http://www.springframework.org/schema/p"    
    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-3.1.xsd      
                        http://www.springframework.org/schema/context      
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd      
                        http://www.springframework.org/schema/mvc      
                        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">    
    <!-- class annotation related... start 
    <context:component-scan base-package="com.ssm.controller" />
     class annotation related... end 
     -->
     <!-- 添加注解驱动  使用注解标注的类生效-->      
    <mvc:annotation-driven />
    <!-- 设置能访问静态资源 -->    
    <mvc:default-servlet-handler/>
    <!--扫描controller-->
    <context:component-scan base-package="com.ssm.controller" />    

    <!-- jsp page related... start -->
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
    <!-- jsp page related... end -->

    <!-- rest json related... start -->
    <bean id="mappingJacksonHttpMessageConverter"
        class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
        <property name="supportedMediaTypes">
            <list>
                <value>application/json;charset=UTF-8</value>
            </list>
        </property>
    </bean>

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="mappingJacksonHttpMessageConverter" />
            </list>
        </property>
    </bean>
    <!-- rest json related... end -->
</beans>

jdbc.properties

jdbc.host=127.0.0.1
jdbc.database=user
jdbc.port=3306
jdbc.username=root
jdbc.password=111

log4j.properties

# Global logging configuration
log4j.rootLogger=WARN,stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c:%L - %m%n
# mybatis log
log4j.logger.com.ssm.dao.UserMapper=DEBUG
# lyz log
log4j.logger.com.ssm.controller=DEBUG
log4j.logger.com.ssm.service=DEBUG

redis.properties

# Redis settings  
redis.host=192.168.80.132
redis.port=6379  
#redis.pass=password
redis.dbIndex=0  
redis.expiration=3000  
redis.maxIdle=300  
redis.maxActive=600  
redis.maxWait=1000  
redis.testOnBorrow=true

showUser.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>show user</title>
<!-- 屏幕和设备的屏幕一致,初始缩放为1:1,禁止用户缩放 -->
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/css/bootstrap.min.css">
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container-fluid">
	<div class="row">
		<div class="col-md-2">
			<h1>showUser</h1>
		</div>
		<div class="col-md-10">
			<br>
			<button class="btn btn-success" onclick="javascript:history.back(-1);">返回上一页</button>
		</div>
	</div>
	<hr>
	<div class="row">
		<div class="col-md-2">
			<c:if test="${empty userList && empty user}">
				<p class="text-warning">未查找到用户信息!</p>
			</c:if>
		</div>
	</div>
	<div class="row">
		<div class="col-md-3">
			<div class="table-responsive">
				<table class="table table-bordered table-hover table-striped table-condensed">
					<c:if test="${requestScope.user != null }">
						<tr>
							<td>id</td>
							<td>userName</td>
							<td>sex</td>
							<td>age</td>
						</tr>
						<tr>
							<td>${user.id }</td>
							<td>${user.userName }</td>
							<td>${user.sex }</td>
							<td>${user.age }</td>
						</tr>
					</c:if>
					<c:if test="${requestScope.userList != null }">
						<tr>
							<td>id</td>
							<td>userName</td>
							<td>sex</td>
							<td>age</td>
						</tr>
						<c:forEach items="${userList }" var="user">
							<tr>
								<td>${user.id }</td>
								<td>${user.userName }</td>
								<td>${user.sex }</td>
								<td>${user.age }</td>
							</tr>
						</c:forEach>
					</c:if>
				</table>
			</div>
		</div>
	</div>
</div>
</body>
</html>

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>SSM-Redis</title>
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/css/bootstrap.min.css">
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/bootstrap.min.js"></script>
</head>
<script type="text/javascript">
	function addUser(){
		var name = $("#userName");
		var sex = $("#sex");
		var age = $("#age");
		var msg = "";
		
		if ($.trim(name.val()) == ""){
			msg = "姓名不能为空!";
			name.focus();
		}else if ($.trim(sex.val()) == ""){
			msg = "性别不能为空!";
			sex.focus();
		}else if($.trim(age.val()) == ""){
			msg = "年龄不能为空!";
			age.focus();
		}
		
		if(msg != ""){
			alert(msg);
			return false;
		} else {
			$.post("${pageContext.request.contextPath}/UserCRUD/addUser",
					$("#addForm").serialize(),function(data){
						if(data == "OK"){
							alert("添加成功!");
							//window.location.href="${pageContext.request.contextPath}/UserCRUD/showUser";
							//jQuery没有reset方法,jq对象需要调用dom对象的js方法
							$("#addForm")[0].reset();
							window.location.reload();
						} else {
							alert("添加失败!");
							return false;
						}
				});
		}
	}
	function update(){
		var ids = new Array();
		<c:forEach items="${ids}" var="id">  
			ids.push("${id}");  
    	</c:forEach> 
		var id = $("#mdf_id");
		var name = $("#mdf_userName");
		var sex = $("#mdf_sex");
		var age = $("#mdf_age");
		var flag = false;//标识ID是否有效
		//var flag2 = false;//标识信息是否有效
		
		if($.trim(id.val()) == ""){
			alert("请指定要更改用户的ID!");
			id.focus();
			return false
		} else {
			for(var i=0;i<ids.length;i++){
				if($.trim(id.val()) == ids[i]){
					flag = true;
				}
			}
			if(flag==false){
				alert("输入的ID不存在")
				id.focus();
				return false;
				}
		}
		
		if($.trim(name.val()) == "" && $.trim(sex.val()) == "" && $.trim(age.val()) == ""){
			alert("未进行修改");
			return false;
		} else {
			$.post("${pageContext.request.contextPath}/UserCRUD/editUser",
					{
						id:id.val(),
						name:name.val(),
						sex:sex.val(),
						age:age.val()
					},
					function(data){
						if(data == "OK"){
							alert("信息修改成功!");
							window.location.href="${pageContext.request.contextPath}/UserCRUD/search?keyWords=" + $.trim(id.val());
						} else {
							alert("信息修改失败!");
							return false;
						}
				});
		}
		
	}
	function searchByKeyWords(val) {
		window.location.href = "${pageContext.request.contextPath}/UserCRUD/search?keyWords=" + val;
	}
	function showUsers() {
		window.location.href = "${pageContext.request.contextPath}/UserCRUD/showUser";
	}
	function getUserById(val) {
		window.location.href = "${pageContext.request.contextPath}/UserCRUD/getUserById?userId=" + val;
	}
	function deleteById(id){
		var UID = $("#UID");
		var flag = false;
		if(id == null || id == ""){
			alert("请输入id!");
			UID.focus();
	    	return false;
		}
		var ids = new Array();
		<c:forEach items="${ids}" var="id">  
			ids.push("${id}");  
    	</c:forEach> 
    	for(var i=0;i<ids.length;i++){
            if(id == ids[i]){
            	flag = true;
            	$.post("${pageContext.request.contextPath}/UserCRUD/delUser/" + id,
						   function(data){
	 						  if(data == "OK"){
	 								alert("用户删除成功!");
	 								//window.location.href="${pageContext.request.contextPath}/UserCRUD/showUser";
	 								UID.val("");
	 								window.location.reload();
	 							} else {
	 								alert(data);
	 								return false;
	 							}
				   });
            }
        }
    	if(flag == false){
	    	alert("请输入正确的id!");
	    	UID.focus();
    	}
    	return false;
	}
	$(function (){
		var text = $("#num").text();
		if(text==null || text == ""){
			window.location.href="${pageContext.request.contextPath}/UserCRUD/indexMSG";
		}
		$("#userName").focus();
	})
</script>
<body style="background: #333">
	<h3>
		<span style="color:#FFFFFF">当前注册用户数量(一个小时更新一次):</span>
		<a id="num" href="${pageContext.request.contextPath}/UserCRUD/showUser">${usersCount }</a>
	</h3>
	<hr>
	<div class="container-fluid" style="background-color: #fff">
		<div class="col-md-2">
			<h2 class="page-header">增</h2>
			<form id="addForm" action="" method="post">
				<div class="form-group">
					<label for="userName">姓名</label><span style="color:red"> *</span>
					<input type="text" name="userName" id="userName" placeholder="UserName" class="form-control">
				</div>
				<div class="form-group">
					<label for="sex">性别</label><span style="color:red"> *</span>
					<input type="text" name="sex" id="sex" placeholder="UserSex" class="form-control">
				</div>
				<div class="form-group">
					<label for="age">年龄</label><span style="color:red"> *</span>
					<input type="text" name="age" id="age" placeholder="UserAge" class="form-control">
				</div>
			</form>
			<div class="text-right">
				<button class="btn btn-info" onclick="return addUser();">
					<span class="glyphicon glyphicon-plus"></span> 添加用户
				</button>
			</div>
		</div>
		<div class="col-md-3">
			<h2 class="page-header">删</h2>
			<p class="text-muted">现有ID(${fn:length(ids)}个):</p>
			<p class="text-success">
				<c:forEach items="${ids }" var="id">
					<a href="${pageContext.request.contextPath}/UserCRUD/getUserById?userId=${id }">${id } </a>
				</c:forEach>
			</p>
			<div class="form-inline">
				<div class="form-group">
					<div class="input-group">
						<span class="input-group-addon">UID:</span>
						<input type="text" name="UID" id="UID" placeholder="填入上方ID" class="form-control">
					</div>
				</div>
				<button class="btn btn-info" onclick="return deleteById($('#UID').val());">
					<span class="glyphicon glyphicon-remove"></span> 删除
				</button>
			</div>
		</div>
		<div class="col-md-3">
			<h2 class="page-header">改</h2>
			<form id="updateForm" action="" method="post">
				<div class="form-group">
					<label for="id">UID</label><span style="color:red"> *</span>
					<input type="text" name="mdf_id" id="mdf_id" placeholder="要修改用户ID" class="form-control">
				</div>
				<div class="form-group">
					<label for="mdf_userName">姓名</label> 
					<input type="text" name="mdf_userName" id="mdf_userName" placeholder="留空则不进行更改" class="form-control">
				</div>
				<div class="form-group">
					<label for="mdf_sex">性别</label> 
					<input type="text" name="mdf_sex" id="mdf_sex" placeholder="留空则不进行更改" class="form-control">
				</div>
				<div class="form-group">
					<label for="mdf_age">年龄</label> 
					<input type="text" name="mdf_age" id="mdf_age" placeholder="留空则不进行更改" class="form-control">
				</div>
			</form>
			<div class="text-right">
				<button class="btn btn-info" onclick="return update();">
					<span class="glyphicon glyphicon-refresh"></span> 更新信息
				</button>				
			</div>
		</div>
		<div class="col-md-4">
			<h2 class="page-header">查</h2>
			<button class="btn btn-info" onclick="showUsers();">查找全部</button><br><br>
			<div class="form-inline">
				<div class="form-group">
					<div class="input-group">
						<span class="input-group-addon">关键字:</span>
						<input type="text" name="keyWords" id="keyWords" class="form-control">
					</div>
				</div>
				<button class="btn btn-info" onclick="searchByKeyWords($('#keyWords').val());">
					<span class="glyphicon glyphicon-search"></span> 查找
				</button>
			</div>
			<br>
			<div class="form-inline">
				<div class="form-group">
					<div class="input-group">
						<span class="input-group-addon">UserID:</span>
						<input type="text" name="ById" id="ById" class="form-control">
					</div>
				</div>
				<button class="btn btn-info" onclick="getUserById($('#ById').val());">
					<span class="glyphicon glyphicon-search"></span> 查找
				</button>
			</div>
		</div>
	</div>
</body>
</html>

pom.xml

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>ldd</groupId>
  <artifactId>SSMRedisDemo</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>SSMRedisDemo Maven Webapp</name>
  <url>http://maven.apache.org</url>
  
	<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.version>4.2.0.RELEASE</spring.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>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <warSourceDirectory>WebContent</warSourceDirectory>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

效果图:


然后简述一下Demo数据需求:

    数据库很简单,只有一个user表,属性有自增的ID,字符串类型的用户名、性别,整型的年龄。

对于Demo中需求的数据分为两种:

    一种是对一致性要求不高的,比如说页面头部的统计当前注册用户的总数,所以对于这种类型的数据,使用redisTemplate进行读取,先从redis中读取,读取不到的话就从数据库中读取,然后存放入redis缓存中,并设置生存时间,比如说1小时。

    另一种是对一致性要求较高的,比如说现有的ID,因为这个ID列表需要输出到首页,供删除用户或者修改用户信息时参考,所以像这种不需要设置生存时间的数据,直接使用spring缓存放入redis中即可,然后执行增删改的时候,清空对应缓存即可。

缓存注解:

    执行到serviceImp时,如果方法的上面有@Cacheable、@CachePut、@CacheEvict注解时,则表示该方法需要spring缓存管理,简单说一下这三个注解,

@Cacheable:表明在进入方法之前,Spring会先去缓存服务器中查找对应key的缓存值,如果找到缓存值,那么Spring将不会再调用方法,而是将缓存值独处,返回给调用者;如果没有找到缓存值,那么Spring就会执行你的方法,将最后的结果通过key保存到缓存服务器中。

@CachePut:表明Spring会将该方法返回的值缓存到缓存服务器中,这里需要注意的是,Spring不会事先去缓存服务器中查找,而是直接执行方法,然后缓存。换句话说,该方法始终会被Spring所调用。

@CacheEvict:表示执行方法后从缓存服务器移除对应key的值;

一般而言,对于查询,我们会考虑@Cacheable;对于插入和修改我们会考虑使用@CachePut;对于删除,我们会考虑@CacheEvict;

具体的使用方法可以请参考spring文档:

https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#cache-annotations


完整Demo下载  密码zb03


仅用于学习记忆与总结,如有错误的地方还请各位指出。

阅读更多

没有更多推荐了,返回首页