[MySQL] MySQL事务

1.事务有哪些特征 原子性,隔离性,一致性,持久性 原子性:要么全做,要么全不做 隔离性:保证其它的状态转换不会影响到本次状态的转 一致性:数据全部符合现实世界的约束 持久性: 更新后的数据存储到磁盘 InnoDB引擎通过以下技术来保证事务的四个特性 持久性是通过 redo log(重做日志)来保证 原子性是通过 undo log(回滚日志)来保证 隔离性是通过 mvcc(多版本并发控制)或者锁机制来保证 一致性是通过持久性+原子性+隔离性来保证 2.并发事务会引发的问题 MySQL服务端是允许多个客户端连接,这意味着MySQL会出现同时处理多个事务的情况 在同时处理多个事务的时候,可能会出现脏读、不可重复读、幻读的问题 脏读:一个事务读到了另一个未提交事务修改过的数据 不可重复读:在一个事务中多次读取同一个数据,出现前后两次读到的数据不一样的情况 幻读:在一个事务中多次查询某个符合查询条件的记录数量,如果出现前后两次查询到的记录数据不一样的情况 以上三个现象,问题的严重性是 脏读 > 不可重复读 > 幻读 3.事务的隔离级别 四种隔离级别: 读未提交:指一个事务还没有提交时,它做的变更就能被其他事务看到 读提交:指一个事务提交之后,它做的变更才能被其他事务看到 可重复读:指一个事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,MySQL InnoDB引擎的默认隔离级别 串行化:对记录加上读写锁,在多个事务对这条记录进行读写操作时,如果发生读写冲突的时候,后访问的事务必须等前一个事务执行完成 按隔离水平高低排序如下: 串行化 > 可重复读 > 读已提交 > 读未提交 针对不同的隔离级别:并发事务时可能发生的现象也不同 读未提交:脏读、不可重复读、幻读 读提交:不可重复读、幻读 可重复读:幻读 串行化: 可重复读的隔离级别下,可以很大程度上避免幻读现象的发生,所以MySQL不使用串行化隔离级别来避免幻读现象的发生,因为串行化隔离级别会影响性能 InnoDB在默认隔离级别:可重复读的情况下很大程度上解决幻读现象的解决方案有两种: 针对**快照读(普通 select 语句),**是通过MVCC方式解决幻读 针对**当前读(select … for update),**通过next-key lock(记录锁+间隙锁)方式解决了幻读 四种隔离事务是怎么实现的 对于读未提交:可以读到未提交事务修改的数据,所以直接读取就行 对于串行化,通过加读写锁的方式来避免并行访问 对于读提交和可重复读这两种隔离级别的事务,是通过Read View来实现的,它们的区别是在于创建Read View时,读提交隔离级别是在每个语句执行之前都会重新生成一个Read View;而可重复读隔离级别是启动事务时生成一个Read View,然后整个事务都在用这个Read View 在执行开启事务命令,并不意味着启动了事务: 在MySQL中,开启事务有两种命令,分别是: ...

October 27, 2024 · 1 min · Chen-Hang

[redis] 执行流程

四、执行流程 内存结构 核心执行是单线程 多线程负载一些异步任务 1.Redis在内存中是怎么存储的 redis是内存存储,将数据放在redis时,都是以键值对形式存到内存 数据库结构 redisDb代表Redis数据库结构,各种操作对象,都是存储在dict数据结构里 // redisDb 结构 type struct redisDb { dict *dict; //字典 dict *expires; // 过期键 dict *blocking_keys; dict *ready_keys; dict *watched_keys; int id; long long avg_ttl; list *defrag_later; } redisDb; // dict 结构 typedef struct dict { dictType *type; void *privdata; dictht ht[2]; long rehashidx; unsigned long iterators; } dict; redisDb即数据库对象,指向了数据字典,字典包含我们平常存储的k-v数据,v支持任意redis对象 在增加、查询、更新、删除的操作后,分别在内存存储是怎么体现的? 增删改查在Redis内存中的体现 添加数据 即添加键值对,添加到dict结构字典中,Key必须为String对象,value为任何类型的对象 添加数据后,会在redisDb里字段dict上添加dict对象 查询数据 直接在dict找到对应的key,即完成查询 更新数据 对已经Key对象的任何变更操作,都是更新 删除数据 删除即把key和value从dict结构里删除 过期键 Redis可以设置过期键,到达一定时间,这些对象会被自动过期并回收 **过期键存储在expires字典上,**expires字典中,value就是过期时间 在redisDb中,dict和expires中Key对象,实际都是存储String对象指针,两个的key都会指向内存相应的字符串地址 2.Redis是单线程?还是多线程? redis是一个能高效处理请求的组件 核心处理逻辑,Redis一直都是单线程,其他辅助模块会有一些多线程、多进程的功能,例如:复制模块用的多进程;某些异步流程从4.0开始用多线程;网络I/O解包从6.0开始用多线程; 核心处理逻辑:Redis在处理客户端的请求时,包括获取(socket写)、解析、执行、内容返回等都是由一个顺序串行的主线程处理,这就是所谓的单线程 Redis为什么选择单线程 redis的定位是内存k-v存储,是做短平快的热点数据处理,一般来说执行会很快,执行本身不会成为瓶颈,瓶颈通常在网络I/O,处理逻辑多线程并不会有太大收益 同时Redis本身秉持简洁高效的理念,代码的简单性、可维护性是redis一直依赖的追求,执行本身不应该成为瓶颈,而且多线程本身也会引起额外成本 1.多线程引入的复杂度是极大的 多线程引入后,redis原来的顺序执行特性就不复存在,为了事务的原子性、隔离性,redis就不得不引入一些很复杂的实现 redis的数据结构是极其高效,在单线程模式下做了很多特性的优化,如果引入多线程,那么所有底层数据都要改为线性安全,这很复杂 多线程模式使得程序调试更加复杂和麻烦,会带来额外的开发成本及运营成本 2.多线程带来额外的成本 除了引入复杂度,多线程还会带来额外成本,包括 上下文切换成本,多线程调度需要切换线程上下文,这个操作先存储当前线程的本地数据,程序指针,然后载入另一个线程数据,这种内核操作的成本不可忽略 同步机制的开销,一些公共资源,在单线程模式下直接访问就行,多线程需要通过加锁等方式进行同步 一个线程本身也占据内存大小,对redis这种内存数据库来说,内存非常珍贵,多线程本身带来的内存使用的成本也需要谨慎决策 总结 多线程会引入额外的复杂度和成本,而redis是追求简洁高效的存储组件,而且事实也证明,虽然redis是单线程处理架构,redis性能还是经受住了考验 3.Redis单线程为什么能这么快 Redis单线程 Redis核心的请求处理是单线程,但是Redis却能使用单线程模型达到每秒数万级别的处理能力,这是Redis多方面极致设计的一个综合结果 ...

