- 博客(99)
- 收藏
- 关注
原创 MySQL如何解决事务并发的幻读问题
本文探讨了MySQL如何解决事务并发中的幻读问题。在InnoDB引擎的可重复读隔离级别下,主要通过MVCC机制和临键锁两种方式应对幻读:快照读通过Read View读取历史版本数据避免幻读;当前读则通过临键锁锁定查询范围防止其他事务插入数据。然而,幻读并未被完全解决,当快照读后执行更新操作或混合使用快照读和当前读时仍可能出现幻读。要完全避免幻读,需在首次查询时就使用当前读并加临键锁。
2025-07-17 16:52:31
736
原创 事务隔离:从锁实现到MVCC实现
本文探讨了数据库事务隔离的实现机制,从锁实现到MVCC的实现方式。首先介绍了事务的基本概念和四大特性(ACID),然后分析了通过锁机制实现不同事务隔离级别的原理,包括一级、二级、三级封锁协议。接着重点讲解了MVCC(多版本并发控制)机制,包括当前读与快照读的区别,以及如何通过Read View实现读已提交和可重复读隔离级别。文章指出MVCC通过维护多版本快照链和无锁读取的方式,显著提高了并发事务的性能,相比纯锁机制更为高效。最后总结了两者的适用场景和技术特点。
2025-07-17 00:39:46
559
原创 Java Integer包装类缓存机制详解
Java Integer包装类缓存机制会导致数值比较出现意外结果。其缓存范围为-128到127,在此范围内的整数自动装箱后会复用缓存对象,使用"=="比较会返回true;但超出此范围则会创建新对象,"=="比较会返回false。因此,比较包装类对象值时,必须使用equals()方法而非"=="。其他包装类如Byte、Short、Long、Character和Boolean也有类似缓存机制,而Float和Double则没有。最佳实践是始终使用equa
2025-07-14 20:08:38
259
原创 快速失败(fail-fast)和安全失败(fail-safe)
Java集合框架中的快速失败(fail-fast)与安全失败(fail-safe)机制对比:fail-fast通过modCount检查在遍历时检测容器修改,立即抛出ConcurrentModificationException,强调数据一致性;fail-safe采用读写分离(如CopyOnWriteArrayList)或弱一致性策略,允许遍历期间修改容器但可能读取旧数据,侧重线程安全与容错性。前者适用于单线程环境,后者更适合高并发场景。这两种机制分别体现了Java对集合并发访问的不同处理策略。
2025-07-10 01:06:34
343
原创 消息队列避免重复消费(幂等性处理)
摘要:消息队列中重复消费问题可能由生产者、MQ或消费者原因导致。解决方案主要围绕幂等性处理:1)业务层面插入记录,通过数据库唯一索引或分布式锁(Redis setnx+MySQL持久化)来确保消息唯一性;2)分布式锁方案性能更优,避免了大量数据库访问。核心思想是无论消息被消费几次,处理逻辑都能保证无副作用。
2025-07-09 14:14:29
298
原创 RabbitMQ的消息可靠传输
RabbitMQ消息可靠传输机制解析 RabbitMQ通过AMQP协议实现消息传输,架构包含生产者、交换机、队列和消费者四个核心组件。为确保消息可靠性,RabbitMQ提供了三重保障机制:1)生产者端的confirm确认机制,通过ack/nack反馈消息接收状态;2)Broker端的持久化机制,将消息和队列持久化到磁盘;3)消费者端的ACK事务机制,确保消息被成功消费。这些机制配合应用层的超时重传等逻辑,可以有效防止消息丢失。但需注意消息ID唯一性、幂等性处理等问题。通过完整可靠性方案,RabbitMQ能够
2025-07-08 12:28:33
976
原创 Java闭包是什么?5分钟让你搞明白
Java闭包是指Lambda表达式能够访问并"记住"外部变量的特性。文章通过函数式接口引入,解释了闭包的本质是"Lambda表达式+外部变量"。通过计算器、数据过滤等实例演示了闭包的实际应用,并指出Java闭包的限制:被捕获的变量需是final或等效final状态(不可修改)。最后总结闭包的核心概念:保存环境快照的函数,在Java中通过Lambda实现,常用于事件处理、数据转换等场景。
2025-07-07 21:18:16
372
原创 ThreadLocal内存泄漏 强引用vs弱引用
ThreadLocal内存泄漏问题分析:ThreadLocal通过ThreadLocalMap实现线程隔离,其中Entry对key使用弱引用,value使用强引用。若不调用remove方法,强引用的value会持续占用内存;而弱引用的key在ThreadLocal对象失去强引用后会被GC回收,形成Entry(null,value)的无效条目。虽然Map内部方法会清理无效条目,但线程池场景下线程复用会导致内存持续累积,最终可能引发OOM。建议使用后及时remove,同时弱引用机制能在一定程度上减轻key的内存
2025-07-07 16:27:49
411
原创 Redis的单线程和多线程(单Worker线程)
Redis采用单线程模型但性能依然高效的原因:6.0版本之前完全单线程处理I/O和逻辑,6.0后引入多I/O线程但核心Worker线程仍为单线程。其高性能得益于内存操作和简单命令处理,避免了多线程上下文切换的开销。Redis单线程设计权衡了性能与复杂度,适合处理高频但非复杂的操作场景。
2025-07-04 20:23:42
210
原创 自定义编解码器问题及解决
客户端:服务端:可以看到服务端打印了客户端查询的消息,那么证明服务端已经接收到了客户端的消息并且解析好了,那么Encoder和Decoer在RPCRequest这一消息的传递上是没有错误的。然后再具体分析错误。
2025-07-04 20:05:53
400
原创 自定义编码器和解码器报错java.lang.IndexOutOfBoundsException和NullPointerException空指针异常问题。
摘要:文章分析了自定义编码解码器出现的IndexOutOfBoundsException和NullPointerException异常问题。通过排查发现,服务端因读取数据不足导致异常,客户端因引用不同包的同名类导致编解码不一致。解决方案包括:1)在解码器中添加可读字节数检查,确保数据完整;2)统一客户端和服务端使用的类路径,避免因包名不同导致的编解码问题。优化后解决了异常和卡死问题,实现了正常通信。
2025-07-04 19:59:35
388
原创 消息队列:Redis Stream到RabbitMQ的转换
本文介绍了从Redis Stream迁移到RabbitMQ的消息队列方案。Redis Stream作为轻量级消息队列,具有低延迟但需轮询消费的缺点。RabbitMQ作为专业消息中间件,提供更完善的可靠性保证。文章详细说明了RabbitMQ的安装步骤(需先安装Erlang),Spring Boot集成方式(添加AMQP依赖),以及配置示例(包括普通队列、死信队列设置)。重点对比了两种方案的优缺点,并给出了代码实现,展示了如何通过RabbitMQ实现更高效的消息处理,包括手动ACK确认、消费者并发控制等关键配置
2025-06-29 19:01:07
874
原创 依赖注入:@Autowired和@Resource
如果没显式指定名字,但是按名称没找到,就会根据类型去容器中找匹配的Bean。如果找出来了多个,也会报错,只会返回找到的唯一匹配类型的Bean。Bean的默认名称是首字母小写的类型名,可以通过使用@Component、@Service、@Controller、@Bean等注解创建Bean的时候自定义该Bean的名称。Spring引入之后主动支持了这个注解,把它也作为了依赖注入的注解。在大型应用中,如果没有特殊需求,推荐使用@Autowired。继续 ------>继续 ------>继续 ------>
2025-06-29 00:40:56
717
原创 动态规划的“后效性”:一篇理解
动态规划的核心思想是将复杂问题分解为子问题,通过存储子问题的最优解来避免重复计算。无后效性确保了我们可以基于当前状态做出最优决策,而不需要回溯历史路径。这就像下棋时,我们只需要知道当前棋局状态就能决定下一步最优走法,而不需要知道棋局是如何演变到当前状态的。当问题的状态定义不足以支持无后效性时,我们需要扩展状态维度,将影响未来决策的所有必要信息都编码到状态中。这样,状态的定义包含了做出最优决策所需的全部信息,使得未来的最优决策只依赖于状态值,而不依赖于历史路径。
2025-06-13 10:46:43
445
原创 泛型的PECS原则
当这个泛型类是生产者,生成东西给我们读取的时候,我们使用?extends T。因为这样生成的东西,也就是我们读取的东西都是T的子类,我们可以很方便地使用T类型地变量接收而不会出错。当这个泛型类是消费者,也就是我们要向这个类写入数据的时候,我们使用?supper T,因为这样我们可以控制写入的数据永远都是T的父类,我们只要写入的数据都是T类型也就不会出错。上面的示例就是将source列表的值全部复制到target列表中,source是生产者,target是消费者。extends T, 何时使用?
2025-06-12 23:40:18
242
原创 传统Web应用和RESTful API模式
为什么我需要搞清楚这个呢,是由于学习Spring MVC的时候,Spring MVC的执行流程中的DispatcherServlet去解析Controller的返回值这个步骤困惑住了我,如果是RESTful API模式,其实就没有这个流程,如果是传统Web模式,就会又这个步骤。1. DispatcherServlet接收请求2. HandlerMapping找到Controller3. HandlerAdapter调用Controller方法。
2025-06-12 00:04:25
338
原创 深入理解二叉树遍历:递归与栈的双重视角
读者可以根据前序遍历的思路自行去理解中序遍历和后序遍历。重点就是理解系统的线程栈是怎么运作的,以及手动实现的栈是如何保存节点的。搞清楚了这两点,对二叉树的遍历的理解就会更上一层了。
2025-04-26 21:33:49
867
原创 Java 并行快速排序:Fork/Join 框架的高效应用与性能对比
本篇文章介绍了快速排序的原理,并通过Fork/Join 框架实现了 并行快速排序。通过实验对比,我们发现并行计算在大规模数据集上具有显著优势,是高性能数据处理中的重要优化手段。
2025-04-01 00:32:37
790
原创 装饰器模式:如何用Java打扮一个对象?
装饰器模式通过“动态增强”而非“本质改变”的设计理念,为软件设计提供了高度的灵活性和可扩展性。本文以生活中“换装打扮”的生动场景为引,巧妙类比了装饰器模式的核心思想——在不修改对象自身的基础上,通过层层叠加装饰器来扩展功能。核心价值体现:灵活组合,动态扩展如同男孩可根据场合自由切换妆容和服饰,装饰器模式允许在运行时动态添加或替换功能。例如,先穿简约服装,再化妆,最后换宴会礼服,每一步装饰都独立且可逆,避免继承带来的僵化性。职责分离,结构清晰。
2025-03-30 01:45:10
1019
原创 Java为什么要使用线程池?
之前对于Java线程池的理解,一直停留在:对于Java中的多线程机制来说,如果不使用线程池的话,线程的使用就会变得杂乱无章。这一步。一直没有深入去理解为什么其更深层次的原因,今天来仔细思考一下,并记录我自己的理解。
2025-03-26 23:03:45
496
原创 Java实现死锁
(Circular Wait): 线程形成环状等待。小明等勺子 -> 小红等叉子 -> 小明等勺子(循环了!(Mutual Exclusion): 资源一次只能被一个线程占用。只有一个叉子或者叉子,不能两个人同时用。(Hold and Wait): 线程持有资源的同时,还在等待其他资源。小明拿着勺子,还在等叉子。学习并发编程的死锁,之前在408的操作系统也学习过相关概念,今天使用Java代码自己实现了一下。(No Preemption): 线程持有的资源不能被强行拿走。勺子被小红拿了,不能抢。
2025-03-11 23:45:30
426
原创 匿名内部类
在日常编写代码的过程中,总是会遇到匿名内部类的使用,但是对这一块一直不是很熟,所以这里总结记录一下。可以看到,不需要额外写一个子类去重写父类Kp中的show方法,而是直接在匿名内部类中重写就行。使用了匿名内部类,我们就只需要知道该接口和要实现的方法就行了。可以发现,要想使用Kp这个接口,还要先为他写一个实现类。
2025-02-24 16:43:23
171
原创 全局唯一ID
时间戳就是获取当前时间的秒数,在redis中保存的键是根据当前日期存储的,然后值是自增的。每次获取一个全局ID,就是获取当前的秒数然后左移32位,最后再用或运算拼接自增的id。2.在一些分布式系统中,数据库要分库分表,如果不适用全局ID,会导致两个库中两个不同的东西拥有同一个ID,这就会产生逻辑上的错误。1.如果不用全局ID,只使用数据库自增的方式的话,这样自增出来的id规律性太明显,很容易被人得到一些敏感信息。3.使用雪花算法,雪花算法和使用Redis自增生成的全局ID思路类似。
2025-02-23 18:38:35
223
原创 Redis作为缓存和数据库的数据一致性问题
因为对数据库操作是很慢的,而对缓存操作是很快的,所以很容易出现下面一个情景:线程A先更新数据,线程B再读取数据,线程A删除了缓存,但是由于更新数据库的速度很慢,事务还未提交,线程B又进来了,它读取缓存但是缓存被删了就去读数据库,读取到了数据库中的数据返回给了客户端,同时将数据写到了缓存中,最后线程A更新数据库的操作终于完成了。那么此时就会进行1000次数据库的修改和缓存的修改,但是缓存的前999次修改都是无效的,造成了大量的时间和空间浪费,删除操作又比修改操作快,而且无数据时删除操作是不执行的。
2025-02-22 16:19:36
718
原创 对计算机中缓存的理解和使用Redis作为缓存
客户端在获取数据的时候,不会直接访问数据库,而是先去访问Redis缓存,看看Redis中是否有想要的数据,如果有就从Redis中获取并直接返回,如果没有才会再去数据库中获取并保存到缓存中,以便下次使用,这与CPU和Cache缓存之间的思路是一样的。下面两张图分别对应缓存命中和缓存不命中的情况,可以看到,添加了缓存之后,将常用数据保存到Redis中,确实可以让数据的获取多次从内存中获取而不是硬盘中,提高了不少性能。 而Redis作为非结构型数据库,它的数据是保存在内存中的,读写速度很快。
2025-02-22 13:51:05
452
原创 JAVA使用Scanner类的nextLint()方法无法正确读取中文。
在练习的时候,我发现我使用Scanner类的nextLint()方法无法正确读取到中文了。检查了我的idea编辑器,用的编码格式也是”utf-8“。所以编码格式没有问题。问题如下棉两张图所示,我输入宝马后,控制台不打印出来显示还是空的。微软自带输入法,idea2024.2,jdk21。当我使用复制的中文输入进去时候,就又可以了。还是idea版本太高的原因?并且当我在最后打印的时候,出现的也是空的。
2024-09-27 17:16:56
467
4
原创 JAVA后端程序拉取私人仓库的npm包并将该程序打包成jar包
你可以通过在你的 pom.xml 文件里的 标签中增加像下面这样的片段来完成这个整合。创建了一个测试程序,在其中的pom.xml文件中引入已经打包好的jar包(引入的仓库地址配置在settings.xml中,在这里也不过多赘述。程序会自动创建该文件夹,根据该路径将拉取下来的npm包存储到该目标文件夹中,如果该文件夹里已有内容,程序会依据同名覆盖的原则进行覆盖。当前有一个系统用于导出项目,而每次导出的项目并不可以直接使用,需要手动从npm私人。私有仓库中去,这样可以在pom.xml中引入即可使用。
2024-08-23 17:19:44
572
原创 JAVA后端拉取gitee仓库代码并打包成jar包
当前有一个系统用于导出项目,而每次导出的项目并不可以直接使用,需要手动从gitee代码仓库中获取一个模板代码然后将他们整合到一起它才是一个完整的项目,所以目前我的任务就是编写一个java程序可以自动地从gitee仓库拉取下来那个模板代码到指定地路径上去。即可看见在目标文件夹中拉取到了目标gitee仓库中的代码,这里要注意,在设置localPath的时候,所存的目标文件夹可以不存在,系统会自动创建,但是要保证所存的目标文件夹为空,否则会拉取失败。有很多种方式可以让 JGit 连接你的项目,并依靠它去写代码。
2024-08-23 17:16:37
519
原创 删除二叉搜索树中的节点,力扣405题
这种情况下,按照二叉搜索树的删除的官方做法,是找到它的前驱节点(左子树中最右边的结点),或者是找到它的后继结点(右子树中的最左边的结点)。将它作为根节点,然后原来的左子树作为新的左子树,原来的右子树作为新的右子树。// 同时,网上还有另外一种做法,就是将左子树整个的挂在右子树的最左边的结点的左孩子下,返回右子树的根作为新的根节点,这样也可以,但是这样好像会不断地增加树地高度,最终这个树会变成一个链表。// 2.左孩子为空,右孩子不为空,直接删除根结点,返回右孩子结点作为删除之后的树。
2024-08-22 13:41:39
236
1
原创 JAVA中的ArrayDeque和LinkedList实现Deque,前者不能存NULL结点,后者可以存放NULL。
在刷力扣的时候,在进行二叉树的题目训练时,需要用队列来存储二叉树的结点。因为使用ArrayDeque实现Deque习惯了,所以默认使用ArrayDeque来实现Deque。但是在运行的时候,发现这个dq中无法存入null空结点,会报空指针异常。于是尝试了使用LinkedList来实现Deque。可以看到在ArrayDeque会对加入的值进行判断,如果为空就会报出异常,而LinkedList不会。具体原因我也不清楚。这样再将null空结点存入这个队列就不会报错了,我分别查看了一下两者的源码。
2024-08-13 10:41:15
486
原创 下载安装ansible后,缺失pyyaml,pip安装时又出错,升级时又由于时Python2.7,不好升级遇到的一系列问题。
经过上一篇文章,我虽然误删了CentOs自带的python和yum,但是我重新将他们恢复了。这里记住默认的python版本是2.7.5。我使用yum安装好ansible后,检查我的ansible版本的时候,发生了错误,提示没有yaml模块。
2024-08-06 17:45:41
1177
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人