自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(352)
  • 收藏
  • 关注

原创 分布式事务框架 Seata 入门案例

细心的同学会发现,微服务架构中有配置中心和注册中心,Dubbo中也有配置中心和注册中心,而本文讲的Seata也有配置中心和注册中心。其实,并没有区别,各是各的。微服务的配置中心和注册中心你要配置,Dubbo的你也要配置,Seata的配置中心和注册中心你还要配置,尽管它们可能是同一个实例,但那也得各配各的。由于这里导入配置的时候没有-t指定命名空间,即导入到默认命名空间,所以配置里面namespace为空,如果-t指定了特定的命名空间,则server和client端的namespace也要与之对应。

2025-07-24 21:57:52 1004

原创 Spring Boot 多数据源配置

这样写看起来确实有些麻烦,通常可能不会像这样在一个方法里操作多个数据库,就比如说假设这是一个管理后台,为了图省事把所有业务都写在这一个项目里,这个时候就需要配置多个数据源,各个数据库的业务互相没有关联,只是写在同一个项目中而已,这样的话如果每次都手动设置数据源太麻烦,可以定义一个AOP切面来自动切换数据源。由于是MyBatsi-Plus,所以配的是MybatisSqlSessionFactoryBean,如果是MyBatis,则应该是SqlSessionFactoryBean。2、定义切面、切点、通知。

2025-07-24 21:56:24 425

原创 MQ收到无序的消息时如何进行业务处理?

发送消息的时候可以将消息的创建时间写进消息体中,这样消费者收到消息后可以根据创建时间来排序,至少同一种业务下的消息的顺序是可以保证的,事实上通常我们也只关心某个业务下的消息的顺序。收到“消息3”时,根据原先消息ID,先找消息2,如果消息2已被处理,则直接处理消息3,如果消息2没被处理,则找消息1,消息1处理完后,再处理消息2,最后处理消息3。收到“消息2”时,根据原始消息ID找到上一条消息(假设是“消息1”),则首先判断消息1是否已被处理,如有没有被处理,则先处理消息1,再处理消息2。

2025-07-24 21:55:31 769

原创 Spring事务使用注意事项

Spring提供的事务使用起来很方便,一个@Transactional注解就搞定全部,但是如果不注意,也会踩坑。

2025-07-24 21:54:52 180

原创 Seata 全局锁等待超时 问题排查

但这个疑虑很快被打消了,因为这是必现的一个问题,每次执行到这个方法都报错,甚至在下班后系统没有人使用的情况下,我一点,还是报这个错,这个时候可以确定就我一个人在用,而且查了数据库没有被锁定的数据和事务,所以应该不是资源竞争导致的获取锁等待超时。2、所有的RM在执行本地操作的时候都是一样的流程,因为数据源被Seata代理,所以在执行各自本地的逻辑时,设计到数据库操作的,都是首先更改连接为非自动提交,然后进行分支注册,注册成功后连接可以提交了,最后报告分支状态。而注册就是要获取全局锁。

2025-07-24 21:54:10 988

原创 MyBatis-Plus批量插入方法saveBatch

当我们使用insert批量插入的时候,如果中间有一条或多条数据插入失败了,此时这一批次的所有数据都不会插入成功。因为这是一条insert语句,它是一个原子操作,要么所有的都插入成功,要么都失败。先说结论,saveBatch()方法也是一条一条的插入,也就是说它会产生多条insert语句,而不是一条insert语句,所以它不是真正的批量插入,更不能提高插入效率。因此,saveBatch()并不能提高插入的效率。插入数据的时候,经常会遇到非空校验、唯一约束等等,如果不满足的话就插入失败了。

2025-07-24 21:53:16 301

原创 Spring Retry

为此,Spring Retry提供了一个名为RetryContextCache的存储策略,您可以将其注入到RetryTemplate中。回调失败后,RetryTemplate必须调用RetryPolicy,要求它更新自己的状态(存储在RetryContext中)。然而,这个状态是在堆栈上的,不需要在全局的任何地方存储它。可以将@EnableRetry注释添加到@Configuration类上,并在想要重试的方法上(或在所有方法的类型级别上)使用@Retryable,还可以指定任意数量的重试监听器。

2025-07-24 21:52:39 959

原创 SpringBoot Seata 死锁问题排查

