自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

程序员小航

公众号:『 程序员小航 』

  • 博客(132)
  • 资源 (1)
  • 收藏
  • 关注

原创 MyBatis-Plus 中 Mapper 重载踩坑指南

前言近期在 Mapper 中写了个方法重载,然后死活查不到正确结果,最终灵机一动,想到是不是因为重载,然后我Shift + F6把重载方法名字改了一下!结果,显而易见,重载的那个方法也...

2021-08-22 14:52:10 6636 1

原创 ZooKeeper 分布式锁 Curator 源码 04:分布式信号量和互斥锁

前言分布式信号量,之前在 Redisson 中也介绍过,Redisson 的信号量是将计数维护在 Redis 中的,那现在来看一下 Curator 是如何基于 ZooKeeper 实现信号量的。使用 Demopublic class CuratorDemo { public static void main(String[] args) throws Exception { String connectString = "127.0.0.1:2181,127.0.0.1:2

2021-07-23 10:22:24 240 1

原创 ZooKeeper 分布式锁 Curator 源码 03:可重入锁并发加锁

前言在了解了加锁和锁重入之后,最需要了解的还是在分布式场景下或者多线程并发加锁是如何处理的?并发加锁先来看结果,在多线程对 /locks/lock_01 加锁时,是在后面又创建了新的临时节点。这块在加锁方法 CreateBuilderImpl#pathInForeground 中已经介绍过这里判断 /locks/lock_01 路径已经存在,会直接创建新的临时顺序节点。真正判断锁是否获取成功,其实是在 LockInternals#attemptLock 方法中的 internalLockLo

2021-07-22 20:17:06 161 1

原创 ZooKeeper 分布式锁 Curator 源码 02:可重入锁重复加锁和锁释放

前言加锁逻辑已经介绍完毕,那当一个线程重复加锁是如何处理的呢?锁重入在上一小节中,可以看到加锁的过程,再回头看 internalLock 这个方法。加锁成功之后,将当前线程放到 threadData 中,threadData 是 ConcurrentMap<Thread, LockData> 类型的,不用担心并发问题。假如锁重入了,直接就会在上一部分 lockData != null 被拦下,然后执行 lockData.lockCount.incrementAndGet();。对

2021-07-21 16:11:01 280

原创 ZooKeeper 分布式锁 Curator 源码 01:可重入锁

前言一般工作中常用的分布式锁,就是基于 Redis 和 ZooKeeper,前面已经介绍完了 Redisson 锁相关的源码,下面一起看看基于 ZooKeeper 的锁。也就是 Curator 这个框架。Curator 的锁也分为很多种,本文分析共享可重入锁。考虑到如果文章篇幅较长,不太适合阅读,所以对文章做了适当的拆分。环境配置本机三个节点版本:3.7.0系统:macOS安装方式:brew install zookeeperCurator Maven 依赖版本:5.1.0&lt

2021-07-16 10:19:31 359 2

原创 Redisson 分布式锁源码 11:Semaphore 和 CountDownLatch

前言Redisson 除了提供了分布式锁之外,还额外提供了同步组件,Semaphore 和 CountDownLatch。Semaphore意思就是在分布式场景下,只有 3 个凭证,也就意味着同时只会有三个线程执行业务。设置凭证参数列表:KEYS[1]:指定的 key 这里叫 semaphoreKEYS[2]:redisson_sc:{semaphore}ARGV[1]:凭证数 3这块 lua 脚本相对简单,直接设置一个 key 的 value 为 3。获取凭证参数列表:

2021-07-15 15:04:39 220

原创 Redisson 分布式锁源码 10:读写锁

前言Redisson 还支持可重入读写锁,允许在分布式场景下,同时有多个读锁和一个写锁处于加锁状态。使用读写锁Redisson 读写锁实现了 JUC 下的 ReadWriteLock,使用方式基本相同。源码加锁源码基本和之前的可重入锁加锁无区别,唯一的差异就是在 Lua 脚本这里。所以下面着重分析 Lua 脚本。读锁源码源码地址:org.redisson.RedissonReadLock#tryLockInnerAsync参数列表:KEYS[1]:锁名字 anyRWLockKEYS

2021-07-13 10:08:55 294

原创 Redisson 分布式锁源码 09:RedLock 红锁的故事

前言RedLock 红锁,是分布式锁中必须要了解的一个概念。所以本文会先介绍什么是 RedLock,当大家对 RedLock 有一个基本的了解。然后再看 Redisson 中是如何实现 RedLock 的。在文章开头先说明 Redisson RedLock 建议不要使用!!!在文章开头先说明 Redisson RedLock 建议不要使用!!!在文章开头先说明 Redisson RedLock 建议不要使用!!!重要的事情重复三遍!什么是 RedLock?RedLock,这块可以从网上搜到很

2021-07-12 18:43:42 969

原创 Redisson 分布式锁源码 08:MultiLock 加锁与锁释放

前言基于 Redis 的 Redisson 分布式联锁 RedissonMultiLock 对象可以将多个 RLock 对象关联为一个联锁,每个 RLock 对象实例可以来自于不同的 Redisson 实例。当然,这是官网的介绍,具体是什么?一起看看联锁 MultiLock 使用以及源码吧!MultiLock 使用按照官方文档的说法,这里 Redisson 客户端可以不是同一个。当然,一般工作中也不会说不用一个客户端吧。加锁在阅读 MultiLock 加锁之前,小伙伴应该已经阅读过普通加锁的相

2021-07-10 10:02:28 686 3

原创 Redisson 分布式锁源码 07:公平锁释放

前言看门狗机制是在 RedissonBaseLock#scheduleExpirationRenewal 方法中,这块公平锁和非公平锁并无区别。前文已经了解到,公平锁加锁失败之后,会将当前放到等待队列中,通过 Java 代码中的循环不断尝试获得锁。锁释放主动释放源码:RedissonFairLock#unlockInnerAsyncKEYS[1]:加锁的名字,anyLock;KEYS[2]:加锁等待队列,redisson_lock_queue:{anyLock};KEYS[3]:等待队列中

2021-07-09 10:01:32 214

原创 Redisson 分布式锁源码 06:公平锁排队加锁

前言在上一篇文章中已经分析过公平锁的加锁源码,并得出结论:Redis Hash 数据结构:存放当前锁,Redis Key 就是锁,Hash 的 field 是加锁线程,Hash 的 value 是 重入次数;Redis List 数据结构:充当线程等待队列,新的等待线程会使用 rpush 命令放在队列右边;Redis sorted set 有序集合数据结构:存放等待线程的顺序,分数 score 用来是等待线程的超时时间戳。现在看一下加锁失败被放到等待队列之后,线程是如何处理的?排队等锁源码

2021-07-08 10:02:46 355

原创 Redisson 分布式锁源码 05:公平锁加锁

前言默认的加锁逻辑是非公平的。在加锁失败时,线程会进入 while 循环,一直尝试获得锁,这时候是多线程进行竞争。就是说谁抢到就是谁的。Redisson 提供了 公平锁 机制,使用方式如下:RLock fairLock = redisson.getFairLock("anyLock");// 最常见的使用方法fairLock.lock();下面一起看下公平锁是如何实现的?公平锁相信小伙伴们看过前面的文章,已经轻车熟路了,直接定位到源码方法:RedissonFairLock#tryLock

2021-07-07 08:12:33 728 2

原创 Redisson 分布式锁源码 04:可重入锁释放

前言前面已经了解到了,可重入锁加锁,看门狗以及锁的互斥阻塞。当锁加锁成功之后,锁是如何释放的?主动释放源码入口:RedissonLock#unlock在解锁时会获取当前线程的id。一路往里跟,直接来到 RedissonLock#unlockInnerAsync:分析一下 lua 脚本的内容:如果锁不存在,直接返回 null;如果锁存在,则对锁的重入次数 -1;剩余重入次数大于 0,重新设置过期时间,返回 0;剩余重入次数不大于 0,删除 redis key 并发布消息,返回

2021-07-05 11:06:04 149

原创 Redisson 分布式锁源码 03:可重入锁互斥

前言看过可重入锁的 Lua 脚本,已经可以知道当锁存在时,是会加锁失败的。下面看一下,加锁失败之后是如何处理的呢?加锁 Lua 脚本在 lua 脚本中,前两段 if 分别排除了两种情况:锁不存在;锁存在且是自己线程(可重入);剩下的情况就是锁存在,但是不是自己,也就意味着加锁失败。执行 pttl 命令,返回锁的剩余时间。加锁失败后的处理源码定位:org.redisson.RedissonLock#lock(long, java.util.concurrent.TimeUnit, b

2021-07-05 08:09:57 187

原创 Redisson 分布式锁源码 02:看门狗

前言说起 Redisson,比较耳熟能详的就是这个看门狗(Watchdog)机制。本文就一起看看加锁成功之后的看门狗(Watchdog)是如何实现的?加锁成功在前一篇文章中介绍了可重入锁加锁的逻辑,其中 RedissonLock#tryAcquireAsync 方法是进行异步加锁的逻辑。回顾一下这个方法的入参:waitTime:-1;leaseTime:-1,加锁时未指定锁时间,则为 -1,如果指定,则是指定的时间;unit:null;threadId:当前线程 id。其中的 tr

2021-07-03 16:24:58 600

原创 Redisson 分布式锁源码 01:可重入锁加锁

前言相信小伙伴都是使用分布式服务,那一定绕不开分布式服务中数据并发更新问题!单系统很容易想到 Java 的各种锁,像 synchronize、ReentrantLock 等等等,那分布式系统如何处理?当然是使用分布式锁。如果小伙伴不知道什么是分布式锁,那推荐看看石杉老师的突击课或者在网上搜一搜相关资料。当使用 Redis 作为分布式锁时,当前使用较多的框架就是 Redisson。当然 Redisson 也不仅仅只能当做锁来使用,也有很多其他的功能,小伙伴们可以看一看官方文档,自己多动手实践一下。

2021-07-02 08:24:29 321 2

原创 Spring @Transactional 注解是如何执行事务的?

前言相信小伙伴一定用过 @Transaction 注解,那 @Transaction 背后的秘密又知道多少呢?Spring 是如何开启事务的?又是如何进行提交事务和关闭事务的呢?画图猜测在开始 debug 阅读源码之前,小伙伴们应该已经知道 MySQL 是如何开启事务的。因此可以得出猜测:那下面跟着源码一起读一读,Spring 的 @Transaction 注解是如何执行事务逻辑的?Spring 事务执行流程开启事务这里使用的是 Spring Boot + MySQL + Druid&

2021-06-25 10:43:51 342 1

原创 为了不写接口文档,我肝了个 IDEA 插件!

前言写代码的快乐,在于通过一顿猛如虎的操作,实现了自己设计的逻辑流程。(也可能并不是很快乐!)这时候,你以为就可以关机么?还有接口文档没写呢!哈?开始进入无限 CV 模式,各种请求参数、必填非必填、请求返回示例!几分钟后…… ????????????我要写个 IDEA 插件,以后再也不想手写文档了!下面,来看看我肝出来的插件吧!功能介绍插件名字必须得先介绍,Doc View,有兴趣的小伙伴直接在 IDEA 中搜索插件即可。Controller/Dubbo 接口文档生成支持 Va

2021-06-17 16:15:53 402 2

原创 MySQL next-key lock 加锁范围总结

前言三篇文章分别通过实际操作,介绍了主键、非主键唯一索引、普通索引、普通字段四个方面介绍了加锁的范围。本篇文章再做一个总结。data_locksselect * from performance_schema.data_locks;LOCK_MODELOCK_DATA锁范围X,REC_NOT_GAP1515 那条数据的行锁X,GAP1515 那条数据之前的间隙,不包含 15X1515 那条数据的间隙,包含 15LOCK_MODE = X 是前

2021-06-08 10:38:50 779

原创 MySQL普通索引的加锁

前言前面已经介绍了主键索引的加锁范围和非主键唯一索引的加锁范围。主键索引:加锁时,会先给表添加意向锁,IX 或 IS;加锁是如果是多个范围,是分开加了多个锁,每个范围都有锁;(这个可以实践下 id < 20 的情况)主键等值查询,数据存在时,会对该主键索引的值加行锁 X,REC_NOT_GAP;主键等值查询,数据不存在时,会对查询条件主键值所在的间隙添加间隙锁 X,GAP;主键等值查询,范围查询时情况则比较复杂:8.0.17 版本是前开后闭,而 8.0.18 版本及以后,修改为了前

2021-06-06 11:56:03 1861 1

原创 看来,MySQL next-key lock 的 bug 并没有被修复!

前言在上一篇文章《MySQL next-key lock 加锁范围是什么?》中已经介绍了主键索引的加锁范围,现在来回顾一下:加锁时,会先给表添加意向锁,IX 或 IS;加锁是如果是多个范围,是分开加了多个锁,每个范围都有锁;(这个可以实践下 id < 20 的情况)主键等值查询,数据存在时,会对该主键索引的值加行锁 X,REC_NOT_GAP;主键等值查询,数据不存在时,会对查询条件主键值所在的间隙添加间隙锁 X,GAP;主键等值查询,范围查询时情况则比较复杂:8.0.17 版本是前

2021-06-06 11:55:25 190

原创 MySQL next-key lock 加锁范围是什么?

前言某天,突然被问到 MySQL 的 next-key lock,我瞬间的反应就是:这都是啥啥啥???这一个截图我啥也看不出来呀?仔细一看,好像似曾相识,这不是《MySQL 45 讲》里面的内容么?什么是 next-key lockA next-key lock is a combination of a record lock on the index record and a gap lock on the gap before the index record.官网的解释大概意思

2021-06-06 11:54:22 782

原创 使用 Docker 安装并连接 MySQL

前言作为开发,在本机捣鼓一下 Docker 还是很有必要的,本篇文章介绍如何使用 Docker 安装 MySQL,并在终端(iTerm2)使用命令连接 MySQL。安装 MySQL核心命令如下:# 用 8.0.17 版本举例docker pull mysql:8.0.17# 运行 mysqldocker run -itd --name mysql8.0.17 -p 23306:3306 -e MYSQL_ROOT_PASSWORD=root mysql:8.0.17docker ps

2021-06-06 11:53:10 333 1

原创 Toolkit 大更新:UI 更美观,用起来更方便!

前言前段时间有小伙伴在群里聊天,说到 Toolkit 下载量到 4.9k 了。就突然想起来,很久没有更新这个插件。PS:我是用它申请了 License,一般时候使用 Json 格式化功能。趁着周末,更新了下版本,下面介绍直接介绍更新后的版本。功能介绍UI 界面这次修改最大的就是 UI 界面,基本参考 Doc View 的 UI,全面进行改造,同时对代码也进行的一定程度上的重构。同时增加快捷键 Control + Shift + T 直接唤起操作面板的功能。UI 界面调整,以标签页的形

2021-04-18 15:04:54 218

原创 工作中的设计模式 —— 建造者模式

前言建造者模式是一种创建型设计模式,使你能够分步骤创建复杂对象。该模式允许你使用相同的创建代码生成不同类型和形式的对象。一个 Builder 类会一步一步构造最终对象。这个 Builder 类是独立于其他对象的。使用场景在阅读源码过程中经常看到建造者模式,主要是为了简化复杂对象的创建。具体那些房子啥的举例子就不扯了,以实际工作中的应用为主。@Builder 注解如果小伙伴使用 lombok 这个框架的话,那一定对 @Builder 这个注解不会陌生。@Data@Builderpubl

2021-04-18 15:03:59 110

原创 工作中的设计模式 —— 原型模式

前言原型模式是一种创建型设计模式, 使你能够复制已有对象, 而又无需使代码依赖它们所属的类。通俗说法,就是将一个类作为原型,然后复制出来另一个类。使用场景这么一说,是不是发现我们经常使用?比如咱们项目中有 BO、DTO、VO,但是在开发过程中,需要各种转换,get/set,一般情况下大家都会使用 BeanUtils,将一个类的属性值 set 到另一个类的属性值中,然后返回。当然,也有一个实体直接从头捅到尾的。关于 BeanUtils 的 copy 方法,各个框架都提供了相关工具,不过 Ja

2021-04-06 15:27:14 105

原创 IDEA 文档插件 DocView 版本更新:支持编辑文档注释

前言老大:我想请个假。。。请反转一下链表1反转单链表解题思路使用两个临时变量,分别标记反转过程中的两个链表的头。class Solution { public ListNode reverseList(ListNode head) { if (head == null || head.next == null) { return head; } ListNode temp;

2021-04-06 15:26:19 706

原创 IDEA 敏捷开发技巧——实时模版

前言本文通过自定义模版,在 IDEA 中,通过简单的几个字符,快捷生成既定的代码。示例自定义模版如何自定义模版Windows and LinuxFile -> Settings -> Editor -> Live TemplatesmacOSIntelliJ IDEA -> Preferences -> Editor -> Live Templates先添加一个 group,表示这里都是自己自定义的。这个名字就自己随便取了,只要

2021-03-07 13:19:16 865

原创 IDEA 敏捷开发技巧——后缀完成

前言“工欲善其事,必先利其器。”所以说今天来看一看如何压榨 IDEA ,让你的 IDEA 使用的更顺手!今日技巧:后缀完成自定义后缀完成模版示例上面动图使用了 .sout .if 来举例,相信有些小伙伴在工作中经常使用。如果没有使用过,也可以????尝试一下。自定义后缀模版因为打印日志的时候,为了方便日志的查看,一般会将实体打印成 Json (性能问题先忽略)。然后就可以使用这个方式来自定义后缀完成的模版。是不是瞬间感觉方便很多了。如何自定义后缀模版Windows an

2021-02-20 11:17:28 267

原创 Spring 事务、异步和循环依赖有什么关系?

前言在循环依赖中有一种循环依赖,就是自注入:自己依赖自己。事务的自注入在 Spring 自调用事务失效,你是怎么解决的? 有小伙伴提出可以自己注入自己来解决事务失效。具体使用方式如下:@Slf4j@Servicepublic class OrderBizServiceImpl implements OrderBizService { // 注入自己 @Autowired private OrderBizService orderBizService; @O

2021-02-02 17:25:56 286

原创 Spring 动态代理时是如何解决循环依赖的?为什么要使用三级缓存?

前言在研究 『 Spring 是如何解决循环依赖的 』 的时候,了解到 Spring 是借助三级缓存来解决循环依赖的。同样在上一节留下了疑问:循环依赖为什么要使用三级缓存?而不是使用二级缓存?AOP 动态代理对循环依赖的有没有什么影响?本篇文章也是围绕上面的内容进行展开。笔记也在不断整理,之前可能会有点杂乱。循序渐进,看一看什么是循环依赖?开始先简单回顾一下 Bean 的创建过程,当然小伙伴也可以直接阅读『 单例 Bean 的创建 』这篇文章。不过考虑到阅读本文前再阅读上一篇文章、

2021-01-31 12:39:29 1083 7

原创 Spring 是如何解决循环依赖的?

前言相信很多小伙伴在工作中都会遇到循环依赖,不过大多数它是这样显示的:还会提示这么一句:Requested bean is currently in creation: Is there an unresolvable circular reference?老铁!这就是发生循环依赖了!当然这里是一个异常情况。在我的一篇文章中介绍如何避免 Spring 自调用事务失效,其中网友给建议,说可以在类中注入自身,然后调用,而注入自身的过程也是循环依赖的处理过程。下面就一起看一看,什么是循环依赖,以及

2021-01-26 12:11:18 304

原创 Spring 源码学习 16:单例 Bean 创建

前言在 finishBeanFactoryInitialization 中介绍了创建 Bean 的流程大概流程,这里进入单例 Bean 的创建过程。这里主要分为三个部分创建单例 BeangetSingletoncreateBeangetObjectForBeanInstance下面进入源码:getSingletonpublic Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {

2021-01-21 14:40:50 354

原创 Spring 源码学习 15:finishBeanFactoryInitialization(重点)

前言可以说前面的都是准备工作,而接下来开始的才是重点,在这一步会完成 BeanFactory 的初始化,同时实例化单例 Bean。具体怎么操作的,那就一起阅读源码吧!不过在阅读源码之前,还是需要了解一些知识的。什么是 FactoryBean ?FactoryBean 是如何使用的 ?Bean 是如何初始化的?常说的循环依赖是怎么解决的?什么是 FactoryBean ?在官网的这篇文章《What’s a FactoryBean?》中有相关解答,有兴趣的小伙伴可以看一下。由内部使用的对

2021-01-19 10:57:34 195

原创 Spring 源码学习 14:initApplicationEventMulticaster、onRefresh 和 registerListeners

前言上一篇介绍了国际化的使用以及初始化消息源的源码,接下来接着往下阅读,将进入 initApplicationEventMulticaster 、onRefresh 和 registerListeners 的相关操作逻辑。这一部分主要是初始化事件广播器以及注册监听器。而 onRefresh 部分则需要子类去实现。 所以本文主要介绍以下几个部分:什么是 Spring 事件?监听器是如何使用的?什么是 Spring 事件?这块的介绍在官网 1.15.2. Standard and Custom

2021-01-13 22:56:43 237

原创 Spring 源码学习 13:initMessageSource

前言在阅读完 registerBeanPostProcessors 源码之后, 下一步就进入到 initMessageSource,这一步主要作用是初始化国际化文件。依然如之前所示,先通过官网了解到国际化的用法,然后再对源码进行研究。MessageSource 国际化如官网1.15.1. Internationalization using MessageSource所示,主要作用就是使用国际化,定制不同的消息。需要注意的是 MessageSource 定义的 Bean 名字必须为 messag

2021-01-04 22:16:20 331

原创 Spring 源码学习 12:registerBeanPostProcessors

前言前面通过 invokeBeanFactoryPostProcessors 这一步了解到了什么是 BeanFactoryPostProcessor ,以及 BeanFactoryPostProcessor 的使用及作用,并通过 invokeBeanFactoryPostProcessors 这一步源码,对 BeanFactoryPostProcessor 的加载流程有了进一步了解。现在就一起进入下一个环节:registerBeanPostProcessors(beanFactory);这一步主要的

2021-01-02 17:38:20 367

原创 Spring 源码学习 11:invokeBeanFactoryPostProcessors

前言invokeBeanFactoryPostProcessors 会执行 BeanFactory 的后置处理器。看到这里会有疑问:什么是 BeanFactoryPostProcessor ?BeanfactoryPostProcessor 该如何使用?知道了上面两个问题的答案,对 BeanFactoryPostProcessor 有了了解之后,然后再深入源码,继续阅读 invokeBeanFactoryPostProcessors 这个方法。作用资料还是在官网可以找到答案:阅读了一下,

2020-12-28 23:18:53 403

原创 Spring 源码学习 10:prepareBeanFactory 和 postProcessBeanFactory

前言根据 refresh 流程,当 obtainFreshBeanFactory 执行结束后,下一步会执行 prepareBeanFactory ,顾名思义,这个方法主要是准备 BeanFactory,下面一起看一看这部分逻辑。prepareBeanFactoryprotected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to

2020-12-27 19:01:56 201

原创 Spring 源码学习 09:refresh 大概流程

前言前面的准备工作结束之后,就是进入核心代码 refresh。源码public void refresh() throws BeansException, IllegalStateException { // 加锁 synchronized (this.startupShutdownMonitor) { StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh")

2020-12-23 12:06:42 173

IDEA输入法不跟随

搜狗输入法, IDEA, 输入框不跟随, 将文件下载, 解压, 并替换IDEA安装目录的 jre64即可. 替换前请注意备份原jre64.

2018-05-22

空空如也

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

TA关注的人

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