三十、MVCC(多版本并发控制器)

事务隔离级别的无锁实现方式,提高事务的并发性能。

事务隔离级别:解决多个事务并发产生的问题。

​ 读未提交:会产生脏读:事务1修改某个值,事务2读取的是事务1修改的值,但事务1失败执行回滚。

读已提交:产生不可重复读问题;

重复读:解决幻读

串行化:

​ MVCC:隐藏列(DB_TRX_ID:当前数据由哪个事务id维护的(持有),DB_ROLL_PTR:当前数据修改前的数据的指针,维护主键id)

三十一、用户忘记密码为什么只能重置密码

系统不知道用户的密码

md5加密(24字符):只能加密不能解密,抗碰撞性不强(哈希冲突,密码可能会一样),同一字符串生成密文一样。(加盐,程序内密码拼接随机字符串)

sha256(64字符):每次生成密文一样,碰撞性增强。

BCrypt(60长度):spring添加依赖即可使用.

三十二、Java实现简单的消息队列

生产者消费者模式,队列,生产者,消费者,锁。

package org.springframework.boot.pradco;

import javax.swing.text.TableView;
import java.util.concurrent.ArrayBlockingQueue;

public class test {
    //声明一个数组队列(最大长度)
    //消息队列
    private int queueSize=10;
    private ArrayBlockingQueue<Integer> queue=new ArrayBlockingQueue(queueSize);

    public static void main(String[] args) {
        //实例化类
        test test=new test();
        //创建一个消费者,持续监听
        Consumer consumer=test.new Consumer();
        consumer.start();
        //循环生产
        for (int i = 0; i < 10; i++) {
            Producer producer=test.new Producer();
            producer.start();
        }
    }
    //生产者
    class Producer extends Thread {
        @Override
        public void run() {
            //保证生产者线程安全
            synchronized (queue){
            //判断当前队列长度是否小于最大长度
            if(queue.size()<queueSize){
                //小于就生产消息
                //向队列添加一条消息
                queue.add(queue.size()+1);
                //唤醒消费者
                System.out.println("添加了一条消息"+queue.size());
               queue.notify();
                //模拟业务处理
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
                else{
                //大于生产者停止工作
                try {
                    queue.wait();
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                    //出现异常,手动唤醒
                    queue.notify();
                }
            }
            }
        }
    }
    //消费者
    //写一个消费者(consumer)继承Tread
    class Consumer extends Thread{
        //重写Run方法
        @Override
        public void run() {
            //死循环持续输出
            while(true){
                //添加同步锁保证线程安全
                synchronized (queue){
                    //队列为空,线程停止
                    if(queue.isEmpty()){
                        System.out.println("当前为空队列");
                        try {
                            queue.wait();
                        } catch (InterruptedException e) {
                           e.printStackTrace();
                           //出现异常,手动唤醒
                           queue.notify();
                            //模拟业务处理
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e1) {
                                e1.printStackTrace();
                            }
                        }
                    }else{
                        //消费头部消息
                        Integer poll = queue.poll();
                        System.out.println("消费了一条消息"+poll+"  "+queue.size());
                        //唤醒生产者
                        queue.notify();
                    }
                }
            }
        }
    }
}

这段代码实现了一个经典的 生产者-消费者模式,通过 ArrayBlockingQueue 和线程同步机制来协调生产和消费行为。

核心结构:

  1. 消息队列:使用 ArrayBlockingQueue<Integer> 作为共享缓冲区,容量为10
  2. 生产者线程 (Producer):
    • 继承 Thread 类,每次向队列添加一条消息(值为当前队列大小+1)
    • 使用 synchronized(queue) 保证线程安全
    • 队列满时调用 queue.wait() 等待
    • 生产完成后调用 queue.notify() 唤醒消费者
  3. 消费者线程 (Consumer):
    • 继承 Thread 类,通过 while(true) 持续监听队列
    • 使用 synchronized(queue) 保证线程安全
    • 队列为空时调用 queue.wait() 等待
    • 消费完成后调用 queue.notify() 唤醒生产者
  4. 主方法流程
    • 创建一个消费者线程并启动(持续监听)
    • 循环创建10个生产者线程并启动(每个生产一条消息)

同步机制:通过 wait()/notify() 实现线程间通信,确保生产者不会向满队列写入,消费者不会从空队列读取。

三十三、线上突发bug本地正在开发新需求

git,提交分支当下,复制一个线上版本进行修改,merging到想合并的分支。

1.暂存正在开发的分支(dev)。

2.严重的话先回滚到上一个版本,不严重在(fix)分支修改。

3.十分紧急:直接合并到(master分支),上线

一般:合并到(release)分支,测试,上线

非紧急:合并到dev分支,测试,上线

三十四、RestTemplate如何优化连接池

默认没有连接池,进行远程访问,每次创建一个http链接

HTTP client:配置依赖,修改redistemplate默认的http工厂

三十五、用锁实现线程安全,并将性能提升到极致

使用synchronized锁的对象根据情况认定,比如一个考试系统根据不同的班级分类,锁的是班级号性能就会更高,同一个班级会使用锁串行,不同班级并行。(class.intern()获取到字符串常量,锁这个锁的就是常量而不是字符串)但是常量是共享的会影响加入班级的性能。

三十六、策略模式+简单工厂+模板方法

三十七、springBoot防止反编译

使用 classfinal-maven-plugin 对编译后的 class 文件加密

