Maxkb实现数据库备份与恢复

备份脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/bin/bash

# 定义变量
BACKUP_DIR="/opt/db_bak" # 备份文件存储目录
DATE=$(date +%Y%m%d_%H%M%S) # 创建时间戳
CURRENT_TIME=$(date +"%Y-%m-%d %H:%M:%S") # 添加当前时间变量(用于日志)
DB_NAME="maxkb" # 数据库名
DB_USER="postgres" # 数据库用户(根据配置修改)
DB_PASS="123123" # 数据库密码(根据配置修改)
DB_HOST="localhost" # 数据库主机地址
DB_PORT="5432" # 数据库端口

# 创建备份文件名
BACKUP_FILE="$BACKUP_DIR/$DB_NAME-$DATE.dump"

# 检查备份目录是否存在,如果不存在则创建
if [ ! -d "$BACKUP_DIR" ]; then
mkdir -p "$BACKUP_DIR"
echo "[${CURRENT_TIME}] 备份目录不存在,已创建目录:$BACKUP_DIR"
fi

# 执行备份
echo "[${CURRENT_TIME}] 开始备份数据库:$DB_NAME"

# 使用环境变量设置密码,避免在命令行中明文传递
PGPASSWORD="$DB_PASS" pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -Fc > "$BACKUP_FILE"

# 检查备份是否成功
if [ $? -eq 0 ]; then
echo "[${CURRENT_TIME}] 备份完成,文件路径:$BACKUP_FILE"
else
echo "[${CURRENT_TIME}] 备份失败!"
exit 1
fi

# 压缩备份文件
gzip "$BACKUP_FILE"
COMPRESSED_FILE="${BACKUP_FILE}.gz"
echo "[${CURRENT_TIME}] 备份文件已压缩:$COMPRESSED_FILE"
echo "------------------------"

添加执行权限

1
sudo chmod +x /opt/maxkb/backup_maxkb.sh

执行

1
sudo sh backup_maxkb.sh 

此时默认将数据库导入到/opt/db_bak路径下,我们需要定时执行这个脚本。

设置定时任务

1
sudo crontab -e

在文件末尾添加

1
2
# 每周六凌晨2点进行备份
00 02 * * 6 /opt/backup_maxkb.sh >> /var/log/maxkb_backup.log 2>&1

恢复脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#!/bin/bash

# 定义变量
RESTORE_FILE="/opt/db_bak/maxkb-20250606_095233.dump.gz" # 备份文件路径,支持 .gz 压缩格式
DB_NAME="maxkb" # 要恢复的数据库名
DB_USER="postgres" # 数据库用户(根据实际情况修改)
DB_PASS="123123" # 数据库密码(根据实际情况修改)
DB_HOST="localhost" # 数据库主机地址
DB_PORT="5432" # 数据库端口
TEMP_DIR="/tmp/postgres_restore" # 临时解压目录

# 创建临时目录
mkdir -p "$TEMP_DIR"
echo "临时目录已创建:$TEMP_DIR"

# 检查备份文件是否存在
if [ ! -f "$RESTORE_FILE" ]; then
echo "错误:恢复文件不存在:$RESTORE_FILE"
exit 1
fi

# 提取文件名(不含路径)
FILENAME=$(basename "$RESTORE_FILE")

# 检查文件是否为 .gz 压缩格式
if [[ "$FILENAME" == *.gz ]]; then
echo "检测到压缩文件,开始解压..."
UNZIPPED_FILE="$TEMP_DIR/${FILENAME%.gz}" # 移除 .gz 后缀

# 解压文件
gunzip -c "$RESTORE_FILE" > "$UNZIPPED_FILE"
if [ $? -ne 0 ]; then
echo "错误:解压文件失败!"
exit 1
fi
echo "文件已解压至:$UNZIPPED_FILE"
else
# 如果不是压缩文件,直接使用原文件
UNZIPPED_FILE="$RESTORE_FILE"
fi

# 检查目标数据库是否已存在
echo "检查数据库 '$DB_NAME' 是否存在..."
if psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -lqt | cut -d \| -f 1 | grep -qw "$DB_NAME"; then
echo "数据库 '$DB_NAME' 已存在,将清空数据库并继续恢复操作..."

# 清空数据库(危险操作!)
PGPASSWORD="$DB_PASS" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -c "
BEGIN;
-- 关闭所有连接(避免锁表)
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = '$DB_NAME' AND pid <> pg_backend_pid();

-- 清空所有模式下的对象(注意:会删除所有数据!)
DROP SCHEMA public CASCADE;
CREATE SCHEMA public;
GRANT ALL ON SCHEMA public TO public;
GRANT ALL ON SCHEMA public TO $DB_USER;
COMMIT;
"

if [ $? -ne 0 ]; then
echo "错误:清空数据库失败!"
exit 1
fi
else
echo "数据库 '$DB_NAME' 不存在,将创建新数据库..."
# 创建新数据库
PGPASSWORD="$DB_PASS" createdb -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" "$DB_NAME"
if [ $? -ne 0 ]; then
echo "错误:创建数据库失败!"
exit 1
fi
fi

# 执行恢复
echo "开始从 $RESTORE_FILE 恢复数据库 $DB_NAME..."

# 使用环境变量设置密码,避免在命令行中明文传递
PGPASSWORD="$DB_PASS" pg_restore -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -v "$UNZIPPED_FILE"

# 检查恢复是否成功
if [ $? -eq 0 ]; then
echo "恢复完成!"
else
echo "错误:恢复失败!"
exit 1
fi

# 清理临时文件
echo "清理临时文件..."
rm -rf "$TEMP_DIR"
echo "恢复过程已完成!"

执行

1
sudo bash restore_maxkb.sh 

恢复完成!