![](https://img-blog.csdnimg.cn/20201014180756780.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
进阶
文章平均质量分 92
需要对java有一定的熟练度
析道者
To be or not to be,It's a question.
展开
-
2-3-6-2、undo 日志
事务需要保证原子性,也就是事务中的操作要么全部完成,要么什么也不做。这两种情况都会导致事务执行到一半就结束,但是事务执行过程中可能已经修改了很多东西,为了保证事务的原子性,需要把东西改回原先的样子,这个过程就称之为回滚(英文名:rollback),这样就可以造成这个事务看起来什么都没做,所以符合原子性要求每当要对一条记录做改动时(这里的改动可以指 INSERT、DELETE、UPDATE),都需要把回滚时所需的东西都给记下来。原创 2023-12-25 16:50:05 · 873 阅读 · 0 评论 -
2-3-6-1、redo 日志
在事务的实现机制上,MySQL 采用的是 WAL(Write-ahead logging,预写式日志)机制来实现的在使用 WAL 的系统中,所有的修改都先被写入到日志中,然后再被应用到系统中。通常包含 redo 和 undo 两部分信息redo log 称为重做日志,每当有操作时,在数据变更之前将操作写入 redo log,这样当发生掉电之类的情况时系统可以在重启后继续操作undo log 称为撤销日志,当一些变更执行到一半无法完成时,可以根据撤销日志恢复到变更之间的状态。原创 2023-05-02 17:12:27 · 738 阅读 · 1 评论 -
2-3-5-3、InnoDB 的 Buffer Pool
InnoDB 的内存结构和磁盘存储结构图总结如下:其中的 Insert/Change Buffer 主要是用于对二级索引的写入优化,Undo 空间则是 undo 日志一般放在系统表空间,但是通过参数配置后,也可以用独立表空间存放,所以用虚线表示。原创 2023-04-05 20:45:50 · 354 阅读 · 0 评论 -
2-3-5-1、InnoDB 记录存储结构和索引页结构
InnoDB 是一个将表中的数据存储到磁盘上的存储引擎,所以即使关机后重启数据还是存在的。而真正处理数据的过程是发生在内存中的,所以需要把磁盘中的数据加载到内存中,如果是处理写入或修改请求的话,还需要把内存中的内容刷新到磁盘上InnoDB 采取的方式是:将数据划分为若干个页,以页作为磁盘和内存之间交互的基本单位,InnoDB 中页的大小一般为 16 KB。也就是在一般情况下,一次最少从磁盘中读取 16KB 的内容到内存中,一次最少把内存中的 16KB 内容刷新到磁盘中。原创 2023-03-29 09:08:34 · 206 阅读 · 2 评论 -
2-3-4-4、MySQL的查询重写规则
对于一些执行起来十分耗费性能的语句,MySQL 还是依据一些规则,竭尽全力的把这个很糟糕的语句转换成某种可以比较高效执行的形式,这个过程也可以被称作查询重写。原创 2023-03-17 17:06:45 · 692 阅读 · 0 评论 -
2-3-4-3、InnoDB中的统计数据
查询成本的时候经常用到一些统计数据,比如通过 SHOW TABLE STATUS 可以看到关于表的统计数据,通过 SHOW INDEX 可以看到关于索引的统计数据,在此着重了解下统计数据的由来。原创 2023-03-13 13:36:04 · 312 阅读 · 0 评论 -
2-3-4-2、MySQL的查询成本解析
MySQL 执行一个查询可以有不同的执行方案,它会选择其中成本最低,或者说代价最低的那种方案去真正的执行查询,其实在 MySQL 中一条查询语句的执行成本是由I/O成本和CPU成本组成的。原创 2023-03-06 13:33:56 · 818 阅读 · 0 评论 -
2-3-4-1、索引合并及连接查询
连接的本质就是把各个连接表中的记录都取出来依次匹配的组合加入结果集并返回给用户把 e1 和 e2 两个表连接起来的过程如下图所示:这个过程看起来就是把e1表的记录和e2的记录连起来组成新的更大的记录,所以这个查询过程称之为连接查询。连接查询的结果集中包含一个表中的每一条记录与另一个表中的每一条记录相互匹配的组合,像这样的结果集就可以称之为笛卡尔积。因为表 e1 中有 3 条记录,表 e2 中也有 3 条记录,所以这两个表连接之后的笛卡尔积就有 3×3=9 行记录。原创 2023-03-03 10:09:44 · 413 阅读 · 0 评论 -
2-3-3-3、高性能索引使用策略及了解分区表
索引范围查询越后,就可以过滤掉更多的数据索引范围查询越前,就会导致索引命中越低,甚至不使用索引分区是指根据一定的规则,数据库把一个表分解成多个更小的、更容易管理的部分。就访问数据库的应用而言,逻辑上只有一个表或一个索引,但是实际上这个表可能由数 10 个物理分区对象组成,每个分区都是一个独立的对象,可以独自处理,可以作为表的一部分进行处理。分区对应用来说是完全透明的,不影响应用的业务逻辑分区表是一个独立的逻辑表,但是底层由多个物理子表组成。实现分区的代码实际上是对一组底层表的的封装。原创 2023-03-01 09:17:46 · 90 阅读 · 0 评论 -
2-3-3-2、Explain详解
通过使用 EXPLAIN 关键字可以模拟优化器执行 SQL 查询语句,从而知道MySQL 是如何处理 SQL 语句。表的读取顺序数据读取操作的操作类型哪些索引可以使用哪些索引被实际使用表之间的引用每张表有多少行被优化器查询注意:如果 from 中包含子查询,仍会执行该子查询,将结果放入临时表中。原创 2023-02-28 09:20:49 · 182 阅读 · 0 评论 -
2-3-3-1、MySQL调优分层及慢查询
慢查询日志,顾名思义,就是查询花费大量时间的日志,是指 mysql 记录所有执行超过 long_query_time 参数设定的时间阈值的 SQL 语句的日志。该日志能为 SQL 语句的优化带来很好的帮助。默认情况下,慢查询日志是关闭的,要使用慢查询日志功能,首先要开启慢查询日志功能。原创 2023-02-27 09:57:32 · 197 阅读 · 0 评论 -
2-3-2-5、高性能索引的创建策略
正确地创建和使用索引是实现高性能查询的基础原创 2023-02-24 21:17:56 · 513 阅读 · 0 评论 -
2-3-2-4、索引基础知识补充
InnoDB 中索引即数据,也就是聚簇索引的那棵 B+树的叶子节点中已经把所有完整的用户记录都包含了,而 MyISAM 的索引方案虽然也使用树形结构,但是却将索引和数据分开存储的。每建立一个索引都要为它建立一棵 B+树,每一棵 B+树的每一个节点都是一个数据页,一个页默认会占用 16KB 的存储空间,一棵很大的 B+树由许多数据页组成会占据很多的存储空间。如果有需要的话,也可以对其它的列分别建立索引或者建立联合索引, 原理和 InnoDB 中的索引差不多,不过在叶子节点处存储的是相应的列+行号。原创 2023-02-09 16:13:14 · 194 阅读 · 0 评论 -
2-3-2-3、索引在查询中的作用
由于二级索引记录是先按照 insert_time 列的值进行排序的,所以所有符合 insert_time < '2021-03-22 18:34:55’条件的记录肯定是相邻的,我们可以定位到第一条符合 insert_time < '2021-03-22 18:34:55’条件的记录(其实就是 u_idx_day_status 索引第一个叶子节点的第一条记录),然后沿着记录所在的链表向前扫描,直到某条记录不符合 insert_time < '2021-03-22 18:34:55’为止。原创 2023-02-07 16:29:35 · 355 阅读 · 0 评论 -
2-3-2-2、InnoDB中的索引分类
所以在 InnoDB 存储引擎内部自己去监控索引表,如果监控到某个索引经常用,那么就认为是热数据,然后内部自己创建一个 hash 索引,称之为自适应哈希索引( Adaptive Hash Index,AHI),创建以后,如果下次又查询到这个索引,那么直接通过 hash 算法推导出记录的地址,直接一次就能查到数据,比重复去B+tree 索引中查询三四次节点的效率高了不少。所以,并没有统一的索引标准:不同存储引擎的索引的工作方式并不一样,也不是所有的存储引擎都支持所有类型的索引。聚集索引的叶子节点就是数据页。原创 2023-02-06 17:20:14 · 229 阅读 · 0 评论 -
2-3-2-1、InnoDB的索引结构
叶节点具有相同的深度,叶节点的指针为空所有索引元素不重复节点中的数据索引从左到右递增排列非叶子节点不存储data,只存储索引(冗余),可以放更多的索引叶子节点包含所有索引字段叶子节点用指针连接,提高区间访问的性能。原创 2023-02-03 17:34:31 · 553 阅读 · 0 评论 -
2-3-1-4、表结构设计和数据类型优化
范式来自英文 Normal Form,简称 NF。要想设计—个好的关系,必须使关系满足一定的约束条件,此约束已经形成了规范,分成几个等级,一级比一级要求得严格。满足这些规范的数据库是简洁的、结构明晰的,同时,不会发生插入(insert)、删除(delete)和更新(update)操作异常。反之则是乱七八糟,不仅给数据库的编程人员制造麻烦,而且面目可憎,可能存储了大量不需要的冗余信息。原创 2023-02-02 17:33:59 · 231 阅读 · 0 评论 -
2-3-1-3、事务和事务的隔离级别
事务是数据库管理系统(DBMS)执行过程中的一个逻辑单位(不可再进行分割),由一个有限的数据库操作序列构成(多个 DML 语句),要不全部成功,要不全部不成功DDL (DataDefinitionLanguage)︰数据定义语言,用来定义数据库对象︰库、表、列等DML(DataManipulationLanguage)︰数据操作语言,用来定义数据库记录(数据)DQL (DataQueryLanguage):数据查询语言,用来查询记录(数据)原创 2023-02-01 17:41:37 · 174 阅读 · 0 评论 -
2-3-1-2、MySQL中的目录和文件
这个文件是所谓的自扩展文件,也就是当不够用的时候它会自己增加文件大小,当然,如果你想让系统表空间对应文件系统上多个实际文件,或者仅仅觉得原来的 ibdata1 这个文件名难听,那可以在 MySQL 启动时配置对应的文件路径以及它们的大小,我们也可以把系统表空间对应的文件路径不配置到数据目录下,甚至可以配置到单独的磁盘分区上。表结构就是该表的名称是什么,表里边有多少列,每个列的数据类型是啥,有啥约束条件和索引,用的是啥字符集和比较规则各种信息,这些信息都体现在了建表语句中了。原创 2023-01-31 11:32:42 · 212 阅读 · 0 评论 -
2-3-1-1、MySQL相关变种及体系结构
MySQL 最上层是连接组件。下面服务器是由连接池、管理工具和服务、SQL 接口、解析器、优化器、缓存、存储引擎、文件系统组成可以看出 MySQL 最上层是连接组件。下面服务器是由连接池、管理工具和服务、SQL 接口、解析器、优化器、缓存、存储引擎、文件系统组成。原创 2023-01-30 15:51:23 · 182 阅读 · 0 评论 -
2-2-3-10、并发设计模式
类 Unix 的操作系统中创建进程的 API是 fork(),传统的 fork() 函数会创建父进程的一个完整副本,例如父进程的地址空间现在用到了 1G 的内存,那么 fork() 子进程的时候要复制父进程整个进程的地址空间(占有 1G 内存)给子进程,这个过程是很耗时的。在计算机当中,创建的线程越多,CPU进行上下文切换的成本就越大,所以我们在编程的时候创建的线程并不是越多越好,而是适量即可,采用生产者和消费者模式就可以很好的支持我们使用适量的线程来完成任务。所以在实际工作中,如果写操作非常少(原创 2022-12-29 10:07:02 · 174 阅读 · 0 评论 -
2-2-3-9-2-2、jdk1.8ConcurrentHashMap详解
在高并发的场景下,initTable()方法通过cas(compareAndSwapInt)的机制来保证只有一个线程能够成功初始化。其他线程放弃本次循环的cpu竞争,进行自旋。比如:一个线程本次循环放弃竞争,但是第二次循环又竞争到了cpu,依次叠加,就会导致cpu占有率过高甚至百分之百的问题。CounterCell是一个静态内部类,里面的long属性是通过volatile 修饰,来保证并发是当前类型数据的可见性。和jdk1.8的HashMap一样,使用的是数组+链表+红黑树的结构。原创 2022-12-28 15:32:10 · 531 阅读 · 0 评论 -
2-2-3-9-2-1、jdk1.8HashMap详解
初始化表格是在第一次用到的时候,也就是put值的时候table才会被初始化,这样做有利于减少空间资源的浪费扩容机制的触发是在put元素时发现当前table的中存储的元素达到了临界值,就开始扩容操作,初始化和扩容全部是在resize()方法中实现的树化的阈值是8,而链表化的阈值是6,是因为两者之间如果频繁转换很影响性能,所以当红黑树移除一个元素时不会立即就触发转为链表的操作,提高性能和效率。原创 2022-12-27 14:31:43 · 47 阅读 · 0 评论 -
2-2-3-9-1-2、jdk1.7ConcurrentHashMap详解
DEFAULT_INITIAL_CAPACITY 初始容量 默认值16DEFAULT_LOAD_FACTOR 加载因子DEFAULT_CONCURRENCY_LEVEL 并发级别 默认值16。原创 2022-12-26 16:01:33 · 342 阅读 · 0 评论 -
2-2-3-9-1-1、jdk1.7HashMap详解
为了保证负载因子(loadFactor) * 容量(capacity)的结果是一个整数,这个值是0.75(3/4)比较合理,因为这个数和任何2的幂乘积结果都是整数。从上面的图我们可以看到,因为线程1的 e 指向了 key(3),而 next 指向了 key(7),在线程2 rehash 后,就指向了线程2 rehash 后的链表。因为对数组进行取模的时候可能会遇到获取index的位置是一样的,所以可能会遇到hash碰撞冲突,而HashMap使用链表来存储hash碰撞的元素。很明显,环形链表出现了。原创 2022-12-23 17:34:23 · 910 阅读 · 3 评论 -
2-2-3-8、线程池底层原理详解
线程池中的核心线程数,当提交一个任务时,线程池创建一个新线程执行任务,直到当前线程数等于corePoolSize;如果当前线程数为corePoolSize,继续提交的任务被保存到阻塞队列中,等待被执行;如果执行了线程池的prestartAllCoreThreads()方法,线程池会提前创建并启动所有核心线程。原创 2022-12-22 16:41:28 · 87 阅读 · 0 评论 -
2-2-3-7、Future&CompletableFuture详解
当需要批量提交异步任务的时候建议你使用CompletionService。CompletionService将线程池Executor和阻塞队列BlockingQueue的功能融合在了一起,能够让批量异步任务的管理更简单CompletionService能够让异步任务的执行结果有序化。先执行完的先进入阻塞队列,利用这个特性,你可以轻松实现后续处理的有序性,避免无谓的等待,同时还可以快速实现诸如Forking Cluster这样的需求线程池隔离。原创 2022-12-21 17:26:30 · 381 阅读 · 0 评论 -
2-2-3-6、ForkJoin工作原理分析
Fork/Join是一种基于分治算法的模型,在并发处理计算型任务时有着显著的优势。任务切分:将大的任务分割成更小粒度的小任务,让更多的线程参与执行任务窃取:通过任务窃取,充分地利用空闲线程,并减少竞争在使用ForkJoinPool时,需要特别注意任务的类型是否为纯函数计算类型,也就是这些任务不应该关心状态或者外界的变化,这样才是最安全的做法。如果是阻塞类型任务,那么你需要谨慎评估技术方案。虽然ForkJoinPool也能处理阻塞类型任务,但可能会带来复杂的管理成本。原创 2022-12-19 15:01:29 · 279 阅读 · 1 评论 -
2-2-3-5-5、Disruptor详解
Disruptor是英国外汇交易公司LMAX开发的一个高性能队列,研发的初衷是解决内存队列的延迟问题(在性能测试中发现竟然与I/O操作处于同样的数量级)。基于Disruptor开发的系统单线程能支撑每秒600万订单,2010年在QCon演讲后,获得了业界关注。2011年,企业应用软件专家Martin Fowler专门撰写长文介绍。同年它还获得了Oracle官方的Duke大奖。目前,包括Apache Storm、Camel、Log4j 2在内的很多知名项目都应用了Disruptor以获取高性能。注意,原创 2022-12-12 11:11:38 · 533 阅读 · 0 评论 -
2-2-3-5-3、SynchronousQueue详解
SynchronousQueue是一个没有数据缓冲的BlockingQueue,生产者线程对其的插入操作put必须等待消费者的移除操作take如图所示,SynchronousQueue 最大的不同之处在于,它的容量为 0,所以没有一个地方来暂存元素,导致每次取数据都要先阻塞,直到有数据被放入;同理,每次放数据的时候也会阻塞,直到有消费者来取需要注意的是,SynchronousQueue 的容量不是 1 而是 0,因为 SynchronousQueue 不需要去持有元素,它所做的就是直接传递(direct原创 2022-12-07 15:50:26 · 433 阅读 · 0 评论 -
2-2-3-5-2、LinkedBlockingQueue详解
默认情况下,该阻塞队列的大小为Integer.MAX_VALUE,由于这个数值特别大,所以,代表它几乎没有界限,队列可以随着元素的添加而动态增长,但是如果没有剩余内存,则队列将抛出OOM错误。LinkedBlockingQueue内部由单链表实现,只能从head取元素,从tail添加元素。LinkedBlockingQueue采用两把锁的锁分离技术实现入队出队互不阻塞,添加元素和获取元素都有独立的锁,也就是说LinkedBlockingQueue是读写分离的,读写操作可以并行执行。原创 2022-11-23 08:57:35 · 1105 阅读 · 0 评论 -
2-2-3-5-1、ArrayBlockingQueue详解
在生产者-消费者模型中使用时,;当如果生产速度远远大于消费速度,则会导致队列填满,大量生产线程被阻塞使用独占锁ReentrantLock实现线程安全,入队和出队操作使用同一个锁对象,也就是只能有一个线程可以进行入队或者出队操作;这也就意味着生产者和消费者无法并行操作,在高并发场景下会成为性能瓶颈。原创 2022-11-21 17:23:19 · 121 阅读 · 0 评论 -
2-2-3-5、阻塞队列
所以不同阻塞队列的容量是千差万别的,和它不同的是,LinkedBlockingQueue 的内部是用链表实现的,所以这里就需要我们考虑到,ArrayBlockingQueue 没有链表所需要的“节点”,空间利用率更高。比如说我们开发一个银行转账的程序,那么生产者线程不需要关心具体的转账逻辑,只需要把转账任务,如账户和金额等信息放到队列中就可以,而不需要去关心银行这个类如何实现具体的转账业务。,任务被放在了阻塞队列中,而负责放任务的线程是无法直接访问到我们银行具体实现转账操作的对象的,,直到队列里有数据。原创 2022-11-09 16:04:49 · 163 阅读 · 0 评论 -
2-2-3-4-4、AQS之ReentrantReadWriteLock
对共享资源有读和写的操作,且写操作没有读操作那么频繁(读多写少)。在没有写操作的时候,多个线程同时读一个资源没有任何问题,所以应该允许多个线程同时读取共享资源(读读可以并发);但是如果一个线程想去写这些共享资源,就不应该允许其他线程对该资源进行读和写操作了(读写,写读,写写互斥)。在读多于写的情况下,读写锁能够提供比排它锁更好的并发性和吞吐量针对这种场景,JAVA的并发包提供了读写锁ReentrantReadWriteLock,它内部,维护了一对相关的锁,一个用于只读操作,称为读锁;原创 2022-11-09 09:50:34 · 76 阅读 · 0 评论 -
2-2-3-4-3、AQS之Semaphore&CountDownLatch&CyclicBarrier详解
Semaphore,俗称信号量,它是操作系统中PV操作的原语在java的实现,它也是基于AbstractQueuedSynchronizer实现的Semaphore的功能非常强大,大小为1的信号量就类似于互斥锁,通过同时只能有一个线程获取信号量实现。大小为n(n>0)的信号量可以实现限流的功能,它可以实现只能有n个线程同时获取信号量原创 2022-11-08 09:59:28 · 253 阅读 · 0 评论 -
2-2-3-4-2、AQS之ReentrantLock详解
ReentrantLock是一种基于AQS框架的应用实现,是JDK中的一种线程并发访问的同步手段,它的功能类似于synchronized是一种互斥锁,可以保证线程安全。原创 2022-11-06 18:27:40 · 350 阅读 · 0 评论 -
2-2-3-4-1、AQS详解
AQS(AbstractQueuedSynchronizer)是一个抽象同步框架,可以用来实现一个依赖状态的同步器java.util.concurrent包中的大多数同步器实现都是围绕着共同的基础行为,比如等待队列、条件队列、独占获取、共享获取等,而这些行为的抽象就是基于AQS实现的原创 2022-11-05 18:54:41 · 68 阅读 · 0 评论 -
2-2-3-3、Atomic原子操作类详解
LongAdder的基本思路就是分散热点,将value值分散到一个数组中,不同线程会命中到数组的不同槽中,各个线程只对自己槽中的那个值进行CAS操作,这样热点就被分散了,冲突的概率就小很多。由于计算总和时没有对Cell数组进行加锁,所以在累加过程中可能有其他线程对Cell中的值进行了修改,也有可能对数组进行了扩容,所以sum返回的值并不是非常精确的,其返回值并不是一个调用sum方法时的原子快照值。在并发量较低的环境下,线程冲突的概率比较小,自旋的次数不会很多。原创 2022-11-04 23:10:27 · 548 阅读 · 0 评论 -
2-2-3-2、CAS详解
CAS(Compare And Swap,比较并交换),通常指的是这样一种原子操作:针对一个变量,首先比较它的内存值与某个期望值是否相同,如果相同,就给它赋一个新值以上伪代码描述了一个由比较和赋值两阶段组成的复合操作,CAS 可以看作是它们合并后的整体——一个不可分割的原子操作,并且其原子性是直接在硬件层面得到保障的CAS可以看做是乐观锁(对比数据库的悲观、乐观锁)的一种实现方式,Java原子操作类中的递增操作就通过CAS自旋实现的。原创 2022-11-03 20:24:30 · 618 阅读 · 0 评论 -
2-2-3-1、深入理解Java线程
协程,英文Coroutines, 是一种基于线程之上,但又比线程更加轻量级的存在,协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行),具有对内核来说不可见的特性。这样带来的好处就是性能得到了很大的提升,不会像线程切换那样消耗资源子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。而协程的调用和子程序不同。协程在子程序内部是可中断的,然后转而执行别的子程序,在适当的时候再返回来接着执行。原创 2022-11-02 21:16:01 · 147 阅读 · 0 评论