#数据库# redis入门到实战

- 基本介绍 
	- 为什么会用redi, 为什么大小公司都在用redis
		- 微信红包
		- 微博
		- 淘宝

	- 讲到redis不得不将nosql
		- nosql是不同于传统的关系型数据库管理系统的统称, 其两者最重要的区别是nosql不使用sql作为查询语句
		- noql数据库可以不需要固定的表格模式, noql是基于键值对, 可以想象成表中的主键和值的对应关系
		- nosql: redis, memcached, mongodb, guava(loadingCache)

- redis定义
	- redishi一个开源(BSD许可)的, 内存中的数据结构存储系统, 他可以用作数据库, 缓存和消息中间件, 它支持多种类型的数据结构, 如字符串(strings), 数列(hashes), 列表(lists),集合(sets),有序集合(sorted sets) 等

- 从大家熟悉的mysql出发来认识redis
	- 概念: 关系型数据库的一个长江用法是存储长期的报告数据, 并将这些报告数据用作固定时间范围内的聚合数据, 收集聚合数据的常见做法是: 先将各个行插入一个报告表里面, 之后再通过扫描这些行来收集聚合数据
	- 图解剖析mysql的执行过程(网上自己找图看)

- 分析redis和mencached和mysql之间的区别
	- 从数据库类型, 数据存储方式, 特殊功能讲解redis和mencached和mysql的区别
	- 作为同款功能的内存缓存产品, redis和memcached各有什么优势
		- 内存管理机制
			- mencached默认使用Slab Allocation机制管理内存, 其主要思想按照预先规定的大小, 将分配的内存分割成特定长度的块, 以存储相应长度的key-value数据记录, 以完全解决内容碎片问题, 
			- redis使用现场申请内存的方式来存储数据, 并且很少使用free-list等方式来优化内存分配, 会在一定程度上存在内存碎片
		- 数据持久化方案
			- memcached不支持内存数据的持久化操作, 所有的数据都以in-memory的形式存储
			- redis支持持久化操作, redi提供了两种不同的持久化方法来将数据存储到硬盘里面
				- 第一种是rdb形式: 基于全量护具备份, 备份的是数据
				- 第二种是aof形式: append only if, 增量持久化备份, 备份的是指令 [例如: set key, del key]
		- 缓存数据过期机制
			- mencached在删除失效主键时也是采用消极方法, 即memcached内部也不会见识主键是否失败, 而是在通过get访问主键时才会检查其是否已经失败
			- 定时, 定期等多种缓存失效机制, 减少内存泄露

- redis作为数据库和作为内存缓存的两种使用方法
	- redis作为数据库的使用有什么优缺点:
		- 优点: 没有Schema约束, 数据结构的变更相对容易, 抗压能力强, 性能极高
		- 缺点: 没有索引, 没有外键, 缺少int/date等基本数据类型, 多条件查询需要通过集合内联(sinter, zintertore)和链接间接开发效率低, 可维护性不佳

	- redis作为缓存的左右, 搭配数据库使用的两种方法
		- jedis整合使用方案
			- 第一层在缓存进行查询, 如果得到数据则直接返回
			- 第二层在数据库进行查询, 并且刷新缓存, 方便下次查询
		- 作为mybatis/hibernate二级缓存使用方法	
			- 一级缓存: sqlSession级别, 进程缓存, 单次链接有效

	- 图解分析加redis前后的架构区别		

掌握redis五中数据结构(string,list,set,sortset,hash)

- String: 是最常用的一种数据类型, 普通的key/value存储都可以归为此类
- set/get
	- 设置key对应的值为string类型的value
	- 获取key对应的值
- mget
	- 批量获取多个key的值, 如果可以不存在则返回null
- incr && incrby
	- incr对key对应的值进行加加操作, 并返回新的值; incrby加指定值
- decr && decrby
	- decr对key对应的值进行减减操作, 并返回新的值; decrby减指定值
- sentx
	- 设置key对应的值为String类型的value, 如果key直径存在则返回0
