秒杀商城系统 安装与集成Redis (五)

Redis简介

  • redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

  • Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系数据库起到很好的补充作用。

Redis使用建议

我们刚开始学习数据库的时候,可能会用到mysql,,Oracle之类的工具。那么如果没有特殊需求,每次查询数据,就直接写一个SQL语句去这类数据库中查询就好了。干嘛还要很麻烦的搞一个Redis呢?

在项目中使用 Redis,主要考虑两个角度:性能和并发

比如这样一种场景:

  • 执行一个复杂的SQL去数据库中查询,耗时会比较久。而这个结果又不会频繁变动。比如这个SQL是用来查商品信息的,商家做活动的时候很多人都会发起请求去查询,如果不使用redis,那么这么频繁的查询,可能导致每次查询,其响应时间有差异。

  • 此时就可以把查询结果放入redis缓存,使得请求可以快速得到响应。

  • 继续刚才的场景,比如商家的这个活动是秒杀,那么肯定会出现活动开始时,一群人同时去请求数据库查询信息,这就是并发。
    此时大量的查询,如果都涌入数据库,就会受到很大的压力,说不准会被压垮。此时如果使用了redis,请求就可以先到redis,就避免了数据库一下子被涌入的请求压垮。

Window 下安装

注意:现在官网已经没有下载地址,只能在github上下载,官网只提供linux版本的下载

一、下载windows版本的Redis

官网下载地址:http://redis.io/download
window下载地址:https://github.com/MSOpenTech/redis/releases

Redis版本用的是Redis3.2.100,目前网上都是这个版本,笔者推测应该是停止对Window版更新了。

二、安装Redis

  1. 这里下载的是Redis-x64-3.2.100版本,我的电脑是 64位,所以下载64位版本的,在运行中输入cmd,然后把目录指向解压的Redis目录。
  2. 启动命令redis-server redis.windows.conf,出现下图显示表示启动成功了。
    在这里插入图片描述

三、设置Redis服务

  1. 由于上面虽然启动了redis,但是只要一关闭cmd窗口,redis就会消失。所以要把redis设置成windows下的服务。

也就是设置到这里,首先发现是没用这个Redis服务的。

image

  1. 设置服务命令

redis-server --service-install redis.windows-service.conf --loglevel verbose

image
输入命令之后没有报错,表示成功了,刷新服务,会看到多了一个redis服务。

image

  1. 常用的redis服务命令。

卸载服务:redis-server --service-uninstall

开启服务:redis-server --service-start

停止服务:redis-server --service-stop

  1. 启动服务

在这里插入图片描述
出现问题了,这里是解决方案https://www.cnblogs.com/zy-l/p/9408207.html

顺利解决
在这里插入图片描述

5、测试Redis

在这里插入图片描述
安装测试成功。

如果还有什么问题,这篇比较详细,可以参考https://www.cnblogs.com/javabg/p/9133206.html

如何集成Redis

到这里还要了解Jedis的概念

Jedis :jedis就是集成了redis的一些命令操作,封装了redis的java客户端。提供了连接池管理。一般不直接使用jedis,而是在其上再封装一层,作为业务的使用。

添加Jedis依赖

	<dependency>
    	<groupId>redis.clients</groupId>//redis客户端
    	<artifactId>jedis</artifactId>
    	<version>2.7.3</version>
    </dependency>

添加Fastjson依赖

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>fastjson</artifactId>
	<version>1.2.38</version>
</dependency>
添加redis的配置项
#redis  配置服务器等信息
redis.host=127.0.0.1
redis.port=6379
redis.timeout=10
redis.password=123456
redis.poolMaxTotal=1000
redis.poolMaxldle=500
redis.poolMaxWait=500

redis - RedisConfig类

@Component
@ConfigurationProperties(prefix="redis")  	//将application.properties里面前缀redis都读取
@Getter
@Setter
public class RedisConfig {
	private String host;
	private int port;
	private int timeout;
	private String password;
	private int poolMaxTotal;
	private int poolMaxldle;
	private int poolMaxWait;
}

注意:@ConfigurationProperties(prefix=“redis”)指定配置文件里面前缀为"redis"的配置项,与配置项里面的属性对应起来。

redis - RedisPoolFactory类

@Service
public class RedisPoolFactory {

@Autowired
RedisConfig redisConfig;
	
