news 2026/10/6 13:26:34

Ubuntu 22.04 部署 MySQL 8.0 实战:从安装到主从同步全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Ubuntu 22.04 部署 MySQL 8.0 实战:从安装到主从同步全指南

前阵子帮朋友在一台全新的Ubuntu 22.04服务器上部署MySQL,顺手翻了不少教程,结果发现一个很普遍的问题:网上的教程大量停留在MySQL 5.7时代,很多命令和配置在8.0上要么失效,要么有隐藏的坑。最典型的就是root账号的默认认证方式,Ubuntu的apt源安装的MySQL 8.0默认用的是auth_socket,而不是caching_sha2_password,导致很多人“设了密码”之后依然无法远程登录、甚至本地登录都报错。这篇文章我就把这套流程完整走一遍,从零开始,覆盖安装、安全初始化、root认证修复、远程访问、防火墙、基础调优,一直到xtrabackup备份和GTID主从同步的思路,最后再补一个Docker Compose部署的对比,希望能帮你少踩几个坑。

文章适用于两类读者:一类是第一次在Ubuntu 22.04上装MySQL、需要一份能直接照着敲的新手,另一类是想在测试环境快速验证备份恢复、主从复制方案的运维,虽然不会深入到生产级参数调优,但关键节点的思路和坑都会讲到。

1. 安装前的环境准备:为什么我推荐apt源安装而不是二进制包

1.1 Ubuntu 22.04自带的MySQL版本与选型

Ubuntu 22.04(Jammy)的官方软件源里默认带的是MySQL 8.0.x版本。国内很多云厂商的镜像源也都同步了这个版本。我查了一下当前源里的具体版本号,一般在8.0.3x左右,具体以apt-cache policy mysql-server显示为准。

选型上我强烈建议直接用apt源安装,理由很简单:

  • 依赖自动处理:MySQL Server在Ubuntu上有大量依赖包(libaio、libmecab、libjson-c等),用apt安装会自动把这些依赖一并装上,二进制包方式还得手动处理一堆运行时库。
  • 服务管理集成:apt安装后会自动注册为systemd服务,systemctl start/stop/restart mysql就能管理,省去自己写启动脚本的麻烦。
  • 升级路径清晰:后续MySQL发布小版本更新,apt upgrade就能平滑升级,二进制包方式升级要重新解压覆盖,容易出权限错乱。

你可能想问,那为什么不直接用Docker?这个我放在文章最后专门对比,先按原生安装走。

1.2 先更新软件源并检查系统基础组件

在开始安装之前,先把系统更新到最新状态,这一步不是可有可无的。我遇到过几次因为libaio版本过旧导致后续MySQL启动失败的情况,根源就是系统没有先整体更新。

sudo apt update sudo apt upgrade -y

中间如果有内核更新,建议重启一下服务器,让新内核生效。不重启的话,后续MySQL装好后虽然能跑,但某些系统调优参数可能受旧内核限制,影响性能表现,尤其是vm.swappiness这类参数。

顺手把必要的基础工具装上,MySQL安装过程会用到:

sudo apt install -y net-tools curl wget gnupg lsb-release

其中gnupg和lsb-release在后面添加Percona仓库(用于安装xtrabackup)时会用到,先装好不亏。

1.3 检查端口占用:3306被占用的处理

在正式安装之前,先确认一下3306端口是否被占用。有些云服务器镜像会预装别的数据库(比如MariaDB),而MariaDB和MySQL的包在Ubuntu里是冲突的,直接apt install mysql-server可能会报错。

sudo ss -lntp | grep 3306

如果已经占了,先确认是什么进程:

sudo lsof -i:3306

如果是MariaDB,先停掉并卸载:

sudo systemctl stop mariadb sudo apt remove --purge mariadb-server mariadb-client -y sudo apt autoremove -y

这一步一定要做干净,否则后面装MySQL时,mysql_install_db会因为数据目录里残留的旧库文件直接报错。

2. 核心安装流程:从apt install到安全初始化脚本

2.1 安装mysql-server

在确保环境干净之后,执行安装命令:

sudo apt install mysql-server -y

安装过程Ubuntu会自动启动MySQL服务。安装完成后,检查状态:

sudo systemctl status mysql sudo systemctl enable mysql

enable这一步是把MySQL设为开机自启,默认情况下apt安装后其实会自动启用,但手动执行一次更保险,尤其是你装过其他数据库、可能改过systemd配置的情况下。

验证MySQL是否真的能正常工作:

