- 博客(57)
- 问答 (1)
- 收藏
- 关注
原创 Redis实战-附近的人实现的解决方案
这里指定给GEOSEARCH的参数是,查询key对应的GEOLIST,使用GeoReference.fromCoordinate(x, y)进行指定中心点,直接传入Distance指定范围为圆形,半径为5km,使用RedisCeoCommands.GeoSearchCommandArgs.newGeoSearchArgs().includeCoordinates().limit(end)指定查询的结果包含经纬度数据,并且限制网络IO仅往回返回end个数据(主要是用于分页查询数据)
2025-09-05 17:02:55
985
原创 Redis实战-粉丝关注的解决方案
实现共同关注功能使用Redis的Set集合是比较方便的,在关注的时候将把关注用户的时候的数据推到Set集合重,每个用户都有一个属于自己的Set集合,求共同关注的时候就对两个用户的Set集合求交集,将交集的数据求出来,根据交集中的用户ID数据去数据库中查询用户详情数据。用户去读取收件箱中数据的时候,需要去关注的所有博主的数据中进行拉取,会把关注的所有博主发布的帖子数据拉取下来,如果用户关注的博主较多,博主也比较能发帖子,那这个拉取的过程将会很漫长,比较耗时,给用户的体验也会不好。
2025-08-28 22:53:06
531
原创 Redis实战-点赞的解决方案
使用userService.listByIds(ids):listByIds()接收一个List集合,进行根据里面的数据查询User数据,返回的是List<User>,不能直接进行返回User数据,要进行脱敏处理,所以调用stream().map()进行遍历转换。SQL语句 => 可以发现listByIds进行使用ID集合查询数据的时候,进行使用的是WHERE id IN 用户ID,使用IN进行查询数据,IN进行查询数据的时候,不会按传给IN的顺寻进行排序的,而是按照ID进行升序排序的。
2025-08-28 21:10:00
814
原创 Redis实战-优惠券秒杀解决方案总结大全
解锁时是两个操作redis的步骤的,如果在获取redis中存储的线程标识后,因为各种原因(例如垃圾回收器Stop The World,单机并发太猛导致CPU没有分配时间片,redis连接阻塞)都有可能导致线程阻塞,最终导致进行第二步操作的时候,还以为锁是自己的,就直接给解开了,所以我们需要保证整个解锁的过程都是原子性的,解锁你就直接执行完就可以了,不要分步骤去执行。传入name主要是为了key进行使用的,主要是为了key的设计,这里key设计为lock:业务名称,为什么进行这样的设计呢?
2025-08-27 22:11:44
1144
原创 动态规划4-初级入门破解动态规划的最强奥秘
2.开始进行迭代构建下面行的数据,每次先构建dp[0]的数据,很简单dp[0 = dp[0] + path[i][0],因为当在构建下一行数据的时候,dp[0][0]仍然保持着上一行数据的状态,再循环构建本行的其它数据,其它的数据构建的过程中,dp[j - 1]是左边的数据,这个数据是已经构建好的数据,dp[j]仍然保持着上一行的数据,直接将dp[j]作为上一行的数据即可,所以可以借此逻辑进行构建。
2025-08-27 17:20:55
936
原创 动态规划3-初级入门破解动态规划的最强奥秘
首先在进行动态规划之前,需要先确定动态规划的类型,根据尝试函数的调用方式可以看出来,尝试函数中有两个动态变化的参数,一个是index,另一个是free,index的变化范围是非常好确定的,index的变化范围是0 - drinks.length,free的变化范围最大值是很难去判定的,这里采用的方案是,假设drinks中所有的元素都选择去洗咖啡杯,最终算出来的值,一定是free的最大值,所以free的变化范围也就确定了。至此整个小根堆就帮助就我们完整的走完了,八个人是怎么使用的这四个咖啡机去接咖啡。
2025-08-24 22:15:10
576
原创 Redis实战-缓存的解决方案(一)
逻辑过期,就是定义一个expire过期时间,如果使用逻辑过期的话,就不会出现不是热点key的数据,如果不是热点key的数据根本不会出现在这个缓存中,热点key配合逻辑过期一般是要进行数据预热的,将热点key的数据提前预热到系统中,而不是让整个访问的代码去根据访问数据的不同去重建key,重建的key一定不会是热点key,所以逻辑过期+预加载才是一个真正的热点key模拟出的缓存击穿的场景。若缓存数据不为空,并且通过了第一个if,就代表其中key是对应真实的value数据的,进行返回Shop对象即可。
2025-08-24 13:31:44
871
原创 RabbitMQ基础入门实战
第一个参数是获取消息的唯一标识tag,第二个参数是是否要对当前消息以及之前的都发送ack确认消息,设置true就会对接收到的最后一个消息到之前的消息都进行ack确认,设置false就只会对现在获取到的消息进行ack。第二个参数是是否要对当前消息以及之前的都发送nack确认消息,设置true就会对接收到的最后一个消息到之前的消息都进行nack确认,设置false就只会对现在获取到的消息进行nack。但是,如果消息已经被消费者消费,并且正在处理过程中,即使过期时间到达,消息仍然会被正常处理。
2025-08-23 14:30:00
1134
原创 动态规划2-初级入门破解动态规划的最强奥秘
剪枝优化是这样的,我们要实现一个优化的流程,当进行循环选取卡片去剪裁的时候,我们要重新定义一下什么是有效剪纸,之前我们定义的有效剪纸是,剪纸只要可以将target中的字符消去任意值即可,现在我们重新定义什么是有效剪纸,剪纸可以将target首位的字符消去,就判定这个剪纸是有效字符的,如果不是就判定这个字符不是有效字符。3.j == 0,j!其实就是说,之前我们进行暴力递归的过程,其中是有多余的分支的,多余的分支走起来是没有必要的,可以采用一种优化的方式,巧妙的将没有必要的分支剪裁掉,只去走有必要的分支。
2025-08-22 14:15:00
958
原创 Redis实战-基于Session实现分布式登录
使用redis的时候,一定要使用token吗?token在一定时间后会过期,但是如果在用户持续使用的过程中过期,那真是一个糟糕的事件,所以要采用拦截器刷新token时间的方式,这样就是在用户持续使用的时候,可以帮用户进行刷新token,延期,不会导致用户持续使用的时候过期。拦截器的优先级:可以在registry注册的时候进行指定order,里面的排序数越小的越先执行,如果不进行指定优先级,就按代码的顺序进行注册,越靠上进行注册的拦截器,越先执行。
2025-08-21 19:20:50
981
原创 归并排序的本质
merge其实就是左右部分进行比较,并且在比较的过程将左右有序的数组,整合为一个有序的部分,这就可以理解到这个函数可以解决什么样的问题,在整个过程中只要你需要左边的数据和右边的数据进行比较,且当左部分数据和右部分数据比较的时候,你可以借助右边的数据是有序的,来帮你降低时间复杂度,更快地达到你左边数据比较右边数据的行为。由于我们需要的是找左边的数据比右边大的数据,并根据右边的数据进行计算,所以该题可以在merge的时候,将数组调整为降序的状态即可。2.merge过程编写代码。
2025-08-21 15:45:00
1242
原创 动态规划1-初级入门破解动态规划的最强奥秘
可以看到,在整个dp二维数组构建的过程中,rest的每列都会依赖rest的上一列进行构建,所以我们在循环构建的过程中也需要将数据从rest = 1开始,一列一列的进行构建整个二维dp表。傻缓存方法就是,当发现缓存表中已经构建了数据之后,直接返回即可,如果没有构建数据,就会进行递归操作,并将递归构建出的数据存储到缓存表中,方便下次无需计算,直接使用缓存中存储的数据即可。傻缓存方法就是将之前递归过程中已经计算过的数据进行缓存下来,缓存中如果有数据,就直接返回缓存中的数据,如果没有数据再去进行计算。
2025-08-20 11:30:00
2082
原创 二叉树(Java)
二叉树的递归套路其实就是先从左右树收集信息,然后头节点根据收集上来的数据进行计算信息,继续向上递交信息,直到将所有信息汇聚到根节点为止,最后将计算出的结果返回,其实整体就是完成了一次后序遍历,这其实就是树形DP。判断一棵树是否是完全二叉树,可以使用二叉树的递归套路去做这件事,也可以使用常规的方法,现在我们使用常规方法和递归套路都实现一边,大家可以感受一下不使用二叉树的递归套路和使用二叉树的递归套路的整体流程。
2025-08-19 13:55:22
868
原创 MySQL深度理解-MySQL8新特性
因为MySQL5.7是不支持降序索引的,在上文中我们指出,虽然在语法层面上,我们创建c2字段的索引是降序的,但是实际生成的数据表是升序的,所以当我们使用ORDER BY进行排序的时候,由于索引c1是升序排序,且索引的构建方式也是升序的,所以在根据c1字段进行排序的时候,本身其索引构建就是有序的,所以是可以走索引的,故会有Using Index。死锁检测会耗费数据库性能的。如果查询的行已经加锁,那么NOWAIT会立刻报错返回,而SKIP LOCKED也会立即返回,只是返回的结果中不包含被锁定的行。
2025-08-17 15:41:23
873
原创 MySQL深度理解-MySQL全局优化
redo log的存储策略一般是要设置为1,因为当策略为1的时候,当redo log被记录的时候,将redo log记录到redo log buffer中,然后将数据刷到Page Cache中,最后将数据刷到磁盘上,这种策略可以保障即使服务器宕机后,数据也不会丢失,这种策略是最安全的,一般线上的服务会将innodb_flush_log_at_trx_commit参数设置为1,以此来保证系统的安全。连接的创建和销毁都需要系统资源,比如内存、文件句柄,业务中支持多少并发的概念,指的是每秒请求数,也就是QPS。
2025-08-17 14:59:10
758
原创 MySQL深度理解-Innodb底层原理
我们需要搞清楚的是,数据更改写入ibd文件和redo log日志文件磁盘写入机制的不同,首先磁盘写入ibd文件使用的是随机读写操作,redo log日志写入磁盘使用的是磁盘顺序写,对于机械硬盘来说,磁盘顺序写的性能是远高于磁盘随机写,因为机械硬盘是一种物理的存储结构,读取数据时是在机械圆盘上进行寻道查询物理地址,如果是磁盘顺序写,那寻道速度特别快,但是如果是磁盘随机写,寻道的时候非常费劲,所以对于机械硬盘来说,磁盘随机写的性能是远低于磁盘顺序写的。key时查询的语句,value是查询的结果。
2025-08-16 17:09:57
1111
原创 深入分析MVCC机制
MVCC机制名称是多版本并发机制,主要是为了实现读写操作时的无锁并发的,对于串行化隔离级别来说,为了保证读写数据的操作不冲突,对每行进行操作的时候都需要加锁,比如读数据的时候,会对数据行加读锁,当写数据的时候,会对数据行加写锁,即串行化的隔离效果是使用加锁互斥来实现的,进行任意操作的时候都会对数据行加锁,非常影响性能。在形式上其实就是生成了三个数组,一个以提交事务的数组,一个未提交和已提交事务的数组(未提交的事务可能会随着时间的推移成为已提交的事务),一个未开始的事务的数组。
2025-08-16 13:04:32
990
原创 MySQL深度理解-MySQL锁机制
因为在RR隔离级别下,需要解决不可重复读和幻读的问题,所以在遍历扫描聚集索引记录时,为了防止扫描过的索引被其他事务修改(不可重复读问题)或者间隙被其他事务插入数据(幻读问题),从而导致数据不一致,所以MySQL的解决方案就是把所有扫描过的索引记录和间隙都锁上,这里需要注意的是,并不是直接将整张表加表锁,因为不一定能加上表锁,可能会有其它事务所著了表里的的其它行记录。但是,InnoDB的行级锁同样也有其脆弱的一面,当使用不当的时候,可能会让InnoDB的整体性能表现不仅不能比MyISAM高,甚至可能会更差。
2025-08-03 21:39:17
852
原创 MySQL深度理解-MySQL索引优化
对于in来说,在数据量大的时候,in是会走索引的,在数据量小的时候,是不会走索引的,但是在生产环境下,数据量一般都是比较大的,所以in一般都会走索引的,出于索引设计原因,当性别不进行筛选时,采用这种方案可以使得联合索引可以被完全利用。因此要查询一张大表比较靠后的数据,执行效率是非常低的。age这种数据是经常要进行范围查询的,所以这种数据一般是直接放在最后的,索引也会建立到最后,因为如果将age索引建立到=值前面,在age符合的范围中,后面的=值数据可能不是顺序性的,就无法完全利用建立的联合索引。
2025-07-24 20:41:23
728
原创 MySQL深度理解-详解Explain和索引最佳实践
为什么会出现这种情况呢?用一句话解释什么是索引下推,索引下推就是原本二级联合索引在使用最左字段筛选出二级索引树种的数据之后,直接回表查询数据,然后最终再根据其他字段条件进行筛选,但是经过索引下推优化后,在回表前阶段就进行筛选了,减少了回表操作。即查询的时候走了索引,且索引是唯一的。如果name设置了索引,就不会走filesort,会使用Using index,性能会比较高,因为使用的是索引,索引本身就是一种按顺序组织好顺序的B+Tree结构,所以使用索引树查询的效率非常高。
2025-07-24 12:45:00
1578
原创 MySQL深度理解-深入理解MySQL索引底层数据结构与算法
是树的高度,树越高需要进行的磁盘IO的次数就越多,2000万级别的数据表的索引使用B+Tree进行构建出来的树的高度仅有3,但是如果使用的是B-Tree,由于B-Tree的特性,构建起来整个树的高度绝对是大于3的,而且也不能做内存常驻等优化手段。在MYI索引文件中,存储的其实就是数据表构建的这一棵B+树,叶节点中的data数据是磁盘数据的地址,即当数据表采用的是MyISAM存储引擎的时候,通过索引去查询数据的时候,会根据B+Tree查询到数据的地址,然后再去MYD文件中查询真正的数据。
2025-07-23 23:16:34
1346
2
原创 设计模式-命令模式
但是如果新建一个空命令类,在Invoker进行创建的时候,内置的command集合中的Command都初始化为空命令,并实现Command,提供抽象方法的空实现,这样就无需判空了,如果调用到还没有初始化的Command,就是调用空命令中的空实现方法,不会执行任何逻辑。抽象命令接口实现类进行实现了Command接口,使用构造方法的形式进行聚合具体的执行者Receiver,实现Command接口中定义的抽象方法,调用聚合到命令实现类中的Receiver进行执命令。
2025-07-23 16:33:04
1050
原创 设计模式-代理模式
先创建目标对象,然后调用newProxyInstance()方法,传入目标对象的Class对象,再传入生成的代理对象需要实现的接口(TargetObject定义的类也需要实现相关接口),最终传入一个-InvocationHandler接口实现类,实现invoke方法,invoke方法会传入method参数和args参数(method参数就是劫持的调用方法对象,args参数就是劫持函数对象接收的参数列表),在invoke方法中进行实现代理类的逻辑。
2025-07-23 16:00:21
834
原创 适配者模式
1.Java是单继承机制,所以类适配模式需要继承src类(提供者类),这是一个很大的缺点,一方面要求了抽象适配者必须是一个接口(不能是抽象类之类的),另一方面由于单继承的缘故,适配者的能力调配是依赖于继承获得的,这样就限制了适配者的能力,只能单适配,不能同时做到获取多个能力实现多适配。其别名为包装器(Wrapper)VoltageAdapter适配者,进行实现了适配者接口(对外开放接口能力),继承了提供者(方便调用提供者的能力),在内部进行转化,方便调用者(Phone)进行调用使用。
2025-07-22 22:36:22
835
原创 建造者设计模式
StringBuilder就十分有意思了,它是一个产品,同时也是一个指挥者,进行通过实现AbstractStringBuilder类,调用AbstrtactStringBuilder中的方法(建造者中的方法),进行实现建造对象返回生产对象的功能,生产出的对象就是自己,自己既担任了指挥层,也担任了产品层。其实就是充当一个建造者的上层实现者。2.房子的样式有很多种:如普通防痱子,高楼,别墅,各种房子的建造过程虽然一样,但是要求不一样(也就是建造的大步骤都是一致的,但是建造出来的模样是不同的,即要求都是不同的)
2025-07-22 21:32:58
1018
原创 原型设计模式
深拷贝会为所有引用数据类型的成员变量进行申请存储空间,并进行复制每个引用数据类型成员变 量锁引用的对象,知道该对象可达的所有对象(对于嵌入的对象处理方式是不一样,进行克隆对象中的对象字段的数据的时候,是根据克隆的对象字段的数据进行选择使用深拷贝还是浅拷贝)浅拷贝是纯的变量拷贝,基本数据类型和引用数据类型进行拷贝都是进行值拷贝,也就是说引用数据类型进行拷贝的时候也仅仅是将变量进行拷贝过去而已,拷贝之后两个对象的引用字段进行指向的都是同一个引用变量,这就是最大的问题。但是深拷贝对对象的处理方式是不一样的。
2025-07-21 23:57:41
726
原创 三大工厂设计模式
缺点就是违反了OCP原则(开闭原则),对扩展(提供者)开放,对修改(使用者)关闭,从UML图中就可以进行分析出来,提供者就是Pizza类的派生类,对扩展开放的意思其实就是Pizza的派生类可以无限进行扩展,代码底层可以进行更改(只要外部调用的时候表现出来的特征一样就没问题),对修改关闭的意思就是,当Pizza进行扩展出新的派生类的时候,十一用者可以进行完美的无缝兼容,调用的方法无需进行改变,这就是OCP原则 => 至少要进行保证尽量少的进行修改代码。这样单个工厂类就变为了工厂簇,更利于代码的维护和扩展。
2025-07-21 23:55:28
926
原创 单例设计模式
但是要注意这段代码是线程不安全的设计,如果在单例对象还没有初始化的时候,也就是instance为null的时候,多个线程如果一起调用getInstance这个方法就会出现明显的问题,如果A线程进入if代码块后,还没有执行完new的指令,B线程也进来了,A线程执行完后进行返回出去了A线程new的单例对象,B线程执行完后进行返回出去了B线程new的单例对象,就会导致两个工作线程使用的不是一个单例对象,导致出现相应的问题。这种写法比较简单,就是在类初始化的时候完成实例化,将实例化的单例对象赋值给静态变量。
2025-07-17 23:08:56
688
原创 设计模式是什么呢?
1.设计模式是程序员面对软件工程设计问题时所总结出来的有用的经验,不是代码,是一种思想,一种针对问题的解决方案,设计模式代表了解决这类问题的最佳实践。3.现在常见的23种设计模式是四人组GOF进行提出来的,不能说明设计模式就完全只有这23种,很多设计模式会有很多不同的变种等,但是掌握这23种就足够了。4.设计模式并不会局限于语言,每种语言都会有自己的设计模式,设计模式是思想,并不是某个语言独有的特性或者一种技术。第三层:学习过设计模式,发现自己已经在使用了,并且发现了一些新的设计模式挺好用的。
2025-07-17 22:21:24
214
原创 UML类图怎么画
在这里面进行设计的就是,IDCard对于Person是一个可组装也可以不组装的类,所以相互之间属于一个聚合的关系(Aggregation),但是Head类的对象在Person对象创建的时候,也会进行创建,生死与共,所以Head类与Person类属于是组合的关系(Composition)聚合关系(Aggregation)表示的是整体和部分之间的关系,聚合关系最大的特征就是描述的整体和部分的关系,是可以分开的,并不是锁定强聚合的关系。
2025-07-17 22:20:58
827
原创 设计模式—初识设计模式
1.一个对象应该对其它对象保持最少的了解其实就是设计类的时候,将字段都设置为private私有的,如果想要外部对象进行访问/更改自己内部的状态,使用getter/setter函数即可。2.类与类关系越密切,耦合度越大假设有两个类,类A和类B,如果类A中的字段/方法,依赖于类B中的static字段/实例化对象中的实例字段,就称为类A和类B中有关系,如果这种关系越密切(字段使用越多),则代表类A和类B和耦合度大。3.迪米特法则 => 最少知道原则一个类对依赖自己的类知道的越少越好。
2025-07-16 18:33:28
707
原创 梳理Bean的创建流程
UserServiceProxy代理类会继承UserService类,来保证类型一致性,代理类会有一个字段target,类型就是原始类UserService,而且也会生成和原始类一样的方法,方法中会调用target字段中原始类对象的方法即可。其实是不是的,因为如果是这样的,那为什么在基类方法调用中是有值的,派生类中方法调用时是没有值的呢?生成的代理类继承的原始类中的字段是不会进行赋值的,所以在进行查看代理类中字段的时候,里面原始类拥有的字段是空的,但是在调用原始类的方法时,里面的字段就不是空了。
2025-07-15 23:52:14
1077
原创 一致性Hash算法
假设现在将Hash函数的Hash值定为0-2^64-1,将这个些Hash值收尾相接,想象为一个圆环:Hash函数能输出的所有Hash值都分布在这个圆环上:假设现在根据三台机器的IP,计算出Hash值,分布在圆环上对应的位置上:数据应该存储到哪一台机器上呢?
2024-11-24 19:00:12
1158
1
原创 SpringBoot入门基础-重新相识吧-配置类(一)
在SpringBoot应用中,会默认将application.yml/application.properties加载到Spring上下文环境中,使用@ConfugurationProperties注解去加载已经被Spring加载到上下文中的配置信息(可以使用value/prefix指定属性配置的前缀),该注解可以自动将配置文件中的属性和JavaBean中的字段做映射。1.支持属性名前缀绑定,将属性名前缀相同的属性绑定到JaveBean中。
2024-11-23 16:22:42
1262
原创 史上最全-SpringBoot基础入门-重学SpringBoot吧!!!
当我们使用Maven构建项目的时候,会经历编译,测试,打包的过程,但是Maven传统打包速度太慢了,一个多模块项目打包需要很长很长的时间,所以Maven就开启了一个新的项目:Maven-mvnd项目,这个项目借助的是Gradle和Takari中的技术,以加速Maven的构建速度。maven-mvnd不能独立使用,必须依赖于Maven,可以将maven-mvnd看作是Maven的插件,辅助Maven的构建流程,使得构建流程可以更快更高效。
2024-11-20 15:52:41
1419
原创 AC自动机探究(一)
AC自动机是由字典树发展而来的,是字典树的加强版本,AC自动机就是由字典树发展而来的。字典树是可以使用树的方式,用最少的存储空间和较为低廉的时间成本存储/获取/删除字符串的集合结构。我们总要花点时间去做自己的事情,人生只有一次,勇敢一点,再差又能如何呢?又怎能甘愿措施机会呢?作者没更新完原理篇纯粹是因为,作者陷入了一个需要花费精力解决的事情,作者不要错失,因为作者渴望一个结果。
2024-11-15 19:05:00
1172
原创 Redis大解密之你真的懂String对象吗?
String看起来简单,但实际上有三种编码方式:INT编码:可以用long表示的整数都会使用这个编码,存储整数。EMBSTR:如果字符串小于等于阈值字节大小,就会使用EMBSTR编码。RAW:如果字符串大于阈值字节大小,就会使用RAW编码。EMBSTR和RAW的阈值大小限定和Redis的版本有关系,Redis3.2之前是39个字节,Redis3.2开始是44个字节(在Redis3.2的时候Redis中的字符串结构发生了一些变化)
2024-11-10 14:31:10
1323
原创 1.集合体系补充(1)
ListIterator是更为强大的迭代器,他扩展了Iterator接口,提供了更加强大的功能。ListIterator的定义如下:继承了Iterator并在接口内部定义了一些方法E next();java.util包下的集合体系是不支持多线程操作的,仅仅支持单线程使用,在多线程下没有同步机制,很有可能因为集合体系结构的改变,导致原本应该正常执行的代码在运行中出现异常,Java类库设计者为了避免这种情况的发生,推出了Fail-Fast快速失败机制,尽可能的抛出错误,避免更大的问题出现。
2024-11-09 13:31:13
1013
空空如也
linux系统重装python依赖包出现问题难以解决
2023-08-26
vscode运行go代码时,出现输出乱码
2023-07-12
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