- setex
	- 设置key对应的值为string类型的value, 并设定有效时间
- 其他指令
	- getrange: 获取key对应value的子字符串
	- mset: 数量设置多个key的值, 如果成功表示所有值都被设置, 否则返回0表示没有任何值被设置
	- msetnx, 同mset, 不存在就设置, 不会覆盖已有的key
	- getset: 设置key的值, 并返回key旧的值
	- append: 给指定key的value增加字符串, 并返回新字符串的长度

Hash类型

- Hash类似于HashMap 
	- key / value的形式
	- 格式: Map<String, Map<String, String>>
		- 第一个String 就是 Map<String, String> 的名称

- Hash 是一个String类型的field和value之间的映射类
- redis的Hash数据类型的key(hash表名称)对应的value实际的内部存储结构为一个HashHashMap
- Hash特别适合存储对象
	- 相当于把一个对象的每个属性存储String类型, 将整个对象存储在Hash类型中会占用更少内存.
- 所存储的成员较少时数据存储为zipmap, 当成员数量大时会自动转成真正的HashMap, 此时encoding为ht
- 运用场景:
	- 如用一个对象来存储对象信息, 商品信息, 订单信息等等
- Hash命令讲解:
	- hset: 设置key对应的HashMap中的field的value
	- hget: 获取key对应的HashMap中的field的value
	- hgetall: 获取所有key-value信息
	- hmset: 一次设置多个属性
	- hdel: 删除一个属性
	- hlen: 获取set的长度

LIst数据类型

- lpush: 在key对应的list的头部添加一个元素
- lrange: 获取key对应的list的指定下标范围的元素, -1表示获取所有元素
- lpop: 从key对应的list的头部删除一个元素, 并返回该元素
- rpush: 在key对应的list的尾部添加一个元素
- rpop: 从key对应的list的尾部删除一个元素, 并返回该元素
- lrem: 删除一定个数或者指定的元素
	- lrem list 2 value2 删除两个值为value2的记录
- lindex: 获取指定索引下标的值
- llen: 获取list的长度

set集合

- sadd: 在key对应的set中添加一个元素
- smembers: 获取key对应的set的所有元素
- spop: 随机返回并删除key对应的set中的一个元素
- suion: 求给定key对应的set并集
- sinter: 求给定key对应的set交集
- sdiff: 求给定key对应的set的差集

SortSet讲解

- zadd: 在key对应的zset中添加一个元素
- zrange:  获取key对应的zset中指定范围的元素, -1表示获取所有元素
- zrem: 删除key对应的zset中的一个元素
- zrangebyscore: 返回有序集key中, 指定分户范围的元素列表
- zrank: 返回key对应的zet中指定member的排名, 其中member按score值递增(从小到大), 排名以0为底, 也就是说, score值是最小的成员排名为0
- zcard: 查询sortset有多少个元素(长度)

- set是通过hasmmap存储, key对应et的元素, value是空对象
- sortset是怎么存储并实现排序的呢, hashmap存储, 还加了一层跳跃表
- 跳跃表: 相当于双向链表, 在其基础上添加前往比当前元素大的跳跃链接

redis发布订阅

- 发布订阅作用: 类似于信息管道, 用来进行系统之间消息解耦, 类似于mq, rabbitmq, rocketmq, kafka, activemq, 主要有消息发布者和消息订阅者
- PUBLISH: 将消息message发送到指定的平道channel, 返回收到消息的客户端信息
- SUBSCRIBE: 订阅给指定频道的信息
- UNSUBSCRIBE: 取消订阅指定的频道, 如果不指定, 则取消订阅所有的频道

传统关系型数据库事务

- 一个数据库事务通常包含了一个序列的对数据库的读写操作, 他的存在包含有以下两个目的
	- 为数据库操作序列提供了一个从失联中恢复到正常状态的方法, 同时提供了数据库即使在异常状态下仍然能保持一致性的方法
	- 当多个应用程序在并发访问数据库时, 可以在这些应用程序之间提供一个隔离方法, 以防止彼此的操作互相干扰