sudo mysqladmin ping

如果返回mysqld is alive,说明服务正常。

2.2 安全初始化脚本:mysql_secure_installation逐项讲解

装好后,MySQL默认的安全配置很松,这就是为什么要跑一遍安全初始化脚本。执行:

sudo mysql_secure_installation

这里有一个跟5.7不一样的地方:8.0版本安装完成后,root账号默认是auth_socket认证(后面详细讲),所以这个脚本会以sudo身份让你直接进入MySQL来配置,而不是要你先输入root密码。脚本会依次问你以下几个问题:

  1. 是否设置密码验证组件(VALIDATE PASSWORD COMPONENT):建议选Y,但密码策略先选LOW(只校验长度),避免后续开发调试时因密码规则太严格而烦躁。生产环境再按需调成MEDIUM或STRONG。
  2. 设置root密码:注意这里的root是MySQL的root,不是操作系统的root。
  3. 删除匿名用户(Remove anonymous users):选Y。匿名用户是安全大忌,尤其是MySQL默认监听将通过后续配置开放到局域网时。
  4. 禁止root远程登录(Disallow root login remotely):选Y。这个建议选Y,后续我们会单独创建一个管理账号用于远程连接,root只保留本机登录权限。
  5. 删除test数据库并访问(Remove test database and access to it):选Y。test库有权限漏洞,留着没用。
  6. 重新加载权限表(Reload privilege tables now):选Y,让所有改动立即生效。

每一步的含义我简单解释一下:MySQL的权限系统是分层的,mysql.user表存储全局权限,mysql.db存储数据库级权限,匿名用户如果存在,会在连接时被MySQL优先匹配,导致你新建的普通用户反而拿不到预期权限,所以必须清理干净。

2.3 安装后的目录结构速览

这一步是为了让你后续排查问题时能快速找到对应文件:

  • 数据目录:/var/lib/mysql,所有数据库文件、binlog文件都在这里
  • 配置文件:/etc/mysql/mysql.conf.d/mysqld.cnf,这是最主要的配置入口
  • 错误日志:/var/log/mysql/error.log
  • systemd服务文件:/lib/systemd/system/mysql.service

有个脚本化安装的细节:如果你需要批量部署多台机器,mysql_secure_installation没法直接传参数,但可以通过debconf预置回答。不过8.0版本这个脚本内部用的是mysqladmin和SQL语句执行,预置比较麻烦,我的做法是安装后用一段SQL在多台机器上统一执行,后面统一修改root认证部分会讲到。

3. root账号认证方式的坑:8.0的auth_socket改成密码登录

3.1 为什么默认root登录不需要密码

这里必须花点篇幅说清楚。Ubuntu源安装的MySQL 8.0,root账号默认使用auth_socket插件认证。这个插件的认证逻辑是这样的:只要当前操作系统用户是root(或者sudo切换成root),就能直接通过socket连接MySQL,不需要输密码。

设计初衷是安全——root账号只在系统本机使用,避免暴力破解和远程探测。但实际使用中很多人不适应:明明设置了密码,却始终无法用密码登录;改配置想远程连,发现root根本连不上;甚至用Navicat等客户端本地连接也失败。

查看当前root的认证方式:

SELECT user, host, plugin FROM mysql.user WHERE user = 'root';

正常情况下会看到root的plugin是auth_socket。

3.2 修改认证方式的具体SQL

将root改为caching_sha2_password密码认证,执行以下SQL即可:

ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY '你的强密码'; FLUSH PRIVILEGES;

需要注意:8.0默认情况下mysql_native_password插件虽然还存在,但官方已经标记为废弃,新客户端(包括MySQL Shell、最新版本的Navicat)都能正常支持caching_sha2_password,没必要继续用旧的。

改完后,退出再重新登录验证:

mysql -u root -p

如果密码能正常登录,说明修改成功。

3.3 我这边的踩坑记录:一次权限表误操作

网上不少人教“直接UPDATE mysql.user SET plugin='mysql_native_password'”,这种方法不是说完全不行,但风险很大。我曾经在一次操作中直接UPDATE整个user表,把user和host字段也顺带改了,导致MySQL重启后拒绝所有连接,最后只能通过--skip-grant-tables方式进入数据库修复权限表。那次之后我养成了一个习惯:修改认证方式一律用ALTER USER,不动user表本身。

还有一个隐藏问题:如果你之前执行过ALTER USER把root改成了密码认证,然后又用mysql_secure_installation重新跑了一遍,脚本会要求先输root密码才能继续。所以顺序上我的建议是:先跑安全初始化脚本,再修改认证方式。

