25 - 数据库管理

数据库是现代应用的持久化核心。Linux 上最主流的三个关系型数据库系统——MySQL/MariaDB、PostgreSQL 和 SQLite——覆盖了从嵌入式到企业级的完整需求。本章涵盖它们的安装、基本 SQL 操作、用户权限管理、命令行工具使用以及备份恢复策略。


25.1 关系型数据库概览

三大数据库对比

特性SQLiteMySQL/MariaDBPostgreSQL
类型嵌入式(文件库)客户端/服务器客户端/服务器
SQL 标准基础扩展(方言)最完整
并发写入单写入者行级锁MVCC(多版本)
JSON 支持基础JSON 类型JSON/JSONB(索引)
全文搜索FTS5InnoDB 全文索引内置 + 扩展
地理空间SpatiaLite基础 GISPostGIS(功能最强)
扩展性内置函数插件/存储引擎丰富的扩展生态
适用场景移动端、桌面应用、嵌入式Web 应用、CMS(WordPress 等)复杂查询、数据分析、GIS
安装大小~1MB~200MB+~150MB+
进程模型库内执行多线程每连接 fork 进程

25.2 MySQL / MariaDB

MariaDB 是 MySQL 的社区分支,由原 MySQL 创始人维护。大多数 Linux 发行版默认使用 MariaDB。

安装

# === MariaDB ===
# Debian / Ubuntu
sudo apt install mariadb-server mariadb-client
 
# RHEL / Fedora
sudo dnf install mariadb-server mariadb
 
# openSUSE
sudo zypper install mariadb mariadb-client
 
# Arch
sudo pacman -S mariadb
 
# Alpine
apk add mariadb mariadb-client
 
# === MySQL(Oracle 官方版)===
# Ubuntu
# sudo apt install mysql-server mysql-client
 
# RHEL / Fedora(需要先添加 MySQL 仓库)
# sudo dnf install https://dev.mysql.com/get/mysql80-community-release-el9-1.noarch.rpm
# sudo dnf install mysql-server

初始化与启动

# 初始化数据库(MariaDB 首次启动前需要)
# Debian/Ubuntu 自动完成,其他发行版手动执行:
sudo mysql_install_db --user=mysql --basedir=/usr --datadir=/var/lib/mysql
 
# 启动服务
sudo systemctl enable --now mariadb # MariaDB
sudo systemctl enable --now mysqld # MySQL
 
# === 安全初始化向导(设置 root 密码、删除匿名用户等)===
sudo mysql_secure_installation
 
# 交互过程:
# - Enter current password for root: (首次为空,直接回车)
# - Set root password? [Y/n] Y
# - Remove anonymous users? [Y/n] Y
# - Disallow root login remotely? [Y/n] Y
# - Remove test database? [Y/n] Y
# - Reload privilege tables? [Y/n] Y

连接与基本操作

# 连接(本地 socket 认证)
sudo mysql
mysql -u root -p # 密码认证
 
# === 基本 SQL ===
 
# 显示所有数据库
SHOW DATABASES;
 
# 创建数据库
CREATE DATABASE myapp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
 
# 选择数据库
USE myapp;
 