- 事务ACID四大特性
	- 原子性(Atomicity): 事务作为一个整体被执行, 包含在其中的对数据库的操作要么全部成功, 要么全部不成功
	- 一致性(Consistency): 事务应该确保数据库的状态从一个状态转变为另一个状态一致
	- 隔离性(Isolation): 多个事务并发执行时, 一个事务的执行不会影响另外一个事务
	- 持久性(Durability): 已经被提交的事务对数据的修改应该是永久保存在数据库中

- 事务隔离机制:
	- read uncommitted 读未提交
	- read committed 读已提交
	- repeatable read 可重复读
	- serializable 串行化

redis事务机制

- MULTI 与 EXEX命令
	- 以MULTI开始一个事务, 然后将多个命令如队列到事务中, 最后由EXEC命令触发事务, 一并执行十五中的所有命令

- DISCARD命令
	- DISCARD命令用于取消一个事务, 他清空客户端整个事务队列, 然后将客户端从事务状态调整回非事务状态, 最后返回字符串OK给客户端, 说明事务已经被取消

- WATCH命令
	- WATCH命令用于在事务开始之前见识任意数量的键. 当调用EXEC命令执行事务时, 如果任意一个被见识的键已经被其他客户端修改了, 那么整个事务不再执行, 直接返回失败.

- 图解redis执行事务过程原理

redis事务与传统关系型事务的比较

- 原子性(Automicity)
	- 单个Redis命令的执行是原子性的, 但Redis没有在事务上增加任何维持原子性的机制, 所以Redis事务的执行并不是原子性的, 如果一个事务队列中的所有命令都被成功的执行, 那么称这个事务执行成功

- 一致性(Consistency)
	- 入队错误
		- 在命令入队的过程中, 如果客户端向服务器发送了错误的命令, 比如命令命令参数数量不对,等等, 那么服务器向客户端返回一个出错信息, 并且将客户端的事务状态设为 REDIS_DIRTY_EXEC

	- 执行错误
		- 如果命令在事务执行的过程中发生错误, 比如说, 对一个不同类型的key执行了错误的错误, 那么Redis只会将错误包含在事务的结果中, 这不会引起事务中断或这个失败, 不会影响已执行事务命令的结果, 也不会影响后续要执行的事务命令, 所以他对事务的一致性也没有影响

- 隔离性(Isolation)
	- WATCH 命令用于在事务开始之前见识任意数量的键, 当调用EXEC命令执行事务时, 如果任意一个被监控的键被其他客户端修改了, 那么整个事务不再执行, 直接返回失败

- 持久性(Durability)
	- 因为事务不过是用队列包裹起了一组Redis命令, 并没有提供任何额外的持久性功能, 所以事务的持久性由redis所使用的持久化模式决定
	- redis持久化模式包括:
		- rdb: 数据内存备份
		- aof(append onlyif增量备份), 每个一秒做一个备份

springboot整合redis

- 引入依赖
	<dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter-data-redis</artifactId>
	    <version>2.1.7.RELEASE</version>
	</dependency>

- 引入bean 
	- redisTemplate的使用, 类似于: mongoTemplate, jdbcTemplate数据库链接工具, RedisTemplate是从redisConnectionFactory中获取的
	- 引入jar包 spring-boot-starter-data-redis

- 实例代码
	- RedisConfig.java
		package cn.jishupeng.redis.config;
		import org.springframework.context.annotation.Bean;
		import org.springframework.context.annotation.Configuration;
		import org.springframework.data.redis.connection.RedisConnectionFactory;
		import org.springframework.data.redis.core.RedisTemplate;
		
		@Configuration
		public class RedisConfig {
		    @Bean
		    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
		        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
		        redisTemplate.setConnectionFactory(redisConnectionFactory);
		        return redisTemplate;
		    }
		}

	- textController.java
		package cn.jishupeng.redis.controller;
		import org.springframework.beans.factory.annotation.Autowired;
		import org.springframework.data.redis.core.RedisTemplate;
		import org.springframework.data.redis.core.StringRedisTemplate;
		import org.springframework.web.bind.annotation.GetMapping;
		import org.springframework.web.bind.annotation.RestController;
		
		import javax.annotation.Resource;
		import java.util.HashMap;
		import java.util.Map;
		
		@RestController
		public class test {
		
		    @Resource
		    private RedisTemplate redisTemplate;
		
		    @GetMapping("/setAndget")
		    public String index(String name) {
		        redisTemplate.opsForValue().set("name", name);
		
		        return (String)redisTemplate.opsForValue().get("name");
		    }
		}
		