	@Bean   //@Bean是方法的注入注解
	public JedisPool JedisPoolFactory() {	//JedisPool的实例注入到spring容器里面
		JedisPoolConfig poolConfig=new JedisPoolConfig();
		poolConfig.setMaxIdle(redisConfig.getPoolMaxldle());
		poolConfig.setMaxTotal(redisConfig.getPoolMaxTotal());
		poolConfig.setMaxWaitMillis(redisConfig.getPoolMaxWait()*1000);//s-->ms
		//因为我们使用的是s(秒)来配置的,而源码使用的是ms(毫秒),所以转换一下
		JedisPool jp=new JedisPool(poolConfig,redisConfig.getHost(),redisConfig.getPort(),
				redisConfig.getTimeout()*1000,redisConfig.getPassword(),0);
		return jp;
		
	}
}

注意:RedisPoolFactory 通过配置文件,生成Jedis连接池(配置),方便在RedisService中调用。

redis - RedisService类

	@Service
	public class RedisService {
	@Autowired
	JedisPool jedisPool;	//会出现循环依赖---Circular reference  
	//RedisService引用JedisPool--JedisPool在RedisService,只有创建RedisService的实例才可以获取JedisPool的bean
	//所以需要单独拿出JedisPool的bean
	/**
	 * 获取单个对象
	 * @param prefix
	 * @param key
	 * @param data
	 * @return
	 */
	public <T> T get(KeyPrefix prefix,String key,Class<T> data){
		System.out.println("@RedisService-REDIES-GET!");
		Jedis jedis=null;
		//在JedisPool里面取得Jedis
		try {
			jedis=jedisPool.getResource();
			//生成真正的key  className+":"+prefix;  BasePrefix:id1
			String realKey=prefix.getPrefix()+key;
			System.out.println("@RedisService-get-realKey:"+realKey);
			//System.out.println("jedis:"+jedis);
			String sval=jedis.get(realKey);
			System.out.println("@RedisService-getvalue:"+sval);
			//将String转换为Bean入后传出
			T t=stringToBean(sval,data);
			return t;
		}finally {
			returnToPool(jedis);
		}
	}
	
	/**
	 * 移除对象,删除
	 * @param prefix
	 * @param key
	 * @return
	 */
	public boolean delete(KeyPrefix prefix,String key){
		Jedis jedis=null;
		try {
			jedis=jedisPool.getResource();
			String realKey=prefix.getPrefix()+key;
			long ret=jedis.del(realKey);
			return ret>0;//删除成功,返回大于0
			//return jedis.decr(realKey);
		}finally {
			returnToPool(jedis);
		}
	}
	
	/**
	 * 设置单个、多个对象
	 * @param prefix
	 * @param key
	 * @param value
	 * @return
	 */						//MiaoshaUserKey.token, token, user
	public <T> boolean set(KeyPrefix prefix,String key,T value){
		System.out.println("@RedisService-REDIES-SET!");
		Jedis jedis=null;
		try {//在JedisPool里面取得Jedis
			jedis=jedisPool.getResource();
			String realKey=prefix.getPrefix()+key;
			System.out.println("@RedisService-key:"+key);
			System.out.println("@RedisService-getPrefix:"+prefix.getPrefix());
			//System.out.println("set-realKey:"+realKey);
			String s=beanToString(value);//将T类型转换为String类型,json类型??
			//System.out.println("s:"+s);
			if(s==null||s.length()<=0) {
				return false;
			}
			int seconds=prefix.expireSeconds();
			if(seconds<=0) {//有效期:代表不过期,这样才去设置
				jedis.set(realKey, s);
				//System.out.println("1");
			}else {//没有设置过期时间,即没有设置有效期,那么自己设置。
				jedis.setex(realKey, seconds,s);
				//System.out.println("2");
			}
			return true;
		}finally {
			returnToPool(jedis);
			//System.out.println("3");
		}
	}
	/**
	 * 减少值
	 * @param prefix
	 * @param key
	 * @return
	 */
	public <T> Long decr(KeyPrefix prefix,String key){
		Jedis jedis=null;
		try {
			jedis=jedisPool.getResource();
			String realKey=prefix.getPrefix()+key;
			return jedis.decr(realKey);
		}finally {
			returnToPool(jedis);
		}
	}
	/**
	 * 增加值
	 * @param prefix
	 * @param key
	 * @return
	 */
	public <T> Long incr(KeyPrefix prefix,String key){
		Jedis jedis=null;
		try {
			jedis=jedisPool.getResource();
			String realKey=prefix.getPrefix()+key;
			return jedis.incr(realKey);
		}finally {
			returnToPool(jedis);
		}
	}	
	/**
	 * 检查key是否存在
	 * @param prefix
	 * @param key
	 * @return
	 */
	public <T> boolean exitsKey(KeyPrefix prefix,String key){
		Jedis jedis=null;
		try {
			jedis=jedisPool.getResource();
			String realKey=prefix.getPrefix()+key;
			return jedis.exists(realKey);
		}finally {
			returnToPool(jedis);
		}
	}	
	/**
	 * 将字符串转换为Bean对象
	 * 
	 * parseInt()返回的是基本类型int 而valueOf()返回的是包装类Integer  
	 * Integer是可以使用对象方法的  而int类型就不能和Object类型进行互相转换 。
	 * int a=Integer.parseInt(s);
	   Integer b=Integer.valueOf(s);
	 */
	public static <T> T stringToBean(String s,Class<T> clazz) {
		if(s==null||s.length()==0||clazz==null) {
			return null;
		}		
		if(clazz==int.class||clazz==Integer.class) {
			return ((T) Integer.valueOf(s));
		}else if(clazz==String.class) {
			return (T) s;
		}else if(clazz==long.class||clazz==Long.class) {
			return (T) Long.valueOf(s);
		}else {
			JSONObject json=JSON.parseObject(s);
			return JSON.toJavaObject(json, clazz);
		}		
	}
	/**
	 * 将Bean对象转换为字符串类型
	 * @param <T>
	 */
	public static <T> String beanToString(T value) {
		//如果是null
		if(value==null) return null;
		//如果不是null
		Class<?> clazz=value.getClass();
		if(clazz==int.class||clazz==Integer.class) {
			return ""+value;
		}else if(clazz==String.class) {
			return ""+value;
		}else if(clazz==long.class||clazz==Long.class) {
			return ""+value;
		}else {
			return JSON.toJSONString(value);
		}		
	}
	private void returnToPool(Jedis jedis) {
		if(jedis!=null) {	
			jedis.close();
		}
	}
	public <T> boolean set(String key,T value){
		Jedis jedis=null;
		//在JedisPool里面取得Jedis
		try {
			jedis=jedisPool.getResource();
			//将T类型转换为String类型
			String s=beanToString(value);
			if(s==null) {
				return false;
			}
			jedis.set(key, s);
			return true;
		}finally {
			returnToPool(jedis);
		}
	}
	public <T> T get(String key,Class<T> data){
		Jedis jedis=null;
		//在JedisPool里面取得Jedis
		try {
			jedis=jedisPool.getResource();
			System.out.println("jedis:"+jedis);
			String sval=jedis.get(key);
			System.out.println("sval:"+sval);
			//将String转换为Bean入后传出
			T t=stringToBean(sval,data);
			return t;
		}finally {
			returnToPool(jedis);
		}
	}	
}

注意:该类中封装了常用的Redis 方法操作。

public T get(KeyPrefix prefix,String key,Class data) 根据key取得缓存中值(根据传入的前缀)
public boolean delete(KeyPrefix prefix,String key) 删除key
public boolean set(KeyPrefix prefix,String key,T value) 根据key设置缓存中值
public Long decr(KeyPrefix prefix,String key) 自减
public Long incr(KeyPrefix prefix,String key) 自增
public boolean exitsKey(KeyPrefix prefix,String key) 是否存在key
public static T stringToBean(String s,Class clazz)
public static String beanToString(T value)

但是其中,存入redis 的是String类型,这个时候我们的数据不一定是String类型,所以需要类型转换,将数据转换成String格式存入。
BeanToString()这个方法,就是来转化,先获取传入数据的Class类型,根据类型判断,int,long,String 类型,通过API转换直接转换成String即可,或是其他的自定义对象,则利用fastjson库将我们项目中定义的JavaBean 对象,转化为json字符串。
StringToBean() 相当于上个是反方法。都需要传入一个类型,这样才知道将字符串转换为什么对象。

posted @   长勺  阅读(55)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示