【MySQL 死锁:从 “业务卡顿“ 到 “根因定位“ 的实战指南】

MySQL 死锁:从 “业务卡顿” 到 “根因定位” 的实战指南

后端开发必看:MySQL死锁排查与预防全攻略

线上系统突然报出Deadlock found when trying to get lock; try restarting transaction,用户操作卡顿甚至超时,排查时却对着一堆日志无从下手?这篇文章帮你彻底搞定MySQL死锁问题!

一、先搞懂:死锁的"本质"和"必要条件"

很多人把"锁等待"当成死锁,其实二者完全不同:

  • 锁等待是"一个事务等另一个事务释放锁"(比如事务A没提交,事务B等着改同一行数据),等事务A提交后,事务B就能继续
  • 死锁是"多个事务互相等对方释放锁",陷入无限循环,最后MySQL只能"牺牲"一个事务来打破僵局

死锁的"4个必要条件"

MySQL死锁的产生,必须同时满足4个条件(少一个都不行),搞懂这4点,就能明白死锁的"软肋"在哪里:

  1. 互斥条件:锁资源是"独占的",一个事务拿了锁,其他事务只能等(比如行锁,事务A锁住一行后,事务B不能再拿同一行的写锁)
  2. 持有并等待条件:事务已经拿了至少一个锁,又在等其他事务持有的锁(比如事务A拿了行1的锁,又等着拿行2的锁,同时事务B拿了行2的锁,等着拿行1的锁)
  3. 不可剥夺条件:事务拿到的锁不能被"抢"走,只能自己释放(比如事务A拿了锁,除非它主动提交/回滚,否则其他事务不能强制让它释放)
  4. 循环等待条件:多个事务形成"环形等待链"(比如A等B的锁,B等C的锁,C等A的锁)

既然死锁需要4个条件同时成立,那预防死锁的核心思路就很明确:打破其中一个条件(比如避免循环等待、减少"持有并等待"的时间)。

死锁和"锁等待超时"的区别

很多同学会把Lock wait timeout exceeded(锁等待超时)和死锁搞混,其实二者的触发机制完全不同:

  • 锁等待超时:事务A持有锁,事务B一直等A释放,等了超过innodb_lock_wait_timeout(默认50秒)还没等到,就会报这个错(是"单方面等待超时")
  • 死锁:多个事务互相等待,MySQL的"死锁检测器"(每隔一段时间运行)发现了循环等待,就会主动选择一个"代价小"的事务回滚,报Deadlock found...(是"双向循环等待,MySQL主动干预")

简单说:锁等待是"一个等一个,等不及了";死锁是"互相等,谁也走不了,MySQL强行拆局"。

二、3个真实场景:死锁是怎么"造"出来的?

死锁不是凭空产生的,几乎都是"业务逻辑 + SQL执行顺序"共同导致的。下面3个场景你可能或多或少遇见过,我们逐一拆解死锁的产生过程。

场景1:"交叉更新"引发的死锁(最常见)

业务背景:电商订单系统,用户支付后需要"扣减库存"和"更新订单状态",两个事务分别操作两行数据,但更新顺序相反。

事务1(用户A支付)

-- 步骤1:扣减商品1库存
UPDATE product_stock SET stock = stock - 1 WHERE product_id = 1;
-- 步骤2:更新订单1001状态为"已支付"
UPDATE orders SET status = 'PAID' WHERE order_id = 1001;

事务2(用户B支付)

-- 步骤1:更新订单1001状态为"已支付"
UPDATE orders SET status = 'PAID' WHERE order_id = 1001;
-- 步骤2:扣减商品1库存
UPDATE product_stock SET stock = stock - 1 WHERE product_id = 1;

