- 博客(33)
- 收藏
- 关注
原创 Mysql 中乐观锁和悲观锁是怎么实现的
乐观锁不是 Mysql 中内置的锁机制,而是一种基于版本控制的逻辑。悲观锁适用于,并发冲突严重的业务场景,需要确保操作绝对成功,且可以接受其他请求被阻塞等待的成本。事务开始读取数据时,要将数据加上一个排他锁,阻止其他事务修改。乐观锁适用于并发冲突没那么严重的业务场景,例如用户数据更新,性能较好但需要处理冲突。乐观锁,是比较乐观的,认为冲突不太经常发生,所以核心是先操作,提交时检查冲突。悲观锁,是比较悲观的,认为冲突很有可能发生,所以核心是先加锁,再操作。......(待续未完。诚恳欢迎大家提出意见。
2025-11-28 11:06:34
187
原创 计算机网络 - 在浏览器中输入 URL 地址到显示主页的过程?
第一步,浏览器通过 DNS 来解析 URL,得到相应的 ip 地址(到哪里找) 和 方法(做什么)第三步,建立好连接后,浏览器会组装 HTTP 请求报文,通过刚建立的 TCP 连接发送给服务器。第五步,浏览器在收到响应报文后就解析 HTML,CSS 和 Javascript,渲染页面。第四步,服务器在收到请求报文后,进行相应处理,之后返回 HTTP 响应。第六步,接着,完成数据传输后,通过四次连接断开 TCP 连接。第二步,浏览器于服务器建立 TCP 三次握手连接。诚恳欢迎大家提出意见。
2025-04-18 15:02:57
446
原创 计算机网络 - UDP协议
所以,依照 TCP 的可靠性保证,使用 UDP 的时候,可以为每个数据包附加序号,接收方返回 ACK,发送后启动计时器,利用滑动窗口机制控制发送速率,同时动态调整发送速率。TCP 的可靠性由多方面保证,比如序列号解决乱序问题,ACK 确保接收方成功接收,超时重传解决丢包问题,流量控制防止发送方压垮接收方,拥塞控制避免网络堵塞。,但是正因为 UDP 协议的控制字段较少,在数据传输过程中延迟小、数据传输效率高,适合对可靠性要求不高的服务。UDP是用户数据报协议,它是一种无连接的传输层协议,它没有可靠性保证。
2025-04-17 21:30:08
526
原创 计算机网络 - TCP协议
首先 TCP 是处在传输层的面向流的协议的协议,它本身不会按照应用开发者的期望,保持每次发送时都带有一个数据的边界,这可能导致接收端一次收到了多个应用层报文,需要应用开发者自己分开,也就是需要自己去实现“流”到“数据报”的功能。而如果发送方发送的太慢,数据就会有一定的延迟。而拥塞控制不同于流量控制,它主要强调的是网络的拥塞,导致发送方发的数据包被堵在了半路,而接收方迟迟没收到数据包并返回接收到的最后一个包的确认报文,会让发送方误以为这个包丢了并重新发送,这不仅会浪费信道资源,还会使原来拥塞的网络雪上加霜。
2025-04-16 15:25:59
708
原创 计算机网络 - 四次挥手相关问题
第二个目的的话,先等第一个 MSL 确保主动关闭端发出的最后一个 ACK 值从网络消失,再等第二个 MSL 是为了防止对端在收到这个 ACK 前的一刹那时间可能触发重传机制,等这个重传的 FIN 报文消失的时间也需要 1MSL,总共就是 2MSL。第三次挥手,服务端将剩余数据发送完成后,会发送一份携带 FIN 的报文给客户端,且指定一个序列号,告诉客户端自己也不再发送数据了,服务端处于 LAST-ACK 阶段。主要就是在一二次握手后,服务端可能还有遗留的数据需要处理,也就是需要确保数据的完整性。
2025-04-15 19:18:59
1106
原创 计算机网络 - 三次握手相关问题
但假如由于网络原因,客户端发送的第三次握手包丢失了,但接着发送的数据包正常被服务端接收,由于这个数据包也带有 ACK 的值,服务端就会把这个数据包当作第三次握手包,先建立连接再正常读取数据。这个问题 RFC 文档中提到过,第三次握手时,客户端向服务端返回的报文中可以携带数据,即使此时服务端是 SYN_REVEIVED 状态,但由于数据报中也带有 ACK 的值,服务端接受之后会先确定这个 ACK,然后建立连接,进入 ESTABLISHED 状态,之后就能正常接受这个数据包了。
2025-04-14 21:11:36
759
2
原创 JVM - 垃圾回收器常见问题
G1 垃圾回收器,将堆内存分为许多个 Region 块,最多有 2048个,每块 Region 块的大小必须是 2 的倍数,例如 1MB,2MB。这个过程,就会不断产生新的对象,许多对象也会失去引用。接着进行到重新标记阶段,因为第二阶段又产生了许多新对象,所以这个阶段要继续让其他工作线程停下来,然后重新标记下第二阶段新创建的对象,还有一些已有对象可能失去引用变成垃圾的情况。如果垃圾回收的时候,其他应用线程也在进行,可能回导致数据不一致,比如刚把一个垃圾回收掉了,而后面突然又引用到了,引用内存回收错误。
2025-03-28 15:55:33
518
原创 JVM - 垃圾回收基本问题
比方说 JVM 内存结构中的虚拟机栈,虚拟机栈中有栈帧,栈帧里面存储着有指向堆的对象引用,那么位于虚拟机栈顶就可以称作是 “活跃” 的栈帧,因为此刻它正在被线程调用。标记复制算法,简单来说,就是将新生代空间分为两部分,把新创建的对象放在其中一块,等要进行垃圾回收的时候,则先将存活对象移动到另一块空间当中,然后将垃圾对象回收。如果没有垃圾回收机制的话,则存放对象的内存空间很快就会被塞满,所以为了保证系统能正常地执行,就必须要有垃圾回收机制,回收掉没有被使用的对象,也就是垃圾对象。诚恳欢迎大家提出意见Orz。
2025-03-27 20:52:07
644
原创 JVM - 类加载相关
应用程序加载器(Application ClassLoader):这个类加载器就负责去加载 “ClassPath” 环境变量所指定的路径中的类,简单来说,就是加载你自己写的 Java 代码中的类。打破双亲委派思路就是在加载类时,不按照依次往上匹配类加载器的方式加载。当应用程序类加载器需要加载一个类时,会先委派给其父类加载器,即扩展类加载器,接着扩展类加载器又委派给启动类加载器。接着启动类加载器找不到这个类,则会交给扩展类加载器,如果扩展类加载器也找不到,又会交给应用程序类加载器执行。
2025-03-27 11:12:04
1135
原创 JVM - 年轻代和老年代
每一次 Minor GC 之前,会检查老年代老年代可用空间是否大于年轻代所有对象大小,因为可能 GC 之后,所有的年轻代对象都存活下来了。大致规则就是,假设当前放对象的 Survivor 区中,有一批对象的总大小大于了这块区域的 50%,则所有年龄大于等于这批对象年龄的对象,都可以直接进入老年代。Young GC之前,如果加入堆内存的对象足够大,则直接进入老年代,可通过 JVM 参数 “-XX:PretenureSizeThreshold” 来设置这个值,单位是字节。小于的话,则会进行 Full GC。
2025-03-26 09:24:28
677
原创 Mysql - 锁常见问题
行锁可以做到只锁定需要操作的记录行或间隙,具体可以分为记录锁,间隙锁和 临建锁,也就是记录锁加间隙锁的组合,它锁的是一个范围。虽然用户 A 和用户 B 在 T1,T2时刻都看到还有一件商品,但最终只有用户 A 在 T3 时刻能够获得最后一件商品,此时 version 自赠为 1,那么用户 B 在 T4 时刻将无法看到这条记录,也就无法购买成功。对于行锁来说,数据行是可以加上锁的实体,但其实数据行之间的间隙也是可以加上锁的实体,对于的锁就是间隙锁。按照锁的粒度,可以分为全局锁,表级锁和行锁。
2025-03-17 22:46:14
377
原创 Mysql - 日志相关问题
可以的,由于每个事务执行时,在提交事务前都会将对数据的修改记录到 undo log 中,现在假设 Mysql 正在执行某个事务时突然宕机,如果此时事务还没有提交,那么恢复时系统会通过 undo log 依次对数据进行相反操作,比如已经 insert 了一条记录,那么就 delete 这条记录等等,对这个未完成的事务进行回滚,确保事务的原子性;redo log 是 InnoDB 独有的,记录的是某个数据页做了什么修改,每执行一个事务就会产生相应的 redo log。其中还用到 WAL 技术。
2025-03-17 22:16:57
691
原创 Mysql - 事务基础
在 RR(可重复读)隔离级别下,当一个事务开始时,会生成唯一的事务 ID,当事务需要更新数据时,Mysql 并不会直接修改原始数据,而是将原始数据先复制一份,并将其版本号 +1,再将更新的内容写进 undo log。即开启事时,看到的数据是静态的,能很好解决不可重复的问题,不过会遇到幻读的问题。这个级别下的事务,做的数据操作没提交就能被其他事务看到,具有很好的并发性,不过容易发生脏读,不可重复读等问题。,每个事务都是相互隔离,不能相互影响,在事务提交前,事务的操作是对外不可见的。
2025-03-11 22:59:31
704
1
原创 Mysql - InnoDB 和其他存储引擎的区别
而内存表的索引都是一样的,根据数据位置走一次查找即可。而且 Memory 的数据是存储在内存当中的,数据不支持持久化,但会有速度快的优势。Memory 引擎比较适用于需要内存临时表的场景,内存临时表数据量小,不容易被其他线程访问,没有并发性问题。同时,临时表重启后数据需要删除,这也符合内存表的特性。而 InnoDB 表有行锁,能很好的处理并发,而且 InnoDB 的数据会写入磁盘当中,数据不容易丢失。其他情况都建议使用 InnoDB,因为 InnoDB 可以较好的处理并发量高的事务,同时能持久化数据。
2025-03-10 11:52:25
373
1
原创 Mysql - 自增主键的使用细节
使用身份证号做主键的每个非主键索引叶子节点的大小约为 20 字节,而如果使用自增主键,则只要 4 个字节,如果是长整型也就 8 个字节。INT 类型的自增主键的最大数是 2^32 - 1(4294967295),如果达到这个值,后面再插入的话,得到的值将会保持不变。可以看到,第一条插入语句还是成功的,第二条插入语句就失败了,证明了 INT 类型的自增主键超过了最大值后申请的 id 还是一样的。2. 自增主键的话,如果用 INT,会有 int 最大数限制,如果超过 int 最大数,你觉得应该怎么办?
2025-03-10 11:19:14
273
原创 Mysql - 索引分类相关
当需要更新一个数据页中,而数据页又没在内存当中,就会将更新操作记录在 change buffer 中,当下次查询该数据页时,将数据页读入内存,就会执行 change buffer 中与这个页有关的操作。对于一个整型字段,一个数据页是可以存放许多 key的,所以连续相同的值充满整张数据页的概率是很低的,即代表普通索引可以在一个数据页中完成查询,所以二者查询性能并没有多少差距。除主键索引外,其他索引就是非主键索引,也可以视作辅助索引。这里主要是主键索引,非主键索引,唯一索引,普通索引,联合索引等等。
2025-03-06 23:26:18
982
原创 Mysql - 索引优化相关
亦或者 sql 语句本身没有什么问题,而是 Mysql 统计基数出现差错,使用错了索引,我们可以通过 explain 来查看语句的执行计划,再通过 FORCE INDEX 强制使用索引来进行对比,从而排查速度慢的原因。一般情况下,给一些频繁需要使用的字段,和一些区别度高的字段加索引是比较合适,其次还要考虑字段的长度,过长会占用空间,过短会导致区分度减低,比如身份证号只取前 6 位情况。比如电商支付下的订单表。当然,还有第二种方法,我们可以考虑修改语句,引导 Mysql 使用我们期望的索引,比如,
2025-03-06 10:04:20
881
原创 Mysql - 索引底层实现
同时,B+ 树非叶子节点只存储键值,叶子节点才存储具体数据,这样会使树的整体大小缩小,方便内存可以一次性加载更多的节点。B 树也是一种多叉树,不过 B 树的节点会存储具体的数据,所以相同大小的磁盘页,B 树可以容纳的键值更少。B 树相对于其它数据结构,磁盘访问性能还是较优的,大多数用在文件系统中,比如在 Windows NTPS 文件系统中,每个目录对应着一个 B 树节点,可以快速地对文件进行查找和访问,提高文件系统性能。除了主键索引,还有非主键索引,非主键索引中只有索引值和对应的主键索引,并没有行记录。
2025-03-04 15:27:36
473
原创 Java集合 - ArrayList 和 LinkedList
ArrayList 的默认容量是 10,当需要扩容时,会先申请一个容量为旧数组 1.5 倍的新数组,然后将旧数组复制到新数组当中去。但在执行插入和删除节点时,会涉及数组的复制和移动,所以复杂度为 O(n)ArrayList 的话,会先以 O(1) 的时间定位到第 k 个元素,然后将被这个数组分割的两部分复制拼接到一个新数组上,整体为 O(n)LinkedList首先会用 O(n) 的时间定位到第 k 个元素,然后花 O(1)的时间去进行 remove,总体也为 O(n)诚恳欢迎大家提出意见Orz。
2025-03-02 22:47:18
300
原创 Java基础 - final关键字的理解和使用时机
被 final 修饰过的类,不能被继承。Java 的核心类库中就有许多类被 final 修饰,比如 String 类,为了保证 String 类的不可变性,Java 设计者就通过 final 关键字来禁止这些核心类被修改。还有 final 修饰的方法,不能被子类重写,就是为了防止方法逻辑被修改,保证方法逻辑的稳定性。final 在英文中的意思是:最终的,不可更改的,其实它的作用就可以从英文本意中引导出来。final 是 Java中的一个关键字,它可以修饰类,方法,属性。诚恳欢迎大家提出意见Orz。
2025-03-01 23:34:27
257
原创 Java基础 - 抽象和接口的区别?
抽象类还是像个正常类一样,可以有字段,可以有构造器,可以有方法。每一个继承这个接口的类都必须实现接口中所有的方法,因为接口中声明的方法,默认被定义为 abstract。的关系,通过代码复用,允许定义通用属性和方法,但每个子类也有自己独特的属性和方法。例如鸟是动物,老虎也是动物,它们都会吃,都会叫,不过鸟没有老虎的四条腿,老虎没有鸟的翅膀。所以,构造器是起到一个强制作用,尽管抽象类无法实例化,但其构造器通过子类的实例化过程简接发挥作用,体现了面向对象编程中 "抽象与实现分离" 的思想。
2025-02-26 23:04:03
180
原创 Java基础 - 重载和重写的区别
在 JVM 中,方法重载对应 "静态分配" 的过程,即在编译期就能根据参数的静态类型,决定使用哪个方法。而方法重写则是对应 "动态分配" 的过程,重载指在一个类中定义多个方法,它们具有相同的函数名,重写是指在子类中重新定义或覆盖父类中的方法,在运行的过程中,JVM 根据实际调用对象类型。但参数的类型,个数和和顺序可能有所不同。它提供了一种灵活的方式来实现相似的功能。其返回类型,方法名,参数必须相同。诚恳欢迎大家提出意见Orz。......(待续未完。,来决定使用哪个方法。
2025-02-26 22:26:32
163
原创 Java集合 - HashMap
当 HashMap 遇到哈希冲突的时候,会采用 "链地址法" ,即每个数组的槽位都会对应一个链表,相同哈希值的键值对就会存储到一个链表中去,如果链表上的元素数量达到阈值,比如 JDK 1.8 是 8,链表就会转化为红黑树。比如 JDK 1.8 在进行扩容操作时,HashMap 会先创建一个新的数组,并将数据进行迁移,如果多个线程同时要将数据迁移,两个线程判断一个槽位为空,并一起进行 put 操作,那么后面的数据会覆盖先 put 进行的数据。会的,当红黑树的节点小于 6 的时候,就会从红黑树转化为链表。
2025-02-26 15:36:08
758
3
原创 Java基础 - Java为什么被称为平台无关性语言
好,首先我们得知道,啥叫平台无关性语言顾名思义,即和平台没有关系的语言,......哈哈,开个玩笑。平台无关性语言,简单概括就是 "一次编译,到处运行",其关键在于 JVM拿 c 语言来对比,编译器会根据当前电脑的操作系统,来生成只有当前操作系统能识别的机器码,要想在其他操作系统上运行,得重新编译源代码,才能成功而 Java 编译器是生成平台中立的字节码(.claa),而非直接生成机器码。字节码不直接依赖操作系统,但需 JVM 作为桥梁适配具体平台。比如 开发者A 在 Windows 上编写并编译 Java
2025-02-25 22:43:25
140
2
原创 Java基础 - 介绍一下 Object类 常见方法?
wait() 和 notify() 可以实现一个简单的 "生产-消费" 模型:生产者产生消息后,调用 notify() 叫醒消费者。返回对象的字符串表示,默认为 [class 名 + @ + hashCode 的十六进制表示],类经常会重写该方法,用来满足自己的设计需求,比如调用和打印日志。默认情况使用的就是 ==,基本数据类型比较的是具体值,引用数据类型比较的是引用地址,类可以重写该方法,来实现自己的判断逻辑。是通过一些简单的算法,根据对象的信息,例如内存地址,映射成一个数值,这个值就称为哈希值。
2025-02-25 22:21:05
166
原创 Java基础 - equal() 方法 和 == 有什么区别
equal() 是超类 Object 中的一个方法,== 是一个操作符,对于没有重写 equal() 的类来说,二者基本没有什么区别,因为源码中 equal() 默认使用的就是 ==== 如果比较的是基本数据类型,则就是比较具体的值,例如 int 类型。== 如果比较的是引用数据类型,则就是比较引用对象的内存地址是否相同。对于重写了 equal 方法的类,则根据实际重写逻辑来比较。(贴一张 JDK 8 源码图)诚恳欢迎大家提出意见Orz。......(待续未完。
2025-02-24 22:59:25
163
原创 Java基础 - equals() 和 hashCode() 为什么一般要一起重写?
将两个 name 和 age 相同的 Person 对象放入到 HashSet 的时候,HashSet 会先根据对象的哈希值判断是否为同一个对象,再进行放入。这时,如果没有重写 hashCode(),那两个对象的哈希值肯定是不一样的,所以就会将两个对象当做不同的对象都放入到集合中去,这肯定是 Person 类不希望的。hashCode() 也是 Object 类中的方法,通过一些简单的算法将对象的信息比如内存地址,映射成一个数值,这个值就称为哈希值。诚恳欢迎大家提出意见Orz。......(待续未完。
2025-02-24 22:50:02
241
原创 Java基础 - String
性能又从常量池设计和缓存哈希值这些方面着手,每次创建一个 String 对象,都会缓存自己的哈希值,因为 String 是不可变的,使用时,就不需要重新计算了,这使得 String 适合用来作为 Map 的 key,可以快速获得 key 的哈希值,提高查找和比较的效率;不过根据实际 JVM 堆内存的限制,编译时String长度最多可以是2的16次方减2,运行时长度最多可以是2的31次方减1,意思是可以在编译时定义一些短的字符串,运行时可以进行拼接,长一点也可以。诚恳欢迎大家提出意见Orz。
2025-02-23 23:07:16
921
原创 Java基础 - 多态
举个例子,电商项目中的支付模块,其中有个基类 Payment,基类中有 pay方法。另外,如果想修改支付代码,就可以分别到两个子类中去修改,无须修改主逻辑中的代码,体现了多态的灵活性等价值。多态,是面向对象编程的三大特性之一(封装,继承,多态),其核心价值在于可以提高代码的灵活性,可扩展性和好维护。简单来说,多态,其本质就是 "一个接口,多种实现",即在不同的上下文中,同一个操作可以表现为不同的行为。除此之外,还有编译时多态,即在编译过程中通过调用方法的参数不同,来决定使用的哪个方法,就是通过重载体现的。
2025-02-23 21:10:45
155
原创 Java基础 - 异常
例如有个工具类,现在有多个业务需要使用到该工具类的某个方法,而该方法可能会出现例如空指针异常,而每个业务当遇到该情况时,相应处理的方法可能不同。而 throws 是在方法签名后声明的,更像是一种被动声明,使用 throws 不一定有异常抛出,如果没有声明,方法后面默认会抛出运行时异常。其次,有多个方法可能会出现相同类型的异常,使用 try-catch 会使程序更加冗余,而直接 throw ,在调用这些方法的地方整体 try-catch,统一进行处理就比较好。诚恳欢迎大家提出意见Orz。
2025-02-22 22:54:56
498
原创 进程间的通信方式杂谈
这时候可以通过一种叫共享内存的方式来处理数据教大的情况,这种方式又如何实现呢?以上说的四种通信方式都是一个主机中的进程间的通信方式,而不同主机间的进程也能进行通信,其方式就是 socket,例如平时用浏览器向服务器发送一个 httl请求,而服务器给你返回对应的数据,这种就是采用 socket通信方式了。信号量的本质就是计数器,例如,默认一块内存空间的信号量的值是0,当 a进程访问这块内存空间的时候,我们就把其信号量的值设为1,当 b进程也想访问这块内存的时候,看到信号量的值为 1,就不能访问了。
2024-09-22 23:46:06
242
原创 快慢指针杂谈
例如求链表的中间节点时,快指针一次走两步,慢指针一次走一步,当快指针到达链表尾部时,慢指针就恰好指向了链表的中点,二者走的距离比例一直都是2:1。又例如求链表的倒数第 k个节点时,快指针先走 k步,然后二者一起运动,当快指针走到链表尾部时,慢指针就距离快指针(链表末尾)k远。要想处理这一类问题,必须要知道,
2024-09-01 19:23:00
201
原创 c语言函数杂谈
2.为了更方便(后期维护和修改)更安全(防止打错函数名等)的使用函数,应该把函数原型统统放在一个头文件当中(注意,只是放原型,并不需要放函数源代码)4.若函数没有给出原型,则编译器认为该函数返回一个整型值(注意,值的类型并不是值的内在本质,而是取决于它的使用方式,因此才有强制转换)1.一个函数如果要求返回指针,但函数的参数只有数组,则可通过取地址符&来返回数组中某个元素的地址。5.函数的参数均以“传值调用”的方式传递,即传递的只是数值的一份拷贝,在函数内并不能做到改变参数。
2024-03-18 22:39:57
433
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