缓存机制说明:所有的查询结果都放进了缓存,也就是把MySQL查询的结果放到了redis中去,
然后第二次发起该条查询时就可以从redis中去读取查询的结果,从而不与MySQL交互,从而达到优化的效果,
redis的查询速度之于MySQL的查询速度相当于 内存读写速度 /硬盘读写速度

@Cacheable(value=“xxx” key=“zzz”)注解:标注该方法查询的结果进入缓存,再次访问时直接读取缓存中的数据

1.对于有参数的方法,指定value(缓存区间)和key(缓存的key);

对于无参数的方法,只需指定value,存到数据库中数据的key通过com.ssm.utils.RedisCacheConfig中重写的generate()方法生成。

redis缓存并发测试 redis缓存查询结果_缓存


redis缓存并发测试 redis缓存查询结果_redis缓存并发测试_02


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

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;

@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() 对应方法名,可以在com.ssm.utils.RedisCacheConfig中重写generate()方法自定义
     * 	2) NowIds~key 对应注解参数
     */

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

Redisache:

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();
			}
		};
	}
}