现在,回到项目中来,由于我们的项目中有一个比较耗时的操作,超时时间固定是60秒,这个方法本来应该在Seata代理数据源之后做,不知道为什么服务器上先执行了,导致main线程等待了60秒,之后才执行SeataDataSourceBeanPostProcessor#postProcessAfterInitialization()因此,main线程很有可能会先持有该锁,当初始化到Seata的时候,又要获取该锁,于是出现了锁争用。(PS:我猜测可能是环境不同造成的,包括操作系统不同和JDK版本不同)

2025-07-24 21:51:45 362

原创 MySQL InnoDB加锁规则分析

1. 基础知识回顾1、索引的有序性,索引本身就是有序的2、InnoDB中间隙锁的唯一目的是防止其他事务插入间隙。间隙锁可以共存。一个事务取得的间隙锁并不会阻止另一个事务取得同一间隙上的间隙锁。共享和独占间隔锁之间没有区别。它们彼此之间不冲突,并且执行相同的功能。3、MySQL默认隔离级别是 REPEATABLE-READ4、加锁的对象是索引,加锁的基本单位是next-key锁,而行锁和间隙锁,是由next-key锁退化而来的5、记录锁,锁的是索引,而非数据本身。

2025-07-24 21:50:51 836

原创 JSON字符串反序列化 动态泛型

需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成JSON字符串,然后JSON反序列化成对象,然后反射调用方式一:FastJson方式二:Jackson实践中发现,这两种方式容易导致OOM方案二:直接将参数对象存到数据库中数据库对应字段设置BLOB类型(这里设置的是MEDIUMBLOB) ,对应的java字段类型是byte[]直接将Java对象序列化为二进制数据,这种方式的存储和读取速度非常快,因为序列化和反序列化过程不需要转换格式。

2025-07-24 21:49:59 407

原创 基于Redis有序集合实现滑动窗口限流

Redis有序集合每个value有一个score(分数),基于score我们可以定义一个时间窗口,然后每次一个请求进来就设置一个value,这样就可以统计窗口内的请求数量。value在这里不那么重要,因为我们只需要统计数量,因此value可以就设置成时间戳,但是如果value相同的话就会被覆盖,所以我们可以把请求的数据做一个hash,将这个hash值当value,或者如果每个请求有流水号的话,可以用请求流水号当value,总之就是要能唯一标识一次请求的。那么,问题来了,如果获取注解参数呢?

2025-07-24 21:48:59 382

原创 深入理解 Spring: Spring finishBeanFactoryInitialization

两件大事!!!在实例化Bean前,第一次调用后置处理器, 这件大事绝对是有历史意义的!!!为啥呢?大家想想,bean还没有创建呢!就已经可以插手bean的创建过程了,不是很刺激吗?接着看回调了什么后置处理器呢?Spring会循环所有的处理器检查当前被遍历的处理器是否是类型的,如果是的话呢,就执行这个后置处理器的方法这个是允许有返回值的,大家可以想想,这一点是不是有点可怕?

2025-07-12 22:09:18 663

原创 深入理解 Mybatis - Executor

本文探究MyBatis中的Executor,​。

2025-07-12 22:09:03 1006

原创 深入理解 MyBatis:MyBatis 启动流程!