死锁产生过程

  1. 事务1执行"扣减库存",拿到product_stock表中product_id=1的行锁
  2. 同时,事务2执行"更新订单",拿到orders表中order_id=1001的行锁
  3. 事务1继续执行"更新订单",需要orders表中order_id=1001的行锁,但这把锁被事务2拿着,于是事务1开始等
  4. 事务2继续执行"扣减库存",需要product_stock表中product_id=1的行锁,但这把锁被事务1拿着,于是事务2开始等
  5. 此时,事务1等事务2的锁,事务2等事务1的锁 —— 形成循环等待,死锁产生

为什么会这样:两个事务操作的是"同一批资源"(库存行 + 订单行),但更新的顺序相反,满足了"持有并等待"和"循环等待"两个条件。

场景2:"间隙锁"引发的死锁(容易被忽略)

业务背景:用户表userage字段(无索引),两个事务同时按age范围更新数据,InnoDB的"间隙锁"可能导致死锁。

事务1

-- 更新age在10-20之间的用户状态
UPDATE user SET status = 1 WHERE age BETWEEN 10 AND 20;

事务2

-- 更新age在15-25之间的用户状态
UPDATE user SET status = 1 WHERE age BETWEEN 15 AND 25;

死锁产生过程

  1. InnoDB中,若查询条件是"范围"且字段无索引,会触发"间隙锁"(锁定一个范围的"间隙",防止幻读)
  2. 事务1执行时,age BETWEEN 10 AND 20会锁定(10,20)之间的间隙(包括边界)
  3. 事务2执行时,age BETWEEN 15 AND 25会锁定(15,25)之间的间隙,这两个范围有重叠(15-20)
  4. 此时,事务1可能需要访问事务2锁定的间隙(比如15-20),事务2也需要访问事务1锁定的间隙,双方互相等待,触发死锁

为什么会这样:间隙锁的"范围重叠"导致了循环等待,而且很多人容易忽略"无索引时范围查询会加间隙锁"这个特性,排查时往往想不到是锁的范围出了问题。

场景3:"事务长 + 锁竞争"引发的死锁(高并发下常见)

业务背景:秒杀系统,高并发下多个事务同时"创建订单→扣减库存→记录日志",事务执行时间长,持有锁的时间也长。

事务流程(每个秒杀请求)

-- 步骤1:创建订单(写orders表)
INSERT INTO orders (order_id, user_id, goods_id) VALUES (...);
-- 步骤2:扣减库存(更新goods表)
UPDATE goods SET stock = stock - 1 WHERE goods_id = 100;
-- 步骤3:记录秒杀日志(写seckill_log表)
INSERT INTO seckill_log (log_id, order_id) VALUES (...);
-- 步骤4:(业务逻辑处理,比如调用其他服务,耗时1-2秒)
-- 步骤5:提交事务
COMMIT;

死锁产生过程

  1. 高并发下,事务A执行到步骤2(扣减库存,持有goods表行锁),但因为步骤4有业务逻辑,没及时提交
  2. 事务B也执行到步骤2,需要goods表的行锁,开始等事务A释放
  3. 事务C执行步骤1(创建订单),持有orders表的行锁,继续执行步骤2时,也开始等事务A释放goods表的锁
  4. 此时,事务A可能因为某种原因(比如需要查询订单状态),尝试访问事务C持有的orders表行锁,而事务C在等事务A的goods表行锁 —— 形成循环等待,死锁产生

为什么会这样:事务太长(步骤4耗时)导致锁持有时间久,高并发下锁竞争激烈,原本"单一方向"的等待可能因为"事务回查资源"变成循环等待。

三、死锁排查:3个工具 + 1个核心日志

遇到死锁别慌,MySQL自带了排查工具,关键是要找到"死锁时各事务持有了什么锁、在等什么锁"。掌握下面3个工具和1个核心日志,就能快速定位死锁根因。

1. 实时查看死锁:show engine innodb status

这是排查死锁的"第一手资料",执行后能看到最近一次死锁的详细信息(包括事务ID、SQL语句、锁信息等)。

操作步骤:在MySQL客户端执行:

show engine innodb status\G;

关键信息解读(以场景1的交叉更新为例)