redisTemplate api

- opsForValue -> String
- opsForSet -> Set
- opsForHash -> Hash
- opsForZset -> SortSet
- opsForList -> List

springboot快速整合mybatis(极简 mysql版本8.X)

- 加入依赖
	<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.1</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

- 配置application.properties文件
	spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
	spring.datasource.url=jdbc:mysql://localhost:3306/redis?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false&allowP
	spring.datasource.username=root
	spring.datasource.password=123456
	spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

- 启动类加上@MapperScan(basePackage = )注解
	package cn.jishupeng.redis;

	import org.mybatis.spring.annotation.MapperScan;
	import org.springframework.boot.SpringApplication;
	import org.springframework.boot.autoconfigure.SpringBootApplication;
	
	@MapperScan(basePackages = "cn.jishupeng.redis.mapper")
	@SpringBootApplication
	public class RedisApplication {
	
	    public static void main(String[] args) {
	        SpringApplication.run(RedisApplication.class, args);
	    }
	
	}
	
- 创建UserMapper包(该文件下都是接口文件, 每个文件都要加上@Mapper注解, 否则扫描不到)
	package cn.jishupeng.redis.mapper;

	import cn.jishupeng.redis.domain.User;
	import org.apache.ibatis.annotations.Mapper;
	import org.apache.ibatis.annotations.Select;
	
	import java.util.List;
	
	@Mapper
	public interface UserMapper {
	    @Select("select * from user")
	    User find();
	}
	
- domain/User 实体类文件
	package cn.jishupeng.redis.domain;

	import org.springframework.stereotype.Repository;
	
	
	public class User {
	    private int id;
	    private String username;
	
	    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;
	    }
	
	    @Override
	    public String toString() {
	        return "User{" +
	                "id=" + id +
	                ", username='" + username + '\'' +
	                '}';
	    }
	}

- controller/TestController(常规使用, 直接使用@Autowired注入UserMapper文件, 就可以快乐玩耍啦...)
	package cn.jishupeng.redis.controller;

	import cn.jishupeng.redis.mapper.UserMapper;
	import org.springframework.beans.factory.annotation.Autowired;
	import org.springframework.data.redis.core.RedisTemplate;
	import org.springframework.data.redis.core.StringRedisTemplate;
	import org.springframework.web.bind.annotation.GetMapping;
	import org.springframework.web.bind.annotation.RestController;
	
	import javax.annotation.Resource;
	import java.util.HashMap;
	import java.util.Map;
	
	@RestController
	public class test {
	    @Autowired
	    private UserMapper userMapper;
	
	    @Resource
	    private RedisTemplate redisTemplate;
	
	    @GetMapping("/setAndget")
	    public String index(String name) {
	        redisTemplate.opsForValue().set("name", name);
	
	        return (String)redisTemplate.opsForValue().get("name");
	    }
	
	    @GetMapping("/getUser")
	    public String getUser() {
	        return (String)userMapper.find().getUsername();
	    }
	}

redis作为mybatis缓存整合

- 用户第一次访问的时候获取数据库的值, 再次访问时直接从缓存中获取数据
- 设置缓存过期时间
- 项目8080端口是对外端口(向外部暴露的端口), 区别内部进程号, 查内部端口用ps -ef|grep, 查外部端口用 lsof -i:8080

- 缓存级别
	- 一级缓存: sqlSession, sql建立链接到关闭链接的数据缓存
	- 二级缓存: 全局