October 27, 2024 · 1 min · Chen-Hang

[MySQL] MySQL索引

1. B+树(索引数据结构) 什么是索引? 为什么索引能加快查询? 索引的数据结构是什么? B+ 树 和(B 树 和 红黑树)有什么区别? 为什么选择 B+树 作为索引数据结构? 为什么Mysql InnoDB选择B+ Tree作为索引? B+ 树 vs B 树 B+ 树只在叶子节点存储数据,B树的非叶子节点也要存储数据,所以B+ 树的单个节点的数据量更小 B+ 树 vs 二叉树 对于有N个叶子节点的B+ 树,搜索复制度为O(logdn) B+ 树 vs Hash 08 索引:排序的艺术 为什么 MySQL 采用 B+ 树作为索引? 2. 索引组织表(索引存储) 堆表和索引组织表有什么区别? 分别应用场景是什么? Mysql InnoDB存储引擎中数据存储方式:索引组织表 数据存储有堆表和索引组织表两种。 堆表中的数据是无序存放的,数据的排序完全依赖索引 索引组织表,数据根据主键进行排序存放在索引中,主键索引也叫聚集索引(Clustered Index) 在索引组织表中,数据即索引,索引即数据 二级索引 InnoDB存储引擎的数据是根据主键索引排序存储的,除了主键索引外,其它的索引都称为二级索引(Secondeary Index),或者非聚集索引 二级索引也是一颗B+树索引,但是它和主键索引不同的是叶子节点存放的是索引键值、主键值 通过二级索引idx_name 只能定位主键值,需要额外再通过主键索引进行查询,才能得到最终结果。 这种二级索引通过主键索引进行再一次查询的操作叫做“回表” 这样的二级索引设计的好处:若记录发生了修改,则其它索引无须进行维护,除非记录的主键发生了修改 在索引组织表中,万物皆索引,索引就是数据,数据就是索引。 二级索引的性能评估 要比较顺序,对聚集索引性能友好 尽可能紧凑,对二级索引的性能和存储友好 函数索引(先了解) … 09 索引组织表:万物皆索引 3.组合索引(联合索引) 联合索引的结构是什么? ...

October 26, 2024 · 2 min · Chen-Hang

[redis] redis 对象

三、对象 Redis Object 是什么? redis是key-value存储,key-value在redis中被抽象为对象(Object),key只能是String对象,value支持丰富的对象类型{String, List, Set, Hash, Sorted Set, Stream…} Object在内存中的样子 #define LRU_BITS 24 typedef struct reidsObject { unsigned type:4; unsigned encoding:4; unsigned lru:LRU_BITS; int refcount; void *ptr; } robj; Type: 查看redis对象 Encoding: 表明使用哪种底层编码 Lru: 记录对象访问信息,用于内存淘汰 Refcount: 引用计数,用来描述有多少指针,指向该对象 Ptr: 内容指针,指向实际内容 对象与数据结果 实际操作的对象有6个Redis对象,他们的底层依赖一些数据对象,包括字符串、跳表、哈希表、压缩列表、双端列表等 1.String String是什么 String是字符串,是Redis中最基本的数据对象,最大为512MB,可以通过配置项proto-max-bulk-len修改它 String可以存储各种类型的字符串(包括二进制文件) 适用场景 使用场景:一般用来存放字节数据、文本数据、序列化****后的对象数据 例子: 缓存场景:Value存Json字符串等信息 计数场景:因为Redis处理命令是单线程,所以执行命令的过程是原子的,因此String数据类型适合计数场景 在redis中怎么使用: 常用操作:创建、查询、更新、删除 创建 –> set, setnx SET key value # 设置一个key值为特定的value set命令扩展参数:EX(键过期时间秒)、PX(键过期时间毫秒)、NX(只有键不存在时才对键进行操作,基本替代下面的SETNX操作)、XX(键存在时才对键进行操作) SETNX key value # 用于在指定的key不存在时,为key设置指定的值 查询 –> get, mget Get key # 查询某个key,存在就返回对应的value,不存在返回nil ...

October 26, 2024 · 4 min · Chen-Hang

[redis] Base理论

Redis的基本概念及其应用场景,并解释了BASE理论

October 25, 2024 · 1 min · Chen-Hang