------------------------
LATEST DETECTED DEADLOCK
------------------------
2024-05-20 10:00:00
*** (1) TRANSACTION:
TRANSACTION 12345, ACTIVE 2 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 10, OS thread handle 1234, query id 5678 localhost root updating
UPDATE orders SET status = 'PAID' WHERE order_id = 1001*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 10 page no 3 n bits 72 index PRIMARY of table `test`.`orders` trx id 12345 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0*** (2) TRANSACTION:
TRANSACTION 12346, ACTIVE 2 sec starting index read
mysql tables in use 1, locked 1
2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 11, OS thread handle 5678, query id 5679 localhost root updating
UPDATE product_stock SET stock = stock - 1 WHERE product_id = 1*** (2) HOLDING THE LOCK(S):
RECORD LOCKS space id 10 page no 3 n bits 72 index PRIMARY of table `test`.`orders` trx id 12346 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 11 page no 4 n bits 72 index PRIMARY of table `test`.`product_stock` trx id 12346 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0*** WE ROLL BACK TRANSACTION (1)

重点看这几点

  • TRANSACTION 12345TRANSACTION 12346:两个死锁的事务ID
  • 每个事务下的UPDATE语句:能看到事务在执行什么操作
  • WAITING FOR THIS LOCK TO BE GRANTED:事务在等什么锁(比如事务12345在等orders表的X锁)
  • HOLDING THE LOCK(S):事务已经持有什么锁(比如事务12346已经持有orders表的X锁)
  • 最后一行:MySQL选择回滚哪个事务(这里回滚了事务12345)

通过这些信息,能快速还原"谁持有什么锁、在等什么锁",进而定位到业务代码中的SQL顺序问题。

2. 监控锁等待:information_schema.innodb_locks和innodb_lock_waits

如果死锁不是"实时发生",而是偶尔出现,可以通过这两个系统表查看当前的"锁持有情况"和"锁等待情况"。

常用查询语句

-- 查看当前持有锁的情况
SELECT * FROM information_schema.innodb_locks;-- 查看当前锁等待的情况(谁在等谁的锁)
SELECT r.trx_id waiting_trx_id,  -- 等待锁的事务IDr.trx_mysql_thread_id waiting_thread,  -- 等待锁的线程IDr.trx_query waiting_query,  -- 等待锁的SQLb.trx_id blocking_trx_id,  -- 持有锁的事务IDb.trx_mysql_thread_id blocking_thread,  -- 持有锁的线程IDb.trx_query blocking_query  -- 持有锁的SQL
FROM information_schema.innodb_lock_waits w
JOIN information_schema.innodb_trx b ON w.blocking_trx_id = b.trx_id
JOIN information_schema.innodb_trx r ON w.requesting_trx_id = r.trx_id;

结果解读innodb_lock_waits的结果会清晰显示"等待事务ID、等待的SQL、持有锁的事务ID、持有锁的SQL",比如场景1中,会看到"事务12345在等事务12346的锁,事务12346在等事务12345的锁",直接印证循环等待。

3. 开启死锁日志:innodb_print_all_deadlocks(推荐线上开启)

show engine innodb status只能看到"最近一次死锁",如果死锁频繁发生,可能会覆盖之前的记录。开启innodb_print_all_deadlocks后,MySQL会把所有死锁信息写入错误日志(error log),方便后续分析。

开启方式

  1. 临时开启(重启MySQL后失效):

    set global innodb_print_all_deadlocks = 1;
    
  2. 永久开启(修改my.cnf):

    [mysqld]
    innodb_print_all_deadlocks = 1
    

日志位置:错误日志的位置可以通过show variables like 'log_error';查看,通常在/var/log/mysql/error.log(Linux)或C:\ProgramData\MySQL\MySQL Server 8.0\Data\XXX.err(Windows)。

日志中会记录每次死锁的详细信息(和show engine innodb status的死锁部分一致),方便追溯历史死锁。

四、死锁预防:5个实战方案(从代码到配置)