# 创建表
CREATE TABLE users (
 id INT AUTO_INCREMENT PRIMARY KEY,
 username VARCHAR(50) NOT NULL UNIQUE,
 email VARCHAR(255) NOT NULL,
 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
 INDEX idx_email (email)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
 
# 查看表结构
DESCRIBE users;
SHOW CREATE TABLE users;
 
# 插入数据
INSERT INTO users (username, email) VALUES
 ('alice', 'alice@example.com'),
 ('bob', 'bob@example.com');
 
# 查询数据
SELECT * FROM users;
SELECT id, username FROM users WHERE email LIKE '%example.com';
 
# 更新数据
UPDATE users SET email = 'alice_new@example.com' WHERE username = 'alice';
 
# 删除数据
DELETE FROM users WHERE id = 1;
 
# 聚合查询
SELECT COUNT(*) FROM users;
SELECT DATE(created_at), COUNT(*) FROM users GROUP BY DATE(created_at);

用户与权限管理

-- 创建用户
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'strong_password';
CREATE USER 'appuser'@'192.168.1.%' IDENTIFIED BY 'strong_password'; -- 网段
CREATE USER 'appuser'@'%' IDENTIFIED BY 'strong_password'; -- 任何来源
 
-- 授权
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp.* TO 'appuser'@'localhost';
GRANT ALL PRIVILEGES ON myapp.* TO 'appuser'@'localhost'; -- 全部权限
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'localhost' WITH GRANT OPTION; -- 超级用户
 
-- 查看权限
SHOW GRANTS FOR 'appuser'@'localhost';
 
-- 撤销权限
REVOKE INSERT ON myapp.* FROM 'appuser'@'localhost';
 
-- 删除用户
DROP USER 'appuser'@'localhost';
 
-- 刷新权限(修改后生效)
FLUSH PRIVILEGES;

配置文件

# MariaDB: /etc/mysql/mariadb.conf.d/50-server.cnf(Debian/Ubuntu)
# MySQL: /etc/mysql/mysql.conf.d/mysqld.cnf(Debian/Ubuntu)
# /etc/my.cnf(RHEL/Fedora)
# /etc/mysql/my.cnf(Arch)
 
[mysqld]
# 网络
bind-address = 127.0.0.1 # 仅本地监听(安全默认)
# bind-address = 0.0.0.0 # 所有接口
port = 3306
 
# 字符集
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
 
# 内存(根据服务器配置调整)
innodb_buffer_pool_size = 1G # InnoDB 缓存(建议物理内存的 50%-70%)
innodb_log_file_size = 256M
max_connections = 151
query_cache_type = 0 # MySQL 8 / MariaDB 10.2+ 默认禁用
 
# 日志
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mariadb-slow.log
long_query_time = 2 # 超过 2 秒的查询记录
 
# 数据目录
datadir = /var/lib/mysql

备份与恢复

# === mysqldump:逻辑备份 ===
# 备份单个数据库
mysqldump -u root -p myapp > myapp_backup.sql
 
# 备份所有数据库
mysqldump -u root -p --all-databases > all_backup.sql
 
# 仅备份表结构(不含数据)
mysqldump -u root -p --no-data myapp > myapp_schema.sql
 
# 备份特定表
mysqldump -u root -p myapp users posts > myapp_tables.sql
 
# 压缩备份
mysqldump -u root -p myapp | gzip > myapp_backup.sql.gz
 
# 恢复
mysql -u root -p myapp < myapp_backup.sql
 
# 从压缩文件恢复
gunzip < myapp_backup.sql.gz | mysql -u root -p myapp
 
# === MariaDB Backup(物理备份,MariaDB 专有)===
sudo mariabackup --backup --target-dir=/backup/mariadb --user=root
sudo mariabackup --prepare --target-dir=/backup/mariadb # 准备备份
sudo mariabackup --copy-back --target-dir=/backup/mariadb # 恢复
 
# === 自动备份脚本示例 ===
#!/bin/bash
DB="myapp"
BACKUP_DIR="/backup/mysql"
DATE=$(date +%Y%m%d_%H%M%S)
mysqldump -u root -p"$MYSQL_PASS" "$DB" | gzip > "$BACKUP_DIR/${DB}_${DATE}.sql.gz"
# 保留最近 7 天的备份
find "$BACKUP_DIR" -name "${DB}_*.sql.gz" -mtime +7 -delete

25.3 PostgreSQL

PostgreSQL 以 SQL 标准合规性、扩展性和数据完整性著称,是企业级应用的首选。

安装

# Debian / Ubuntu
sudo apt install postgresql postgresql-client
 
# RHEL / Fedora
sudo dnf install postgresql-server postgresql
 
# openSUSE
sudo zypper install postgresql-server
 
# Arch
sudo pacman -S postgresql
 
# Alpine
apk add postgresql postgresql-client

初始化与启动

# === RHEL / Fedora / openSUSE / Arch ===
# 首次安装后需初始化数据目录
sudo postgresql-setup --initdb # RHEL/Fedora
sudo su - postgres -c "initdb --locale en_US.UTF-8 -D /var/lib/postgres/data" # Arch
 
# === 启动服务 ===
sudo systemctl enable --now postgresql
 
# === Debian/Ubuntu 自动初始化和启动 ===
sudo systemctl enable --now postgresql

psql 命令行基础

# 切换到 postgres 用户
sudo -u postgres psql
sudo -i -u postgres # 或先切换用户再 psql
 
# 连接特定数据库
psql -U postgres -d myapp
psql -h localhost -U appuser -d myapp
 
# === psql 基本操作 ===
-- 在 psql 中执行的命令(SQL)和元命令(\开头)
 
-- === 元命令 ===
\l -- 列出所有数据库
\l+ -- 详细列表
\c myapp -- 连接到 myapp 数据库
\dt -- 列出当前数据库的表
\d users -- 查看表结构
\d+ users -- 详细表结构(含索引、约束)
\di -- 列出索引
\du -- 列出角色/用户
\dn -- 列出 schema
\df -- 列出函数
\dv -- 列出视图
\q -- 退出
\timing -- 显示查询执行时间
\e -- 打开编辑器编写查询
\! ls -- 执行 shell 命令
 
-- === SQL 操作 ===
-- 创建数据库
CREATE DATABASE myapp ENCODING 'UTF8' LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8';
 
-- 创建表
CREATE TABLE users (
 id SERIAL PRIMARY KEY,
 username VARCHAR(50) UNIQUE NOT NULL,
 email VARCHAR(255) NOT NULL,
 metadata JSONB DEFAULT '{}'::jsonb, -- JSON 文档
 created_at TIMESTAMPTZ DEFAULT NOW()
);
 
-- 创建索引
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_metadata ON users USING GIN (metadata); -- JSONB GIN 索引
 
-- 插入
INSERT INTO users (username, email, metadata)
VALUES ('alice', 'alice@example.com', '{"role": "admin", "age": 30}');
 
-- JSON 查询
SELECT username, metadata->>'role' AS role FROM users;
SELECT * FROM users WHERE metadata @> '{"role": "admin"}'::jsonb;
 
-- 窗口函数(PostgreSQL 强项)
SELECT username, created_at,
 ROW_NUMBER() OVER (ORDER BY created_at) AS rn
FROM users;
 
-- CTE(公共表表达式)
WITH recent AS (
 SELECT * FROM users WHERE created_at > NOW() - INTERVAL '7 days'
)
SELECT COUNT(*) FROM recent;

用户与权限管理

PostgreSQL 使用 角色(Role) 概念统一管理用户和组:

-- 创建角色
CREATE ROLE appuser WITH LOGIN PASSWORD 'strong_password';
CREATE ROLE readonly WITH LOGIN PASSWORD 'readonly_pass';
 
-- 创建角色并授予超级用户权限
CREATE ROLE admin WITH LOGIN SUPERUSER PASSWORD 'admin_pass';
 
-- 授予权限
GRANT ALL PRIVILEGES ON DATABASE myapp TO appuser;
 
-- 针对特定 schema 和表
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO appuser;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO appuser;
 
-- 只读权限
GRANT CONNECT ON DATABASE myapp TO readonly;
GRANT USAGE ON SCHEMA public TO readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;
 
-- 设置新表的默认权限
ALTER DEFAULT PRIVILEGES IN SCHEMA public
 GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO appuser;
 
-- 查看权限
\du
 
-- 撤销权限
REVOKE ALL ON ALL TABLES IN SCHEMA public FROM appuser;
 
-- 删除角色
DROP ROLE appuser;

postgresql.conf 配置

# 主配置文件位置:
# Debian/Ubuntu: /etc/postgresql/<version>/main/postgresql.conf
# RHEL/Fedora: /var/lib/pgsql/data/postgresql.conf
# Arch: /var/lib/postgres/data/postgresql.conf
 
# 网络与连接
listen_addresses = 'localhost' # 或 '*' 监听所有接口
port = 5432
max_connections = 100
 
# 内存
shared_buffers = 256MB # 建议 25% 系统内存
effective_cache_size = 1GB # 建议 50%-75% 系统内存
work_mem = 16MB # 单个操作的排序内存
maintenance_work_mem = 256MB # VACUUM/CREATE INDEX 用
 
# WAL(预写日志)
wal_level = replica # 或 minimal, logical
max_wal_size = 1GB
min_wal_size = 80MB
 
# 查询优化器
random_page_cost = 1.1 # SSD 环境降低此值(默认 4.0 针对 HDD)
effective_io_concurrency = 200 # SSD 下的并发 I/O
 
# 日志
log_destination = 'stderr'
logging_collector = on
log_directory = 'log'
log_min_duration_statement = 1000 # 记录慢于 1 秒的查询

基于内存计算推荐配置的工具https://pgtune.leopard.in.ua/

pg_hba.conf 客户端认证

# 位置:PostgreSQL 数据目录内的 pg_hba.conf
# 格式: TYPE DATABASE USER ADDRESS METHOD
 
# 本地 socket 连接(默认信任)
local all all peer
 
# IPv4 本地(密码认证)
host all all 127.0.0.1/32 scram-sha-256
 
# IPv4 远程(应用服务器)
host myapp appuser 192.168.1.0/24 md5
 
# IPv6
host all all ::1/128 scram-sha-256
 
# 修改后重载
# SELECT pg_reload_conf();
# 或 sudo systemctl reload postgresql

备份与恢复

# === pg_dump:逻辑备份 ===
# 备份单个数据库
pg_dump -U postgres myapp > myapp_backup.sql
 
# 自定义格式(可并行恢复、压缩)
pg_dump -U postgres -Fc myapp > myapp_backup.dump
 
# 仅备份 schema(不含数据)
pg_dump -U postgres --schema-only myapp > myapp_schema.sql
 
# 仅备份数据
pg_dump -U postgres --data-only myapp > myapp_data.sql
 
# 备份所有数据库
pg_dumpall -U postgres > all_backup.sql
 
# 恢复
psql -U postgres myapp < myapp_backup.sql
pg_restore -U postgres -d myapp myapp_backup.dump
 
# === pg_dump 并行备份(高性能)===
pg_dump -U postgres -Fd -j 4 -f /backup/myapp_dir myapp
# -Fd: 目录格式, -j 4: 4个并行job
 
# === pg_basebackup:物理备份 ===
pg_basebackup -U postgres -D /backup/basebackup -Ft -z -P
# -Ft: tar 格式, -z: gzip, -P: 显示进度
 
# === 连续归档(WAL 归档)===
# postgresql.conf 中启用:
# wal_level = replica
# archive_mode = on
# archive_command = 'cp %p /archive/%f'
 
# === 自动备份脚本 ===
#!/bin/bash
DB="myapp"
BACKUP_DIR="/backup/postgresql"
DATE=$(date +%Y%m%d_%H%M%S)
export PGPASSWORD="your_password"
pg_dump -U postgres -Fc "$DB" > "$BACKUP_DIR/${DB}_${DATE}.dump"
find "$BACKUP_DIR" -name "${DB}_*.dump" -mtime +7 -delete

25.4 SQLite

SQLite 是一个文件级嵌入式数据库,无需服务器进程,非常适合桌面应用、移动端和轻量级 Web 应用。

安装与使用

# 几乎所有发行版都预装 sqlite3 命令行工具
# Debian/Ubuntu: sudo apt install sqlite3
# RHEL/Fedora: sudo dnf install sqlite
# Arch: sudo pacman -S sqlite
 
# 创建/打开数据库文件
sqlite3 myapp.db
 
# 创建表
CREATE TABLE users (
 id INTEGER PRIMARY KEY AUTOINCREMENT,
 username TEXT NOT NULL UNIQUE,
 email TEXT NOT NULL,
 created_at TEXT DEFAULT (datetime('now'))
);
 
# CRUD 操作(SQL 语法与标准 SQL 高度一致)
INSERT INTO users (username, email) VALUES ('alice', 'alice@example.com');
SELECT * FROM users;
UPDATE users SET email = 'alice_new@example.com' WHERE username = 'alice';
DELETE FROM users WHERE id = 1;
 
# 元命令(点命令)
.tables # 列出所有表
.schema users # 查看建表语句
.mode column # 列对齐显示
.headers on # 显示列名
.output result.txt # 结果输出到文件
.import data.csv users # CSV 导入
.backup backup.db # 备份数据库
.quit

SQLite 备份

# .backup 命令
sqlite3 myapp.db ".backup 'myapp_backup.db'"
 
# 命令行 dump
sqlite3 myapp.db .dump > myapp_dump.sql
sqlite3 restored.db < myapp_dump.sql # 恢复
 
# 直接文件复制(需确保无写入连接)
cp myapp.db myapp_backup.db

25.5 连接字符串参考

应用连接数据库时需要的连接字符串格式:

# SQLite(本地文件)
sqlite:///path/to/database.db

# MySQL / MariaDB
mysql://username:password@host:3306/database?charset=utf8mb4

# 通过 Unix socket
mysql://username:password@localhost/database?unix_socket=/run/mysqld/mysqld.sock

# PostgreSQL
postgresql://username:password@host:5432/database?sslmode=require

# 通过 Unix socket
postgresql://username:password@/database?host=/run/postgresql

25.6 数据库安全基础

# 1. 限制监听地址
# MySQL: bind-address = 127.0.0.1
# PostgreSQL: listen_addresses = 'localhost'
 
# 2. 使用强密码和 SCRAM-SHA-256(PostgreSQL)或 caching_sha2_password(MySQL 8+)
# ALTER USER appuser WITH PASSWORD 'new_strong_password';
 
# 3. 最小权限原则
# - 应用用户只需 CRUD 权限
# - 管理员权限与日常操作分离
 
# 4. 启用 TLS 加密连接
# PostgreSQL: ssl = on, ssl_cert_file / ssl_key_file
# MySQL: 配置 SSL 证书
 
# 5. 定期审计用户权限
# MySQL: SELECT user, host FROM mysql.user;
# PostgreSQL: \du
 
# 6. 检查并删除无密码用户
# MySQL: SELECT user, host FROM mysql.user WHERE authentication_string='';

25.7 相关章节


小结:三个数据库各有定位——SQLite 适合嵌入式和轻量场景,MariaDB/MySQL 是 Web 应用的传统选择,PostgreSQL 在 SQL 标准合规、扩展性和复杂查询方面遥遥领先。无论选择哪个,掌握基本的 SQL 操作、用户权限管理和备份恢复是数据库管理的基本功。