运行时通过 -javaagent 加载解密代理,内存中实时解密

防止反编译拿到源码,保护核心代码(如 AI 密钥、RAG 配置、支付逻辑)。

<build>
    <plugins>
        <!-- ClassFinal 加密插件 -->
        <plugin>
            <groupId>net.roseboy</groupId>
            <artifactId>classfinal-maven-plugin</artifactId>
            <version>1.2.2</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>encrypt</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <!-- 加密密码 -->
                <password>abc123456</password>
                <!-- 要加密的包名 -->
                <packages>com.zhou.book,com.zhou.ai</packages>
                <!-- 排除启动类不加密(必须) -->
                <exclude>com.zhou.BookApplication</exclude>
                <!-- 是否开启项目启动后删除 lib 下加密包 -->
                <delete>false</delete>
            </configuration>
        </plugin>
    </plugins>
</build>

然后进行打包,运行方法

java -javaagent:xxx-encrypted.jar=abc123456 -jar xxx-encrypted.jar

三十八、spring正常springBoot报错的问题

1.重名bean:spring后面的会覆盖前面的但在sprigBoot中会报错。

spring:
  main:
    allow-bean-definition-overriding: true

**2.循环依赖:**spring是兼容的但是SpringBoot不兼容。

spring:
  main:
    allow-circular-references: true

**3.@Value获取不到值:**spring会直接将表达式设置为值,但springboot会报错

spring:
  context:
    resourceloader:
      ignore-unresolvable: true

**4.Aop默认动态代理实现:**spring默认使用jdk,但是SpringBoot默认使用CGLIB

spring:
  aop:
    proxy-target-class: false

三十九、记录mybatis的sql耗时

四十、SpringBoot敏感信息如何加密

SpringBoot + Jasypt 配置文件加密

1.配置依赖

<!-- Jasypt 加密 Starter -->
<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>3.0.5</version>
</dependency>

2.生成密文

import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;

public class JasyptUtil {
    public static void main(String[] args) {
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        // 加密密钥(自己定义,启动时传入)
        encryptor.setPassword("zhou_2025_abc");
        // 要加密的原文:数据库密码、Redis密码、AI密钥等
        String encrypt = encryptor.encrypt("root123456");
        System.out.println("加密后:" + encrypt);
    }
}

java -cp jasypt-1.9.3.jar org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="root123456" password="zhou_2025_abc" algorithm=PBEWithMD5AndDES

3.yml配置

spring:
  # 数据库加密配置
  datasource:
    username: root
    # 密码用 ENC() 包裹
    password: ENC(QeKzJZ9x8xJz9xJz9xJz9xJz9xJz9xJz9)
    url: jdbc:mysql://localhost:3306/book_store?useSSL=false

  # Redis 密码也可以加密
  redis:
    host: localhost
    port: 6379
    password: ENC(xxxxxxx)

# Jasypt 核心配置(指定加密算法)
jasypt:
  encryptor:
    algorithm: PBEWithMD5AndDES

4.启动

命令方法

java -jar xxx.jar --jasypt.encryptor.password=zhou_2025_abc

IDEA启动(Run/Debug Configurations → VM options)

-Djasypt.encryptor.password=zhou_2025_abc

四十一、微服务feign第一次调用为什么这么慢

第一次要初始化负载均衡(load balance),从nacos拉取服务,http的三次握手四次挥手。

前两个启动时即加载

loadbalancer.eager-load.enabled=true
关闭懒加载,启动时就初始化负载均衡器

第三个可以添加连接池。

四十二、jvm锁机制揭秘

MarkWord都存储了什么标记位,为什么升级为偏向锁后对象头会发生变化,如果对象正处于偏向锁被其他线程抢了会怎么样。

new一个对象堆中就会记录这个对象的信息,其中有一个MarkWord的区域。

MarkWord:8个字节64个bit位组成; 会根据所的状态记录不同的内容。

当我们创建一个对象会有未使用区域(25bit),hashcode区域(31bit),用于垃圾回收的分代年龄,后三位记录锁的信息(无锁状态为001)。如果使用synchronizd锁住后就会升级为偏向锁,前54位保存持有当前锁的线程ID,后三位变成101,jdk15后撤销掉偏向锁,升级为轻量级锁,并行获取升级为重量级锁。

总结:默认无锁状态,单线程同步锁升级为轻量级锁,多线程交替执行,串行就会升级位轻量级锁(CAS判断是否被其他线程持有),多线程并行竞争升级为重量级锁(操作系统的monitor组件实现互斥,用户态》》内核态)。

四十三、直播间多人同时点赞

极高写入,海量读取,极致实时,成本平衡

前端:1s内将点赞数聚合,只发一次请求

业务层:单个用户点赞数量限制

网关层:再次聚合

后端:使用MQ流量削峰。(redis使用incr增加)

消费端统计:redis增加后数据同步到本地缓存,redis中的数据异步同步到数据库。

智能推送:定时进行随机取样少量推送。

四十四、线上redis怎么部署

1.单实例模式:简单,服务器宕机不可用,内存大小有限,有数据丢失风险。

2.主从+哨兵:读写分离(一主用来写入,两从用来读取),数据备份,海量数据存储存在瓶颈。

哨兵:定期向主节点发送消息检测,如果主节点无响应,将从节点选择一个作为主节点。

3.分片集群+一致性Hash:

更多推荐