4. 配置远程连接:bind-address、用户授权与防火墙

4.1 修改监听地址

MySQL默认只监听127.0.0.1,也就是只能本机连接。要允许其他机器通过局域网访问,需要修改配置文件:

sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf

找到这一行:

bind-address = 127.0.0.1

改成:

bind-address = 0.0.0.0

重启MySQL使配置生效:

sudo systemctl restart mysql

改完后检查监听状态:

sudo ss -lntp | grep mysql

如果显示0.0.0.0:3306或具体网卡IP,说明监听已经开放。

这里有一个值得注意的点:如果你的服务器有多个网卡(比如内网A、公网B),不要直接设0.0.0.0,最好指定具体的内网IP,避免公网端口暴露。比如:

bind-address = 192.168.1.100

4.2 创建专用账号并授权

远程连接不推荐用root,原因不言自明——root权限太大,一旦被爆破,整个数据库就完了。正确的做法是创建专用业务账号:

CREATE USER 'devops'@'192.168.1.%' IDENTIFIED BY 'StrongPassw0rd!'; GRANT ALL PRIVILEGES ON *.* TO 'devops'@'192.168.1.%'; FLUSH PRIVILEGES;

'devops'@'192.168.1.%'表示仅允许192.168.1网段的机器连接,比'%'(允许所有IP)安全得多。如果确实需要允许所有IP访问(开发环境常见),可以使用'devops'@'%',但生产环境强烈不建议。

单独给业务应用建账号时,最好遵循最小权限原则:

CREATE USER 'app_user'@'%' IDENTIFIED BY 'AppPassw0rd!'; GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'app_user'@'%'; FLUSH PRIVILEGES;

能看到区别吗?业务账号只给了某个数据库的增删改查权限,连DROP、CREATE都没给,这样即使账号被拖库,影响面也有限。

4.3 防火墙配置:ufw和云安全组

Ubuntu 22.04默认使用ufw防火墙。如果你启用过ufw(检查sudo ufw status),需要放行3306端口:

sudo ufw allow from 192.168.1.0/24 to any port 3306 proto tcp sudo ufw reload

只放行指定网段访问,而不是sudo ufw allow 3306这种全开放方式,这是我装过N台机器后总结的经验:全开放意味着公网也能访问,加上云服务器控制台还有一层安全组,两层的规则如果都太宽松,那就等于裸奔。

云服务器(阿里云、腾讯云、AWS等)还需要在控制台的安全组/防火墙规则里也放行对应端口,这个别漏了,很多人改了服务器里的ufw,却忘了安全组那层,结果还是连不上。

4.4 远程连接的测试

在另一台机器上测试:

mysql -h 192.168.1.100 -u devops -p

如果提示Access denied,优先检查账号的host范围是否覆盖了你的来源IP:

SELECT user, host FROM mysql.user;

如果提示Can't connect to MySQL server(10060/2003),优先检查防火墙和安全组,其次是bind-address配置。

5. 基础性能调优:一套适用于16G内存主机的my.cnf配置

5.1 关键参数解释

MySQL装完默认配置其实是非常保守的,它要考虑在最低配机器上也能跑起来。如果你的是16G内存的主机,不改配置直接上业务,用不了多久就会遇到性能瓶颈。我最常用的一套基础调优配置如下:

[mysqld] # 缓冲池大小,建议设为物理内存的50%-70% innodb_buffer_pool_size = 8G innodb_buffer_pool_instances = 8 # 日志相关 innodb_redo_log_capacity = 1G max_binlog_size = 512M binlog_expire_logs_seconds = 2592000 # 连接数 max_connections = 500 max_connect_errors = 1000 # 临时表 tmp_table_size = 64M max_heap_table_size = 64M # 慢查询日志 slow_query_log = 1 slow_query_log_file = /var/log/mysql/slow.log long_query_time = 2 # 排序和join缓冲 sort_buffer_size = 4M join_buffer_size = 4M

各参数的作用简单说明一下:

innodb_buffer_pool_size是最核心的参数,InnoDB引擎的索引和行数据在内存中的缓存池大小。8G缓冲池意味着热数据基本都在内存里,磁盘的随机读次数会大幅下降。但设置太大会导致内存不足,触发Swap,反而更慢,所以50%-70%是经验值。

innodb_redo_log_capacity在8.0.30之后取代了旧的innodb_log_file_size,Redo Log大小直接影响崩溃恢复的速度和写入吞吐量,1G是比较合适的起步值。