- springboot cache的使用: 可以结合redis, ehcache等缓存
	- @Cacheable: (查询时使用)来划分可缓存的方法, 即, 结果存储在缓存中的方法, 以便在后续调用(具有相同的参数)时, 返回缓存中的值而不必实际执行该方法
	- @CachePut: (更新时使用)当需要更新缓存而不干扰方法执行时, 可以使用@CachePut注释, 也就是说, 始终执行该方法并将其结果放入缓存中(根据@CachePut选项)
	- @CacheEvict:(删除时使用) 对于从缓存中删除旧或未使用的数据非常有用, 指示缓存范围内的驱逐是否需要执行而不仅仅是一个条目驱逐

- springboot整合cache的步骤
	- 引入依赖 spring-boot-starter-cache
	- 开启缓存注解: @EnableCaching
	- 在方法上面加入SpEL

redis分布式缓存

- 引入依赖: 
		<dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
            <version>2.1.4.RELEASE</version>
        </dependency>
- 加入注解 @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 50)
- controller方法
	package cn.jishupeng.redis.controller;

	import org.springframework.http.HttpRequest;
	import org.springframework.web.HttpRequestHandler;
	import org.springframework.web.bind.annotation.GetMapping;
	import org.springframework.web.bind.annotation.RequestMapping;
	import org.springframework.web.bind.annotation.ResponseBody;
	import org.springframework.web.bind.annotation.RestController;
	
	import javax.servlet.http.HttpServletRequest;
	import java.util.HashMap;
	import java.util.Map;
	
	@RequestMapping("/session")
	@RestController
	public class RedisHttpSession {
	    @RequestMapping("/set")
	    @ResponseBody
	    public Map<String, String> set(HttpServletRequest request) {
	        Map<String, String> ret = new HashMap<>();
	        request.getSession().setAttribute("request Uri", request.getRequestURI());
	        ret.put("request Uri", request.getRequestURI());
	        return ret;
	    }
	
	    @RequestMapping("/get")
	    @ResponseBody
	    public Map<String, Object> get(HttpServletRequest request) {
	        Map<String, Object> ret = new HashMap<>();
	        Object id = request.getSession().getId();
	        ret.put("request Uri", id);
	        return ret;
	    }
	}

- redis客户端中
	- keys * 查找所有的键
	- ttl 查看超时时间

redis项目实战值排行榜实现(上)

- 排行榜
	- 排行榜功能是一个很普遍的需求, 使用redis中有序集合的特性来实现排行榜是又好又快的实现
	- 一般排行榜都是有时效性, 比如""用户积分榜", 游戏中活跃度排行榜, 游戏装备排行榜等等

- 面临问题: 数据库设计复杂, 并发较高, 数据要求实时性高
- redis实现排行榜api讲解

浅谈mysql数据库设计

- 表设计过程中应该注意的点即数据类型
	- 更小的通常更好, 控制字节长度
	- 使用合适的数据类型
		- 如tinyint只占8个位, char与varchar的对比
	- 尽量避免NULL NOT NULL DEFAULT ''
		- NULL的列会让索引统计和值比较都更复杂. 可为NULL的列会占据更多的磁盘空间, 在Mysql中也需要更多复杂的处理程序
	
- 索引设计过程中更应该注意的点
	- 选择唯一性索引
		- 唯一性索引的值是唯一的, 可以更快的通过该索引来确定某条记录
	- 为经常需要排序, 分组和联合操作的字段建立索引
		- 经常需要order by, group by, distinct和union等操作的字段, 排序操作会浪费更多的时间
	- 长作为查询条件的字段建立索引
		- 如果某个字段常用来做查询条件, 那么该字段的查询速度会影响整个表的查询速度
	- 数据少的地方不必建立索引

- sql优化, explain查看执行计划
	- 能够用between的就不要用in
	- 能够用distinct的就不要用group by
	- 避免数据强转
	- 学会采用wxplain查看执行计划
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值