自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

I wanna be myself, where I Belong.

Java开发工程师,持续学习Java技术栈相关技术.

  • 博客(140)
  • 收藏
  • 关注

原创 【剑指 Offer 40】最小的k个数

因为是输出最小的 k 个数,索引从 0 开始,所以当基准数为 k+1 小的数时,这个基准数的左边子数组就是我们要找的 k 个数,也就是基准数索引为 k 时。例如,输入 4、5、1、6、2、7、3、8 这 8 个数字,则最小的 4 个数字是 1、2、3、4。若 k < 基准数索引 ,代表第 k+1 小的数字在 左子数组 中,则递归左子数组。若 k > 基准数索引 ,代表第 k+1 小的数字在 右子数组 中,则递归右子数组。输入:arr = [0,1,2,1], k = 1。输出:[1,2] 或者 [2,1]

2023-08-09 09:58:05 912

原创 【剑指 Offer 39】数组中超过一半的数字

遍历数组,是众数 +1,不是众数 -1,为 0 就接着继续重新来。数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]使用一个 map,key 存数组中的数字,val 存出现的次数。众数和非众数投票,初始票数为 0,为 0 时假设当前数字为众数。将数组排序,出现次数超过一半的数字肯定在数组中间的那个位置。你可以假设数组是非空的,并且给定的数组总是存在多数元素。当有数字出现次数超过数组长度一半时,直接返回。

2023-08-09 09:56:38 763

原创 【剑指 Offer 32】从上到下打印二叉树 II

循环拿出队列中现有的所有结点,也就是本层节点,共 queue.size() 个,采用 i–的方式循环,因为队列在不停出队,长度是变化的。拿出每一个结点加入到一个 list,即本层的索引结点,然后判断本层节点的左右结点是否存在,存在就加入到对列中,为下层的节点。从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。题目要求从上到下按层打印二叉树,也就是二叉树的广度优先搜索(BFS)将本层节点的 list 加入到结果集合,开始下层循环。头结点先入队(需要先判断头结点不为空,防止空指针)

2023-08-07 11:11:33 197

原创 【剑指 Offer 27】二叉树的镜像

root 的左右结点都为空,代表这棵子树只有根结点了,不需要交换直接返回。先出栈 node,如果 node 的左右子结点哪个不为空,就入栈,然后交换 node 的左右子结点。请完成一个函数,输入一个二叉树,该函数输出它的镜像。输入:root = [4,2,7,1,3,6,9]先 new 一个辅助栈,将头结点入栈,然后开始循环。二叉树的镜像,就是交换二叉树的每个节点的左右结点。栈其实就是遍历所有节点,然后交换左右子节点。递归是自下而上交换,栈是自上而下进行交换。输出:[4,7,2,9,6,3,1]

2023-08-03 10:25:27 138

原创 【剑指 Offer 25】 合并两个排序的链表

输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。因为 l1,l2 都是递增的,我们可以从头比较,交替的拿出每次较小的头结点。当其中一个链表被全部拿出时,另一个可以直接连接在新链表的后边。因为要存放新的顺序,可以定义一个虚拟的辅助结点。输入:1->2->4, 1->3->4。输出:1->1->2->3->4->4。最后从辅助结点的下一个开始返回即可。

2023-08-02 10:07:41 186

原创 【剑指 Offer 22】链表中倒数第 k 个节点

可以使用快慢指针,开始快慢指针都指向 head 结点,先让快指针走 k 步,然后快慢指针一块走,当快指针为空时,慢指针指向的就是该链表中倒数第 k 个节点。题目要输出该链表中倒数第 k 个节点,第一时间想到计算链表的长度 n,然后从头开始走 n-k 步,得到的结点就是该链表中倒数第 k 个节点。例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。输入一个链表,输出该链表中倒数第 k 个节点。为了符合大多数人的习惯,本题从 1 开始计数,即链表的尾节点是倒数第 1 个节点。

2023-08-01 10:05:09 74

原创 剑指offer-11-旋转数组的最小数字(Java)

请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为 1。注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]]。把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入:numbers = [3,4,5,1,2]输入:numbers = [2,2,2,0,1]

2023-07-17 10:41:28 308

原创 剑指offer-06-从尾到头打印链表

想要用数组倒序存储链表,如果知道长度的话,可以利用索引很简单的存入;输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。:利用递归,走到链表的末尾,在回溯时保存结点,即实现倒序;输入:head = [1,3,2]:利用栈先进后出的特性;输出:[2,3,1]

2023-07-11 08:48:25 183