binlog_expire_logs_seconds取代了废弃的expire_logs_days,单位是秒,2592000就是30天,避免binlog把磁盘塞满。

tmp_table_size和max_heap_table_size需要一起设置,否则内存临时表超限后会转成磁盘临时表,复杂查询会慢得离谱。

5.2 应用配置并验证

修改配置文件后重启:

sudo systemctl restart mysql

验证参数是否生效:

SHOW VARIABLES LIKE 'innodb_buffer_pool_size'; SHOW VARIABLES LIKE 'max_connections';

这里有个细节:innodb_buffer_pool_size修改后,MySQL冷启动时会有初始化和预热过程,第一次重启会慢几秒,属于正常现象,不用惊慌。

5.3 一个调优的反面教训:连接数和线程池

有一次我图省事,把max_connections直接设成5000,想着反正内存大。结果连续两个星期出现连接数飙升、CPU耗尽的情况。排查下来发现,一个业务连接池配置不合理,每个Tomcat实例默认建了200个连接,几个实例一叠加,瞬间把数据库连接榨干。后面把连接数调回500,同时优化了业务的连接池配置,系统才稳定下来。所以说:调优不是调一个参数就完事,要先看业务背压的方向,再动手改。

6. 备份与扩容:xtrabackup备份主库和GTID主从同步思路

如果你只是学习安装配置,到第5节就可以收官了。但既然标题里有“部署”,部署就意味着要考虑备份和扩展,这也是最近后台私信里问得最多的话题:怎么备份MySQL主库?怎么部署从库?GTID同步到底怎么玩?我把关键流程列一遍,细节每个都可以单独写一篇,这里先给完整路线。

6.1 安装XtraBackup

XtraBackup是Percona开源的物理备份工具,相比mysqldump逻辑备份,它的优势是备份速度快、支持热备、恢复时能保留InnoDB表空间和binlog位点信息,非常适合做主从搭建和日常备份。

Ubuntu 22.04上通过Percona官方仓库安装:

wget https://repo.percona.com/apt/percona-release_latest.$(lsb_release -sc)_all.deb sudo dpkg -i percona-release_latest.$(lsb_release -sc)_all.deb sudo percona-release setup ps80 sudo apt update sudo apt install -y percona-xtrabackup-80

确认版本:

xtrabackup --version

如果输出里有version 8.0.x,就装好了。

6.2 全量备份与恢复验证

备份命令:

sudo xtrabackup --backup \ --target-dir=/data/backup/mysql_full_$(date +%Y%m%d) \ --user=backup_user \ --password='BackupPassw0rd!' \ --parallel=4

记得提前创建备份专用账号,并给予相应权限:

CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'BackupPassw0rd!'; GRANT BACKUP_ADMIN, RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT ON *.* TO 'backup_user'@'localhost'; FLUSH PRIVILEGES;

备份完成后,目录里会包含一份xtrabackup_checkpoints文件,记录了备份的LSM(Log Sequence Number)信息,做主从同步时这个信息非常关键。

恢复的时候不要直接restore到正在运行的数据目录,而是先prepare再copy-back:

sudo xtrabackup --prepare --target-dir=/data/backup/mysql_full_20250101 sudo xtrabackup --copy-back --target-dir=/data/backup/mysql_full_20250101

prepare阶段做了两件事:回放Redo Log,把数据文件推到一致状态;清理未提交的Undo Log事务。不做prepare直接copy-back,MySQL启动时会报数据文件不一致错误。

6.3 GTID主从同步的配置要点

GTID(Global Transaction Identifier)是MySQL 5.6之后引入的全局事务标识符,相比传统的基于binlog文件名+位置的同步方式,GTID的优点是主从切换时不需要手动找偏移量,故障转移复杂度大幅降低。

主库开启GTID需要修改配置文件:

[mysqld] server-id = 1 gtid_mode = ON enforce_gtid_consistency = ON log_bin = /var/log/mysql/mysql-bin

从库配置:

[mysqld] server-id = 2 gtid_mode = ON enforce_gtid_consistency = ON

注意:gtid_mode=ON不能直接设置,MySQL要求按照OFF -> OFF_PERMISSIVE -> ON_PERMISSIVE -> ON的顺序递增设置。在线上环境直接改回ON会报错,必须一步步来:

SET GLOBAL gtid_mode = OFF_PERMISSIVE; SET GLOBAL gtid_mode = ON_PERMISSIVE; SET GLOBAL gtid_mode = ON;