排查死锁是"事后补救",预防死锁才是"治本之策"。结合前面的死锁产生原因和条件,这5个方案能有效减少死锁发生的概率。

1. 统一资源访问顺序(打破循环等待)

这是预防"交叉更新"死锁最有效的方法 —— 让所有事务操作同一批资源时,按固定的顺序访问。

比如场景1中,两个事务都需要操作"库存行"和"订单行",可以约定"先操作库存行,再操作订单行",无论业务逻辑如何,都严格遵守这个顺序:

事务1(用户A支付)

-- 步骤1:先扣减库存(固定顺序第1步)
UPDATE product_stock SET stock = stock - 1 WHERE product_id = 1;
-- 步骤2:再更新订单(固定顺序第2步)
UPDATE orders SET status = 'PAID' WHERE order_id = 1001;

事务2(用户B支付)

-- 步骤1:先扣减库存(和事务1顺序一致)
UPDATE product_stock SET stock = stock - 1 WHERE product_id = 1;
-- 步骤2:再更新订单(和事务1顺序一致)
UPDATE orders SET status = 'PAID' WHERE order_id = 1001;

这样一来,事务2执行步骤1时,如果事务1已经持有库存行的锁,事务2会等待;但事务1执行步骤2时,不会再等事务2的锁(因为事务2还在等步骤1的锁),不会形成循环等待,死锁就不会产生。

实操技巧:可以给资源(比如订单ID、商品ID)排序,按"从小到大"或"从大到小"的顺序访问,比如"先操作ID小的行,再操作ID大的行"。

2. 减少锁持有时间(打破"持有并等待")

事务持有锁的时间越短,锁竞争的概率就越低,死锁也越难发生。核心是"让事务尽快提交",避免在事务中做"非必要操作"。

优化方案

  • 把"耗时的业务逻辑"放到事务外执行(比如调用第三方接口、复杂计算)
  • 事务中只做"必要的数据库操作"(增删改查),执行完立即提交
  • 避免在事务中使用SELECT ... FOR UPDATE(行级锁)做"预查询",除非确实需要

反例→正例

-- 反例:事务中包含耗时业务逻辑,锁持有时间长
START TRANSACTION;
-- 步骤1:数据库操作(拿锁)
UPDATE goods SET stock = stock - 1 WHERE goods_id = 100;
-- 步骤2:耗时操作(调用第三方支付接口,耗时1秒)
-- 步骤3:数据库操作
INSERT INTO orders (...) VALUES (...);
COMMIT;-- 正例:事务只包含数据库操作,耗时操作放外面
-- 步骤1:先执行耗时操作(无锁)
call third_party_pay(...);
-- 步骤2:事务中只做数据库操作,快速提交
START TRANSACTION;
UPDATE goods SET stock = stock - 1 WHERE goods_id = 100;
INSERT INTO orders (...) VALUES (...);
COMMIT; -- 立即提交,释放锁

3. 避免间隙锁(针对范围查询)

间隙锁是InnoDB为了防止"幻读"引入的,但在某些场景下(比如字段无索引、范围查询)会导致锁范围扩大,引发死锁。可以通过以下方式减少间隙锁:

  • 给查询字段加索引:InnoDB对有索引的字段做范围查询时,只会锁定"存在的行",不会锁定间隙(除非使用FOR UPDATE且是RR隔离级别)
  • 使用RC隔离级别:InnoDB在READ COMMITTED(RC)隔离级别下,会关闭间隙锁(除了外键约束和唯一性检查),减少锁范围
  • 避免用"范围条件"更新数据:如果能明确"主键/唯一索引条件",就别用BETWEENIN等范围条件

示例

-- 反例:age无索引,范围更新触发间隙锁
UPDATE user SET status = 1 WHERE age BETWEEN 10 AND 20;-- 正例1:给age加索引(减少间隙锁范围)
ALTER TABLE user ADD INDEX idx_age (age);-- 正例2:用RC隔离级别(关闭间隙锁)
SET tx_isolation = 'READ-COMMITTED';-- 正例3:用具体条件代替范围(如果业务允许)
UPDATE user SET status = 1 WHERE age = 10 OR age = 11 OR ...; -- 明确值