原创 剑指offer-03-数组中重复的数字

数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。:数组长度n中数字范围为0~n-1,可以想到 数组元素的 索引 和 值 是 一对多 的关系,每次将数字n换到索引n位置,nums[n] == n时重复;:找任意一个重复数字,那我就找第一个重复的,数组是无序的,需要排序,循环比较 i 和 i+1 个数字,相等输出nums[i];:很容易想到HashSet,不能存在相同的数,可以再添加前进行contains判断,已存在直接返回;找出数组中重复的数字。

2023-07-11 08:45:46 297

原创 如何在项目中自定义注解实现权限数据管理案例

这里的思路很简单,就是根据权限,动态的给你的SQL后边追加过滤条件。创建一个实体类BaseEntity,里边是一个map叫做params,key就是data_scope,value就是要追加的SQL。然后让每个实体类都继承这个BaseEntity,接口参数传入实体类。利用AOP前置通知给map中放一个SQL语句,mapper中用==${params.data_scope}==追加实现功能。} }让所以的实体类继承上边的BaseEntity。

2023-05-15 08:50:35 540 1

原创 防止表单重复提交的几种方式,演示一个自定义注解方式的实现

将当前请求的地址参数缓存起来,下次再来一个请求时,去判断和缓存中的请求是否完全一样,一样的话并且小于规定的时间间隔,则认为是重复提交。我们现在要使用拦截器拦截请求缓存的地址参数等信息,但是如果请求参数为JSON,拦截器拦截之后,接口就无法再一次获取了,所以先要解决这个问题。如何解决请求参数为JSON时,采用IO流读取,只能请求一次的问题?

2023-05-11 08:55:12 1792 2

原创 如何解决请求参数为JSON时,采用IO流读取,只能请求一次的问题?

当客户端发送一个参数为JSON的请求时,我现在想使用拦截器先将它拦截并缓存起来,但是发现拦截器拦截之后,请求就无法再一次获取到数据,如下

2023-05-10 12:24:47 551

原创 手把手实现项目中自定义动态数据源?

使用一个小例子演示一下自定义动态数据源的步骤。

2023-05-09 10:45:01 396

原创 如何在项目中实现登录时的验证码校验功能?

【代码】如何在项目中实现登录时的验证码校验功能?

2023-05-08 11:20:15 554

原创 项目结构如何改造(利用RuoYi-Vue脚手架开发一个健身房会员管理系统,改造项目结构)

记录一下利用RuoYi-Vue脚手架开发一个健身房会员管理系统项目结构改造的过程,虽然不难但是没弄过很容易出问题,记录一下。

2023-05-06 16:10:56 775

原创 MySQL高级第十七篇:数据库主从复制原理及保证数据一致性

在实际工作中,我们常常将Redis作为缓存与MySQL来配合使用,当有请求的时候,首先会从缓存中进行查找,如果存在就直接取出,如果不存在再访问数据库。这样就提升了读取的效率,也减少了对后端数据库的访问压力。此外,对于一般数据库应用而言,都是读多写少的,当数据库读取数据压力较大时,我们可以从成本较小的方案开始优化,可以首先考虑优化SQL和索引,其次就是缓存策略,最后才是主从架构。

2023-04-24 23:01:29 1795

原创 MySQL高级第十六篇:数据库日志有哪些(慢查询日志、通用查询日志、错误日志和二进制日志)

慢查询日志:记录所有执行时间超过long_query_time的所有查询,方便我们对查询进行优化。通用查询日志:记录所有连接的起始时间和终止时间,以及连接发送给数据库服务器的所有指令,对我们复原操作的实际场景、发现问题,甚至是对数据库操作的审计都有很大的帮助。错误日志:记录MySQL服务的启动、运行或停止MySQL服务时出现的问题,方便我们了解服务器的状态,从而对服务器进行维护。二进制日志:记录所有更改数据的语句,可以用于主从服务器之间的数据同步,以及服务器遇到故障时数据的无损失恢复。

2023-04-23 22:35:05 1221

原创 MySQL高级第十五篇:MVCC多版本并发控制原理剖析

MVCC(Multiversion Concurrency Control)多版本并发控制。就是通过数据行的多个版本管理来实现数据库的并发控制。这项技术使得在InnoDB的事务隔离级别下执行一致性读操作有了保证。换句话说,就是为了查询一些正在被另一个事务更新的行,并且可以看到它们被更新之前的值,这样在做查询的时候就不用等待另一个事务释放锁。本篇介绍了MVCC在READ COMMITTD、REPEATABLE READ这两种隔离级别的事务在执行快照读操作时访问记录的版本链的过程。