记录一下尝试阅读Mybatis源码的过程,这篇笔记是我一边读,一遍记录下来的,虽然内容也不多,对Mybatis整体的架构体系也没有摸的很清楚,起码也能把这个过程整理下来,这也是我比较喜欢的一种学习方式吧单独Mybatis框架搭建的环境,没有和其他框架整合@Testtry {// 2. 创建SqlSessionFactory工厂// 3. 创建sqlSession// todo 怎么理解这个sqlSession?首先它是线程级别的,线程不安全, 其次它里面封装了大量的CRUD的方法。

2025-07-12 22:08:48 806

原创 深入理解Spring MVC:SpringMvc 启动流程

的处理我们获取出来了一个 HandlerExecutionChain ,并且我们百分百确定这个 HandlerExecutionChain 就是用来处理当前的请求的,但是!我们文件贴在下面,可以看到存放的是一些全类名,这些是DiapacherServlet针对不同策略接口提供的八个默认的实现,当在上下文中没有匹配到程序员添加的这些实现时,就会使用这些默认的实现。但是后来我们都直接实现。我们追踪一下他的生命周期创建过程, 首先是说Servlet的创建时机,其实是存在两种情况的, 这取决于。

2025-07-12 22:08:34 644

原创 深入理解Spring MVC:Spring MVC开发手册

第一步: 实现View接口/*** 返回内容类型* @return*/@Override/*** 渲染视图*/@Override第二步: 配置视图解析器-- 配置视图解析器 BeanNameViewResolver 解析器: 使用视图的名字解析视图 (所以我们需要把我们的视图添加进IOC)-->-- 到现在为止,我们就有了两个视图解析器,需要指定优先顺序-->-- 常用的放在后边,我们的放前边 order越小,优先级越高--></bean>测试// 自定义的视图类名小写。

2025-07-12 22:08:21 1005

原创 深入理解Spring MVC:Spring MVC环境搭建

IDEA搭建SpringMvc开发环境。

2025-07-11 21:39:13 234

原创 深入理解 Spring:Spring BeanPostProcessor

Bean的后置处理器,首先来说,他是Spring中抽象出来的一个顶级的接口, 他里面有如下有如下两个方法, 这两个方法的执行时机通过方法的名字也能猜的出, 一个是在构造方法之后,init()方法之前,第二个是在init()方法之后执行@Nullable@Nullable大家说它是Spring对外提供的拓展点,也许是因为,通过实现这个接口,程序员可以被Spring管理的bean的生命周期进行插手这也体现了AOP的设计思想,就比如在init()方法执行前后做出不同的动作,其实就是对bean的一种增强。

2025-07-11 21:38:53 555

原创 深入理解 Spring:Spring BeanFactoryPostProcessor的回调

方法,就返回了程序员指定的想批量导入DaoIOC中的对象的全类名, 下一步就是将这些类注入到IOC中,Spring的做法是递归调用, 因为上面说了,当前方法可以实现的三种Bean的注入,一般来说,通过。此外,添加了忽略注入的对象,当程序员向注入Spring启动时,依赖的原生对象时,会被忽略注入,企图注入BeanFactory,资源解析器,事件发布器,应用上下文时,被Spring使用原生的对象替换掉。类型的导入方式之后,我们继续往下看,三种方式都是忙着把读取读来的信息往map中放,那么在哪里进行处理的呢?

2025-07-11 21:34:28 529

原创 深入理解 Spring :Spring 环境初始化!

其实是有两种,第一种就是让Spring通过Scanner去扫描包解析程序员提供的添加了注解的类,这是个自动完成的过程,第二种就是。但是,大家可以发现,它的调用时机都是在构造方法执行之后进行拦截,这时候。方法,然后一路往下跟,会经过几个没有什么重要逻辑的方法, 然后来到这里。的抽象方法,我们要找的是它的实现类,那问题来了, 是谁实现他呢?程序的启动入口, 注解配置的应用上下文.主要做了下面的三件事。扫描器的创建过程,经过几个没有重要逻辑的方法,我们会进入。接着看代码,回到上面的代码,我们看如何将。

2025-07-11 21:34:05 841

原创 Spring Boot 如何整合 Mybatis?

一般我们的都是单独创建一个mapper的packet, 闲麻烦可以选择使用。方法的名字见名知意就行,但是方法的返回值得是注解上sql对应的返回值。如下图所示,在Resources目录下面创建指定的配置文件。中添加配置告诉SpringBoot去哪里读取配置文件。配置文件的内容在上面的官网上可以找到,我的如下。注解标记在单个mapper接口上,或者使用。完成mapper的批量扫描。

2025-07-11 21:33:42 203

原创 mybatis - 通用mapper

Mybatis只能针对单表为我们生成sql,如果我们的需求是跨表操作,比如说涉及到两张表,我们就得去mapper里面自己写sql原生sqlinner join tb_category_brand cb on b.id=cb.brand_id -- 去笛卡尔积;mapper?用#{id} 取代。

2025-07-11 21:33:28 725

原创 深入理解分布式锁

一句话,分布式锁是实现有序调度不同的进程,解决不同进程之间相互干扰的问题的技术手段。

2025-07-05 11:00:00 690

原创 深入理解 ZooKeeper:ZooKeeper集群的Leader选举?

ZooKeeper对Zab协议的实现有自己的主备模型,即Leader和learner(Observer + Follower),有如下几种情况需要进行领导者的选举工作情形1: 集群在启动的过程中,需要选举Leader情形2: 集群正常启动后,leader因故障挂掉了,需要选举Leader情形3: 集群中的Follower数量不足以通过半数检验,Leader会挂掉自己,选举新leader情景4: 集群正常运行,新增加1个Follower本篇博文,从这四个方面进行源码的追踪阅读。

2025-07-05 10:45:00 584

原创 深入理解 ZooKeeper:ZooKeeper集群中通过Processor保证数据一致性?

ZK集群启动后完成数据的统一性恢复后,如上图查看的继承图,三种不同的角色有不同的的实现逻辑类三者启动时,都将会来到中的startUp()方法中,源码如下,

2025-07-05 10:30:00 988

原创 深入理解 ZooKeeper:ZooKeeper集群如何保证数据一致性?

只有当服务端的ZK存在多台时,才会出现数据一致性的问题, 服务端存在多台服务器,他们被划分成了不同的角色,只有一台Leader,多台Follower和多台Observer, 他们中的任意一台都能响应客户端的读请求,任意一台也都能接收写请求,不同的是,Follower和Observer接收到客户端的写请求后不能直接处理这个请求而是将这个请求转发给Leader,由Leader发起原子广播完成数据一致性理论上ZK集群中的每一个节点的作用都是相同的,他们应该和单机时一样,各个节点存放的数据保持一致才行。

2025-07-05 10:15:00 588

原创 深入理解 ZooKeeper:ZooKeeper单机服务端的启动

的继承图,不同的上下文工厂的实现可以创建出不同的上下文,通过这个图可以看到,不仅支持传统的NIO,还有一套Netty的实现,,下面是它的源码,通过switch分支针对不同类型的请求做出不同的处理,下面用create类型的请求举例。依然是用create类型距离, 它在下面的方法中做了如下几件事。方法中,存在如下的逻辑,判断是单机版本启动还是集群的启动。,这个对象就是存在于内存中的对象,对磁盘中数据可视化描述。看一看,他是如何处理已经被加载到内存的配置文件的,,他的主要逻辑都在下面的Run方法中。

2025-07-05 10:00:00 754

原创 深入理解 ZooKeeper:ZooKeeper的ACL实现

zookeeper在分布式系统中承担中间件的作用,它管理的每一个节点上可能都存储这重要的信息,因为应用可以读取到任意节点,这就可能造成安全问题,ACL的作用就是帮助zookeeper实现权限控制, 比如对节点的增删改查通过跟踪上面的源码,我们知道了zookeeper的权限acl是如何实现的,以及客户端和服务端之间是如何相互配合的客户端同样是经过主线程跟进不同的命令类型,将请求打包packet发送到服务端服务端将addauth添加认证信息保存在内存中node会被持久化,因为它需要的认证同样被持久化。

2025-07-04 16:26:43 709

原创 深入理解ZooKeeper:ZooKeeper客户端与服务端的watcher回调

当客户端启动时添加watcher对某一个特定path上的node进行监听时 , 客户端的watcher被封装进WatcherRegistion中再进一步发送的服务端watcher不为空的packet达到服务端后会被巧妙的处理,将ServerCnxn当成watcher注册添加到服务端维护的那份watcher map table中。

2025-07-04 16:23:23 788

原创 深入理解ZooKeeper:ZooKeeper单机客户端的启动流程

这是他的构造方法,可以看到它还是一个守护线程,并拥有客户端socket的引用,有了NIO Socket相关技能。针对下标运行,对数组的size取模, 再赋值给自己,所以就实现了从0 - array.size()的循环。能往下追很长的代码,提前说main.run()的作用,就是对用户输入的命令进行下一步处理。它的Run方法, 真的是好长啊, 比我上面写的部分内容还长(大概两百行了),看上面的客户端启动的脚本图,可以看到,zookeeper客户端脚本运行的入口。他是本类的抽象方法,具体的实现类是。

2025-07-04 16:16:47 1024

原创 深入理解ZooKeeper:ZooKeeper单机-集群环境搭建

zookeeper分布式系统中面临的很多问题, 如分布式锁,统一的命名服务,配置中心,集群的管理Leader的选举等。

2025-07-04 16:05:12 952

原创 深入理解 Netty-探究netty的观察者设计模式

任何方法的回调都是提前设计好了的,就像pipeline中的handler中的方法的回调,就是通过遍历pipeline内部的链表实现的,这里的通知观察者,其实也是调用观察者的方法,而且他使用的一定是观察的父类及以上的引用实现的方法回调。,这是不被允许的,因为在netty中,一条channel可能关系着上千的客户端的链接,其中一个客户端的阻塞导致几千的客户端不可用是不被允许的,的操作, 所以按理说,我们添加是listenner的回调就是在header的unsafe中完成的,这是我们的目标地。

2025-07-04 15:51:39 594

原创 深入理解 Netty-Netty中的装饰者模式

如果选择继承的话,现有的四个类全部多出两个子类,让子类添加上特定的功能, 虽然解决了问题,但是类的数量出现了爆炸式的增长 从原来的4长到了 4+4*2。看上面的图,其实netty的设计者选择的处理模式是装饰者模式,只添加了三个类,就达到了同样的效果。的继承体系时,发现上图中的四个直接实现类可能都需要添加新的功能,这俩功能是。是netty中重要的数据容器类,我们看它是如何设计的,如下图。所谓装饰者,说白了,目的就是对现有的对象进行增强,这个类,其实直接实现类有四个,为什么要忽略掉。的直接实现类有五个,忽略。

2025-07-04 15:48:11 307

原创 深入理解 Netty-Netty中的责任链模式

在java中不再存在指针了,如果我们想创建一个链表,只能是在本类中添加本类属性, 因为我们想创建一个链表,所以这是必须的工作需要提供set方法,让当前的节点可以设置自己的下一个节点处理请求的逻辑,设计成抽象方法,让不同的节点根据自己的需求去实现// todo 抽象父类中可以存在构造函数,但是当我们创建子类时,必须要有一个参数的构造函数,// todo 让子类一个参数的构造函数,来给这个函数初始化// 如果当前的处理器处理不了,就会往下传播。

2025-07-04 15:46:01 877

原创 深入理解 Netty-Netty中的策略者模式

策略者模式,就解决了这个问题, 它把行为抽象成了接口,以接口+实现的方式,解决上面的问题, 就上面的例子来说,可以把教学设计成接口,任何类,只要实现了这个接口,就可以教学,而不一定强制要求只有老师才可以实现它。比如先设计Person类,把人类都具有的行为放到这个Person,特有的行为设计成抽象方法,让子类具体去实现, 这样后续无论我们再去构造学生,还是构造老师,大家都继承Person,就达到了代码复用的目的。总的来说,策略模式,就是将行为抽象成接口+实现的模式。, 然后把这个连接注册进选出的。

2025-07-04 15:43:37 225

原创 深入理解Netty-编码流程及WriteAndFlush()的实现

***/// todo write动作会传播到 MyPersonEncoder的write方法, 但是我们没有重写, 于是就执行 父类 MessageToByteEncoder的write, 我们进去看@Override// 消息头 长度// 消息体选择继承从消息到字节的编码器它其实就是一个netty自定义的容器,使用的单向链表的结构,为什么要有这个容器呢?回想一下,服务端需要向客户端发送消息,消息进而被封装进ByteBuf,但是呢, 往客户端写的方法有两个write()

2025-07-04 15:41:52 653

原创 深入理解 Netty-解码器架构与常用解码器

本身是一个抽象类,但是它只有一个抽象方法decode()累加字节流调用子类的decode()方法进行解码将解析完成的ByteBuf往后传递既然是入栈处理器,有了新的数据,channelRead()就会被回调,我们去看一下它的下面是它的源码,@Overrideif (msg instanceof ByteBuf) { // todo 在这里判断, 是否是 ByteBuf类型的,如果是,进行解码,不是的话,简单的往下传播下去try {

2025-07-04 15:39:59 882

原创 深入理解 Netty-Pipeline组件

inbound事件其实就是客户端主动发起事件,比如说客户端请求连接,连接后客户端有主动的给服务端发送需要处理的有效数据等,只要是客户端主动发起的事件,都算是Inbound事件,特征就是事件触发类型,当channel处于某个节点,触发服务端传播哪些动作。

2025-06-30 21:41:37 679

原创 深入理解 Netty-新连接接入

netty的服务端初始化,注册在BossGroup中的一条中,并且给中维护的jdk原生的绑定好了端口后, EventLoop启动,开始轮询工作...这时候 EventLoop 它在轮询什么?其实它在轮询监听当初NioServerSocketChannel经过二次注册感兴趣的事件时, 告诉 Selector,让Selector关注自己身上可能会出现OP_ACCEPT事件, 这合情合理,因为对于Netty的主从Reactor线程模型中, BossGroup中的channel只关心OP_ACCEPT。

2025-06-30 21:39:41 527

原创 深入理解 Netty-Channel架构体系

channel是一个管道,用于连接字节缓冲区Buf和另一端的实体,这个实例可以是Socket,也可以是File, 在Nio网络编程模型中, 服务端和客户端进行IO数据交互(得到彼此推送的信息)的媒介就是ChannelNetty对Jdk原生的进行了封装和增强封装成了, 相对于原生的JdkChannel, Netty的Channel增加了如下的组件id 标识唯一身份信息可能存在的parent Channel管道 pepiline用于数据读写的unsafe内部类。

2025-06-30 21:32:57 603

空空如也

空空如也

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

TA关注的人

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