4. 合理设置事务隔离级别

InnoDB的默认隔离级别是REPEATABLE READ(RR),会启用间隙锁;而READ COMMITTED(RC)隔离级别下会关闭间隙锁,虽然可能出现"不可重复读",但在大部分业务场景下是可接受的,且能减少死锁。

修改隔离级别

  1. 临时修改(当前会话):

    set session transaction isolation level read committed;
    
  2. 永久修改(my.cnf):

    [mysqld]
    transaction-isolation = READ-COMMITTED
    

注意:RC隔离级别下,SELECT ... FOR UPDATE仍会锁行,但不会锁间隙,适合对"幻读"要求不高的业务(如电商订单、用户管理)。

5. 主动重试死锁事务(最后一道防线)

即使做了前面的预防措施,高并发下仍可能出现死锁。此时可以在业务代码中"捕获死锁异常",主动重试事务,减少对用户的影响。

Java代码示例

// 重试次数
private static final int MAX_RETRY = 3;public void processOrder() {int retryCount = 0;while (retryCount < MAX_RETRY) {try {// 执行事务操作transactionTemplate.execute(status -> {updateStock(); // 扣减库存updateOrderStatus(); // 更新订单return null;});break; // 成功则跳出循环} catch (Exception e) {// 判断是否是死锁异常if (e.getMessage().contains("Deadlock found when trying to get lock")) {retryCount++;log.warn("发生死锁,第{}次重试", retryCount);// 可选:短暂休眠,避免立即重试再次冲突Thread.sleep(100);} else {// 其他异常,直接抛出throw e;}}}
}

注意:重试次数不宜过多(建议3-5次),且重试间隔可以加个"随机值"(比如50-200ms),避免多个事务同时重试再次冲突。

五、总结:死锁处理的"黄金流程"

遇到死锁不用慌,记住这个"黄金流程",从排查到解决一步到位:

  1. 查日志:用show engine innodb status或错误日志(开启innodb_print_all_deadlocks)获取死锁详情,明确"各事务持有什么锁、在等什么锁"
  2. 找原因:根据锁信息和SQL语句,判断是"交叉更新"(顺序问题)、“间隙锁”(范围查询问题)还是"长事务"(锁持有时间问题)
  3. 做优化:按场景选方案 —— 交叉更新就统一访问顺序,间隙锁就加索引或降隔离级别,长事务就减少锁持有时间
  4. 留后手:代码中捕获死锁异常,主动重试,降低用户感知

死锁的本质是"资源竞争下的循环等待",只要能打破死锁的4个必要条件中的一个,就能有效减少死锁。实际开发中,最优先做的是"统一资源访问顺序"和"减少锁持有时间"—— 这两个方案成本低、效果好,大部分死锁都能通过这两点解决。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/98113.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/98113.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从虚拟化基石到云原生架构的降维打击:用dd/mkfs玩转namespace隔离,解锁Docker/K8S资源密码,看透物理机到云服务器的进化之路

本篇摘要 本文围绕虚拟化与容器化技术展开&#xff0c;涵盖架构演进、Docker/K8S优势与挑战、namespace隔离实操&#xff08;如主机名/PID隔离&#xff09;、磁盘操作&#xff08;dd/mkfs/df/mount&#xff09;等&#xff0c;对比虚拟机与容器差异&#xff0c;阐明技术原理与架…

自动化测试的概念

文章目录自动化测试能够取代人工测试吗&#xff1f;回归测试自动化分类自动化测试金字塔为啥单元测试的性价比这么高呢&#xff1f;那为啥UI自动化测试的性价比没有组件测试的高呢&#xff1f;web自动化测试举例引入自动化测试的准备工作自动化测试的简单示例自动化测试能够取代…

OSPF故障排查实战:如何通过一条命令精准定位网络掩码不匹配问题

掌握display ospf error命令的解读技巧&#xff0c;快速解决OSPF邻接关系建立失败难题。一、问题背景与场景引入 在网络运维工作中&#xff0c;OSPF&#xff08;开放最短路径优先&#xff09;协议作为主流的内部网关协议&#xff0c;其稳定运行至关重要。然而&#xff0c;在实际…

Redis----如何引入分布式锁

一、概述首先引入分布式锁指的是应用程序引入&#xff0c;不是Redis本身引入&#xff0c;Redis作为中间件可以作为分布式锁的一个典型实现方案&#xff0c;同时也有一些其他的实现方案。分布式锁指的是一个/组程序&#xff0c;使用Redis实现的话就是通过添加一个特殊的Key-Valu…

prometheus-2.42.0.linux-amd64.tar.gz 安装配置展示

一、prometheus 1.1解压文件 # tar -xzvf prometheus-2.42.0.linux-amd64.tar.gz -C ~/apps/ prometheus-2.42.0.linux-amd64/ prometheus-2.42.0.linux-amd64/NOTICE prometheus-2.42.0.linux-amd64/consoles/ prometheus-2.42.0.linux-amd64/consoles/index.html.example p…

Linux 标准输入 标准输出 标准错误

目录一. 简介二. 常见用法2.1 输出重定向2.2 错误重定向2.3 同时重定向标准输出 错误2.4 输入重定向2.5 特殊设备三. 这样设计的好处3.1 区分正常信息和错误信息3.2 方便调用方脚本处理3.3 与管道结合时更清晰四. 案例4.1 if判断4.2 ls查询一. 简介 ⏹在 Linux/Unix 中&#…

零基础新手小白快速了解掌握服务集群与自动化运维(二)Linux Journalctl命令、Journalctl日志持久化存储

Linux提供了一个强大的日志系统&#xff0c;它可以跟踪和记录系统的各种活动。在这个系统中&#xff0c;journalctl是一个非常重要的工具&#xff0c;用于查询和操作由systemd进程管理的日志。 本文将深入探讨journalctl命令&#xff0c;介绍其基本使用、高级选项及示例等内容…

【学习】【js】栈数据结构

栈 栈是一种遵从后进先出&#xff08;LIFO&#xff09;原则的有序集合。新添加或待删除的元素都保存在栈的同一端&#xff0c;称作栈顶&#xff0c;另一端就叫栈底。在栈里&#xff0c;新元素都靠近栈顶&#xff0c;旧元素都接近栈底。 基于数组的栈 时间复杂度O(n),占用较多的…

【Linux】基本指令 · 下

alias 指令起别名为什么 ls -l 指令等价于 ll 指令呢&#xff1f;指令就是可执行程序&#xff0c;和我们自己写的代码编译好的程序&#xff0c;没有本质区别&#xff01; 指令在系统的某一个位置存在&#xff01; 执行指令前&#xff0c;现在系统中查找对应的指令指令在根目录下…

计算机视觉(opencv)实战二十二——指纹图像中提取特征点,计算两两指纹之间的相似度

指纹识别原理与代码实现详解指纹识别是一种常见的生物特征识别技术&#xff0c;广泛应用于门禁系统、手机解锁、考勤打卡、身份认证等场景。其核心思想是&#xff1a;从指纹图像中提取特征点&#xff0c;计算两幅指纹之间的相似度&#xff0c;并根据相似度判断是否为同一人。本…

Linux基础之部署mysql数据库

文章目录一、环境准备二、源码解压与依赖三、CMake 编译配置四、配置 MySQL权限管理修改配置文件 /etc/my.cnf五、环境变量设置六、数据库初始化七、服务管理八、账号密码管理一、环境准备 yum -y install gcc gcc-c ncurses ncurses-devel bison cmakegcc / gcc-c&#xff1a…

代码审计-PHP专题原生开发文件上传删除包含文件操作监控Zend源码解密1day分析

快速分析脆弱&#xff1a;1、看文件路径2、看代码里面的变量&#xff08;可控&#xff09;3、看变量前后的过滤文件安全挖掘点&#xff1a;1、脚本文件名2、应用功能点3、操作关键字文件上传&#xff0c;文件下载(读取)&#xff0c;文件包含&#xff0c;文件删除等emlog-文件上…

零基础搭建 Hexo 博客:从本地到 GitHub Pages 全流程指南

零基础搭建 Hexo 博客&#xff1a;从本地到 GitHub Pages 全流程指南 Hexo 是一个快速、简洁且高效的博客框架&#xff0c;支持使用 Markdown 来编写文章&#xff0c;并能快速生成静态网页&#xff0c;非常适合想要搭建个人博客的同学。本文将带你从零开始&#xff0c;本地搭建…

Git 简介

Git 是目前全球最流行的分布式版本控制系统&#xff08;Distributed Version Control System, DVCS&#xff09;&#xff0c;核心作用是追踪文件修改历史、支持多人协同开发&#xff0c;并能高效管理代码&#xff08;或任何文本类文件&#xff09;的版本迭代。它由 Linux 内核创…

后端Web实战-Spring原理

目录 1. 配置优先级 2. Bean管理 2.1 获取Bean 2.2 Bean作用域 面试题&#xff1a;Lazy是如何解决循环依赖问题的&#xff1f; 2.3 第三方Bean 3. SpringBoot原理 3.1 起步依赖 3.2 自动配置 3.2.1 概述 3.2.2 自动配置的原理及常见方案 3.2.2.1 概述 3.2.2.2 方案…

在 Qoder 等 AI 二创 IDE 里用 VS Code Remote-SSH 的“曲线连接”实战

目标&#xff1a;让你在 Qoder 等在线/AI 辅助 IDE 中&#xff0c;也能像本地 VS Code 一样通过 Remote-SSH 连接到自己的远程服务器进行开发。 前提&#xff1a;只在你拥有或被授权的服务器上使用&#xff0c;遵守所用平台的条款与限制。两句话说清楚 先用本地 VS Code 正常连…

python发送请求SSL验证设置

这个错误通常是由于SSL/TLS握手失败导致的&#xff0c;可能原因包括证书验证问题、不兼容的加密协议或网络连接中断。以下是几种解决方案&#xff0c;按推荐顺序排列&#xff1a; 方案一&#xff1a;临时禁用SSL验证&#xff08;快速测试&#xff09; response requests.get(u…

工厂自动化正从 “人工堆叠” 向 “设备替代” 快速转变

​人工进行零件排列&#xff0c;虽在操作灵活性上有一定表现&#xff0c;但实际应用中存在明显短板&#xff0c;对工厂自动化转型形成制约。从成本来看&#xff0c;一名工人日均工资约数百元&#xff0c;若需 5-6 名工人协同作业&#xff0c;月均人力成本易突破万元&#xff0c…

中标麒麟7.4部署gitlab-runner

1. 部署环境 本次部署环境完全断网。需要离线下载gitlab-runner及其依赖。 本次部署环境为中标麒麟7.4。目前机器上部署了gitlab&#xff0c;安装了maven。 2. 部署步骤 2.1 在外部下载好依赖 我首先在腾讯云上布置了一个centos7.9的虚拟机&#xff0c;没有安装任何东西。 …

在 IDEA 2024 创建 Vue 项目(保姆级)

目录 一、 前后端分离 1. 简介 2. 实现前后端分离的常用前端框架 3. 前后端分离和动静分离 3.1 前后端分离: 3.2 动静分离: 二、 Vue.js概述 1. 简介 2. SPA介绍 2.1 优点 2.2 缺点 3. MVVM介绍 3.1 示例 三、 名词解释 1. Node.js 2. npm 3. webpack 4. Vue…