2023-04-22 15:02:17 719

原创 MySQL高级第十四篇:锁机制分类详解(表锁,行锁,页锁,悲观锁和乐观锁)

事务的隔离性就是由锁来实现。锁是计算机协调多个进程或线程并发访问某一资源的机制。和在开发中加锁以保证数据的一致性一样,这个思想在数据库领域中同样很重要。在数据库中,数据是一种供许多用户共享的资源,为保证数据的一致性,需要对并发操作进行控制,因此产生了锁。同时锁机制也为实现MySQL的各个隔离级别提供了保证。

2023-04-20 22:00:52 608

原创 MySQL高级第十三篇:MySQL事物日志(redo日志-undo日志执行流程)

事务有4种特性:原子性、一致性、隔离性和持久性。事务的隔离性由锁机制实现,而事务的 原子性、一致性和持久性 由事务的 redo日志 和 undo日志 来保证。REDO LOG : 重做日志,提供再写入操作,恢复提交事务修改的页操作,用来保证事务的持久性。UNDO LOG : 回滚日志,回滚行记录到某个特定版本,用来保证事务的原子性、一致性。REDO 和 UNDO 都可以视为是一种恢复操作,区别如下:redo log:是存储引擎层(innodb)生成的日志,记录的是物理级别。

2023-04-12 23:00:55 907

原创 MySQL高级第十二篇:数据库事物概述和隔离级别

事物:一组逻辑操作单元,使数据从一种状态变成另一种状态,这一组逻辑操作要么全部成功,要么全部放弃。ACID是事务的四大特性,在这四个特性中,原子性是基础,隔离性是手段,一致性是约束条件,而持久性是我们的目的。

2023-04-11 21:29:55 425

原创 MySQL高级第十一篇:数据库调优策略(定位-调优-结构)

另外,表的规范化程度越高,表与表之间的关系就越多,需要连接查询的情况也就越多。尤其在数据量大,而且需要频繁进行连接的时候,为了提升效率,我们也可以考虑增加冗余字段来减少连接。通过建立中间表,把需要经常联合查询的数据插入中间表中,然后将原来的联合查询改为对中间表的查询,以此来提高查询效率。对于需要经常联合查询的表,可以建立中间表以提高查询效率。索引相关问题前边几章节已经详细剖析过,这里不在赘述。Redis支持持久化。

2023-04-09 21:58:21 497

原创 MySQL高级第十篇:数据库设计三范式与表设计原则

有的时候不能简单按照规范要求设计数据表,因为有的数据看似冗余,其实对业务来说十分重要。这个时候,我们就要遵循业务优先的原则,首先满足业务需求,再尽量减少冗余。如果数据库中的数据量比较大,系统的UV和PV访问频次比较高,则完全按照MySQL的三大范式设计数据表,读数据时会产生大量的关联查询,在一定程度上会影响数据库的读性能。如果我们想对查询效率进行优化,反范式优化也是一种优化思路。此时,可以通过在数据表中增加冗余字段来提高数据库的读性能。

2023-03-30 21:29:46 817

原创 MySQL高级第九篇:覆盖索引和索引条件下推等相关策略

索引是高效找到行的一个方法,但是一般数据库也能使用索引找到一个列的数据,因此它不必读取整个行。毕竟索引叶子节点存储了它们索引的数据,当能通过读取索引就可以得到想要的数据时,那就不需要读取行了。一个索引包含了满足查询结果的数据就叫做覆盖索引。非聚簇复合索引的一种形式,它包括在查询里的SELECT、JOIN和WHERE子句用到的所有列(即建索引的字段正好是覆盖查询条件中所涉及的字段)。简单说就是,索引列+主键包含SELECT到FROM之间查询的列。

2023-03-28 10:11:18 1045

原创 MySQL高级第八篇:关联查询、子查询和排序相关优化

子查询是MySQL的一项重要的功能,可以帮助我们通过一个SQL语句实现比较复杂的查询。但是,子查询的执行效率不高。,即一个SELECT查询的结果作为另一个SELECT语句的条件。,其速度比子查询要快,如果查询中使用索引的话,性能就会更好。在MySQL中,可以使用连接(JOIN)查询来替代子查询。使用子查询可以进行SELECT语句的。大大增加了1O的次数。

2023-03-27 08:47:48 1354

原创 MySQL高级第七篇:什么情况下会导致索引失效?