6.4 部署从库的流程简述

有了全量备份和GTID,从库搭建就简单了,核心思路是“主库做一次全量备份 -> 恢复到从库 -> 从库通过GTID自动追平主库”。

具体步骤:

  1. 在主库上创建复制账号:
CREATE USER 'repl'@'%' IDENTIFIED BY 'ReplPassw0rd!'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; FLUSH PRIVILEGES;
  1. 对主库使用xtrabackup做一次全量备份(步骤见6.2),拿到备份目录和其中的xtrabackup_binlog_info文件(记录GTID位置)。

  2. 把备份目录拷贝到从库,执行prepare和copy-back,注意从库的数据目录要先清空。

  3. 在从库上执行:

CHANGE MASTER TO MASTER_HOST='192.168.1.100', MASTER_USER='repl', MASTER_PASSWORD='ReplPassw0rd!', MASTER_AUTO_POSITION=1; START SLAVE;

MASTER_AUTO_POSITION=1是GTID自动定位的关键,意味着从库会从主库拉取从全量备份时间点之后的所有事务。

  1. 查看同步状态:
SHOW SLAVE STATUS\G

重点关注两个字段:Slave_IO_Running: Yes和Slave_SQL_Running: Yes。如果两个都是YES,说明同步正常。

我遇到比较多的问题是Slave_SQL_Running: No,大都是由主从数据不一致(比如有人在从库手动写了数据)、事务冲突引起的。处理思路是先跳过出错事务(临时手段),然后对比数据,必要时重建从库。想在GTID模式下安全跳过,用以下SQL:

STOP SLAVE; SET GLOBAL sql_slave_skip_counter = 1; START SLAVE;

但这只是缓兵之计,最终还是要从主库重新同步一次才干净。

7. 卸载与重建:Ubuntu 22.04上正确处理MySQL残留

7.1 为什么卸载不干净会导致重装失败

这节是意外塞进来的,起因是一个粉丝反馈“按教程装MySQL,装一半报错说数据目录已存在”,查了半天发现是他之前卸载过一次MySQL,但/var/lib/mysql目录没有清干净。MySQL安装包会检测数据目录,如果目录存在且非空,就会跳过初始化流程,导致安装完成后服务无法启动。

这是Ubuntu系列Linux上最典型的重装坑,专门写一节讲清楚。

7.2 完整卸载流程

完整的卸载命令如下:

sudo systemctl stop mysql sudo apt remove --purge mysql-server mysql-client mysql-common -y sudo apt autoremove -y

然后清理残留目录:

sudo rm -rf /var/lib/mysql sudo rm -rf /etc/mysql sudo rm -rf /var/log/mysql

清理依赖包(可选但推荐):

sudo apt purge '*mysql*' -y sudo apt autoremove -y

全部清完后检查:

dpkg -l | grep mysql

如果没有输出,说明卸载干净了。这时候重新执行第二章的安装步骤就不会有任何干扰。

7.3 保留数据目录的部分卸载

有一种场景是你只想重装MySQL服务端,但保留数据库文件(比如你想换个版本验证兼容性,又怕数据丢失),那就可以不清/var/lib/mysql,只做apt remove --purge mysql-server,但装新版本之前最好先备份数据目录:

sudo cp -a /var/lib/mysql /var/lib/mysql.bak

重装后如果数据目录里的版本和新装版本不一致(比如从8.0降到5.7),MySQL会拒绝启动并提示“data directory was initialized by a different version”。这种情况基本只能恢复备份或升级回原版本,没有其他好办法。

8. 补充对比:Docker Compose部署MySQL的适用场景

8.1 什么时候用Docker、什么时候用原生安装

最近Docker Compose部署MySQL的热度很高,我也在实际项目里用过。简单对比一下:

维度原生apt安装Docker Compose部署
环境隔离直接使用宿主机资源容器隔离,端口映射
配置修改改/etc/mysql下的配置文件改docker-compose.yml和环境变量
升级apt upgrade拉新镜像重启容器
数据持久化数据目录原生管理需要挂载卷,否则容器删了数据就没了
适合环境生产环境、单机高负载开发环境、微服务多容器编排

我的个人原则是:生产环境的数据库,能用原生安装就用原生安装。理由很简单,生产数据库的道路要可控、可预测,容器化虽然带来了部署便利,但也带来了“数据卷权限混乱”“容器重启后IP变化”“日志收集链路复杂”等额外问题。开发环境我反而推荐用Docker Compose,因为可以快速起停、随心所欲地切换版本。