MySQL中提高性能的一个最有效的方式是对数据表设计合理的索引。索引提供了高效访问数据的方法,并且加快查询的速度,因此索引对查询的速度有着至关重要的影响。使用索引可以快速地定位表中的某条记录,从而提高数据库查询的速度,提高数据库的性能。如果查询时没有使用索引,查询语句就会扫描表中的所有记录,在数据量大的情况下,这样查询的速度会很慢。大多数情况下都(默认)采用B+树来构建索引。其实用不用索引,最终都是优化器说了算。优化器是基于什么的优化器?基于cost开销。

2023-03-26 14:58:14 575

原创 MySQL高级第六篇:数据库性能分析与优化

1.观察服务器状态,看是否存在周期性波动,是的话可以尝试加缓存或者调整缓存失效策略;2.否则考虑开启慢查询日志,找出比较慢的SQL语句;3.分析SQL语句:EXPLAIN,SHOW PROFILE4.如果是因为SQL等待时间比较长,考虑调整服务器参数;5.如果是因为SQL执行时间比较长,考虑优化索引、SQL语句本身或者表设计;6.如果以上都不能解决,考虑是否SQL查询达到瓶颈7.这时需要考虑读写分离,分库分表等。定位了查询慢的SQL之后,就可以。

2023-03-25 18:13:43 702

原创 MySQL高级第五篇:索引的创建与设计原则

1.唯一性约束的字段2.频繁使用where查询的字段3.经常GROUP BY 和 ORDER BY 的列4.UPDATE,DELETE 时的 where 条件列5.DISTINCT的字段6.多表JOIN连接时创建索引注意连接表的数量尽量不超过3张,每加一张表就相当于嵌套一次循环对 where 条件创建所以用于连接的字段创建索引7.尽量给数据类型小的列添加索引,节省空间,让一页存在更多记录,比较速度页更快8.使用区分度高的列作为索引。

2023-03-19 16:38:19 451

原创 MySQL高级第四篇:InnoDB存储结构之页、区、段和表空间

我们都知道,索引信息以及数据记录都是保存在文件上的,确切说是存储在页结构中,并且索引是在存储引擎中实现的,存储引擎负责对表中数据的读取和写入工作。

2023-03-16 23:53:59 1266

原创 MySQL高级第三篇:Hash索引,AVL树,B树和B+树对比

Hash本事是一个函数,可以帮助我们大大提高检索效率,因为它。非叶子节点仅用于索引。B+树查询效率更稳定。B+树的查询效率更高。

2023-03-14 23:10:22 458

原创 MySQL高级第二篇:索引的分类及MyISAM与InnoDB中的索引对比

这个很简单,每个页只存储一条的话,完全没有什么效果,连树的结构都不能形成。针对主键构建的索引,聚簇即数据行和相邻的键值存储在一起。聚簇索引并不是一种单独的索引类型,而是一种。,即所有的用户记录都存储在了叶子结点,可以有多个非聚簇索引。同时为多个列建立索引。

2023-03-13 23:03:08 311

原创 MySQL高级第一篇:索引的来源,优缺点及B+树的演化

当记录一个页放不下时,会存放在多个页中,以双向链表连接,但无论几个页,主键ID都要保持递增,如果插入顺序不是按递增主键插入,会发生记录移动,以保持这种结构,多个页中的这种行为称为页分裂。当多个页查询时,我们难以定位到数据在哪一个页,只能从第一页开始遍历,基于这种情况,考虑可以给所有的页建立一个目录项,让目录项连续依次递增,每个目录项记录页的最小记录和页号。1,随着页的越来越多,目录项也越来越多,而目录项存储在连续的空间,页越来越多,空间压力也越来越大;2,数据页的增删使得目录项也需要增删,很不方便。

2023-03-12 17:50:58 806

原创 JUC并发编程第十四篇,StampedLock(邮戳锁)为什么比ReentrantReadWriteLock(读写锁)更快!

首先获取读锁,如果cache不可用,则释放读锁,获取写锁,在更改数据之前,再检查一次cacheValid的值,然后修改数据,将cacheValid置为true,然后在释放写锁前获取读锁;但是,当读锁被使用时,如果有线程尝试获取写锁,该写线程会被阻塞,需要释放所有读锁,才可获取写锁。当stamp返回零时,表示线程获取锁失败,并且,当释放锁或者转换锁的时候,都要传入最初获取的stamp值。StampedLock采取乐观获取锁后,其他线程尝试获取写锁时不会被阻塞,在获取乐观读锁后,还需要对结果进行校验。

2022-12-16 15:42:03 379

原创 JUC并发编程第十三篇,AQS的作用与体系结构

这个机制主要用的是CLH队列的变体实现的,将暂时获取不到锁的线程加入到队列中,这个队列就是AQS的抽象表现,它将请求共享资源的线程封装成队列的结点(Node),通过CAS、自旋以及 LockSupport.park() 的方式,维护state变量的状态,使并发达到同步的效果。AQS使用一个volatile的 int 类型的成员变量来表示同步状态,通过内置的 FIFO 队列来完成资源获取的排队工作,将每条要去抢占资源的线程封装成一个Node节点来实现锁的分配,通过CAS完成对State值的修改。

2022-12-15 15:07:28 370

原创 JUC并发编程第十二篇,详解Synchronized与锁升级

我们都知道,用锁能够保证数据的安全性,但是会带来性能下降;无锁能够基于线程并行提升程序性能,但是会带来安全性问题,为了达到两着的平衡,于是就有了多种锁的实现和锁升级。经过上一节的了解,我们知道了synchronized锁根据对象头中的 Mark Word 中的锁标志位的不同而区分,这一节来学习锁有哪几种类型以及是如何升级的。

2022-12-14 16:19:16 384

原创 JUC并发编程第十一篇,Java对象的内存布局

对象头分为对象标记(markOop)和类元信息(klassOop),类元信息存储的是指向该对象类元数据(klass)的首地址。虚拟机要求对象起始地址必须是8字节的整数倍。填充数据不是必须存在的,仅仅是为了字节对齐,这部分内存按8字节补充对齐。它会根据对象的状态复用自己的存储空间,在运行期间 MarkWord 里存储的数据会随着锁标志位的变化而变化。对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。对象标记中都保存了什么?Hotspot实现(64位)

2022-12-13 15:05:49 362

原创 JUC并发编程第十篇,谈谈ThreadLocal原理与内存泄露的那些事儿

1、ThreadLocal 不是解决线程间共享数据问题的,而是用于 变量在线程间隔离且在方法间共享的场景。2、它隐式的在不同线程内创建独立实例副本,避免了实例线程的安全问题。3、每个线程持有一个只属于自己的Map,维护了ThreadLocal对象与具体实例的映射,该Map只能被持有它的线程访问,故不存在线程安全以及锁的问题。4、ThreadLocalMap 的 Entry 对 ThreadLocal 的引用为弱引用,避免了 ThreadLocal 对象无法被回收的问题。

2022-12-12 15:33:38 287

原创 JUC并发编程第九篇,原子操作类分类解析,LongAdder为什么这么快原理分析?

LongAdder在无竞争的情况,跟AtomicLong一样,对同一个base进行操作,当出现竞争关系时则是采用化整为零的做法,从空间换时间,用一个数组cells,将一个value拆分进这个数组cells。LongAdder的基本思路就是分散热点,将value值分散到一个Cell数组中,不同线程会命中到数组的不同槽中,各个线程只对自己槽中的那个值进行CAS操作,这样热点就被分散了,冲突的概率就小很多。携带版本号的引用类型原子类,可以解决ABA问题,可以记录修改过几次。

2022-12-08 16:40:56 439

原创 JUC并发编程第八篇,谈谈你对CAS的理解?自旋锁,CAS底层原理和存在的问题?

CAS是JDK提供的非阻塞原子性操作,它通过硬件保证比较-更新的原子性,效率更高且更可靠。compareAndSet 底层源码经过查看源码,找到这几个方法,存在于一个叫UnSafe的类中,UnSafe类是什么呢?Unsafe是CAS的核心类,由于Java方法无法直接访问底层系统,需要通过本地(native)方法来访问,Unsafe相当于一个后门,基于该类可以直接操作特定内存的数据。Unsafe类存在于sun.misc包中,其内部方法操作可以像C的指针一样直接操作内存,Java中CAS的操作执行依赖

2022-12-06 23:29:17 208

原创 JUC并发编程第七篇,volatile凭什么可以保证可见性和有序性?我们该如何正确使用它?

内存屏障是一种同步屏障指令,是CPU或编译器在对内存随机访问操作中的一个同步点,目的是为了保证此点之前的所有读写操作都执行完,然后才可以开始执行此点之后的操作,避免代码重排序。内存屏障其实就是一种JVM指令,Java内存模型的重排规则会要求Java编译器在生成JVM指令时插入特定的内存屏障指令,通过这些内存屏障指令,volatile实现了Java内存模型中的 可见性和有序性,但volatile无法保证原子性。

2022-12-02 13:57:33 462

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除