8.2 一个Docker Compose的参考配置

如果你确实需要在开发环境使用Docker部署MySQL,这是一份可以直接用的docker-compose.yml:

services: mysql: image: mysql:8.0 container_name: mysql-dev restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: RootPassw0rd! MYSQL_DATABASE: appdb MYSQL_USER: app_user MYSQL_PASSWORD: AppPassw0rd! TZ: Asia/Shanghai ports: - "3306:3306" volumes: - ./data:/var/lib/mysql - ./my.cnf:/etc/mysql/conf.d/custom.cnf command: - --character-set-server=utf8mb4 - --collation-server=utf8mb4_unicode_ci

启动:

docker compose up -d

这里有个容易踩的坑:./data:/var/lib/mysql这个挂载,第一次启动时Docker会自动以镜像内默认配置初始化数据目录,但如果宿主机./data目录存在且非空,MySQL会直接使用,可能触发“目录初始化失败”的错误。建议第一次启动前让./data目录保持空状态。

8.3 如果原生安装遇到问题,Docker也不失为一种快速恢复手段

有一次我给客户调试一个MySQL 8.0的读写性能问题,原生环境的配置被之前的同事改得乱七八糟,调了半天没还原到干净状态。后来我直接在Docker里起了一个新实例,用同样的my.cnf和数据集,很快就定位到是某个参数设置异常。这个思路仅供参考:Docker不能替代生产数据库,但它是很好的调试沙盒。

到这一步,从环境准备到安装配置、从调优到备份同步、从卸载清理到Docker对比,整条部署路径都走通了。我个人实际操作下来,最有价值的一句话是:装MySQL从来不是难点,难点在装完后的每一步配置都带着“默认安全但不方便”与“开放但危险”的权衡。希望这篇整理能让你少走几趟弯路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/6 13:25:04

Linux下彻底卸载MySQL:从包清理到残留文件清扫的完整指南

搞Linux运维的,估计没人没跟MySQL卸载这件事较过劲。尤其那种“明明把服务停了、rpm包也删了,重装却还是各种报错到头大”的情况,十有八九就是卸得不够彻底——甚至很多时候你以为自己卸干净了,其实系统里还埋着一堆雷&#xff0c…

作者头像 李华
网站建设 2026/10/6 13:24:32

Flutter权限管理实战:permission_handler配置与避坑指南

做 Flutter 开发,只要是涉及文件下载、拍照、定位、通讯录这些功能,十有八九都会栽在权限管理这个坎上。Android 和 iOS 两套系统的权限机制本身就差异巨大,再加上 Android 6.0 之后运行时权限、Android 11 的包可见性变化、iOS 的隐私新政&a…

作者头像 李华
网站建设 2026/10/6 13:24:24

无监督谱回归测试阶段实现详解:投影矩阵、均值对齐与阈值设定

无监督谱回归(USR)这名字听起来挺学术,但其实它要解决的问题很朴素:给一堆没有标签的样本建图、找低维结构,再让新来的样本也能快速落到同一个低维空间里。我最近在帮业务团队落地一版 USR 模型,整整两天时…

作者头像 李华
网站建设 2026/10/6 13:23:25

基于SQLite FTS5的中文全文搜索实现及踩坑指南

今天是“30天挑战”的第11天,整个项目刚好走完三分之一。先交代一下背景:我在做的是一个本地优先的 Markdown 知识管理工具 DayNotes,要求数据完全离线、启动速度快、折腾成本低。前 10 天已经完成了文档解析、编辑器、标签体系和列表页&…

作者头像 李华
网站建设 2026/10/6 13:22:51

C#开发U盘禁用工具:守护进程+白名单+审计日志完整方案

最近在公司做终端安全加固时接到一个需求:禁止员工随意插入U盘拷贝资料。需求听起来简单,但真正落地才发现坑不少——普通策略禁用U盘后,换台电脑改个注册表就能绕过;光监听插入事件,又不处理开机前已插好的U盘&#x…

作者头像 李华
网站建设 2026/10/6 13:22:30

MySQL慢SQL优化:Explain执行计划关键字段与实战调优

很多搞后端的朋友第一次接触Explain,是在慢SQL压测被领导叫过去的时候。我也不例外:线上有个订单统计页面,运营点一下要等十几秒,一翻日志全是同一条SELECT。当时我做的第一件事不是改代码,而是把这条SQL丢进工具里跑了…

作者头像 李华