Files
banban/talkingq-url/scripts/db_management.py
2026-03-24 15:04:36 +08:00

93 lines
4.2 KiB
Python

import os
import sys
import asyncio
import argparse
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))
from scripts.backup_db import backup_database, list_backups, cleanup_old_backups, BACKUP_DIR
from scripts.restore_db import restore_database, interactive_restore
from scripts.cleanup_db import cleanup_database, remove_orphaned_records
async def main():
parser = argparse.ArgumentParser(description='数据库备份和恢复工具')
subparsers = parser.add_subparsers(dest='command', help='子命令')
backup_parser = subparsers.add_parser('backup', help='备份数据库')
backup_parser.add_argument('--name', type=str, help='备份名称,不含扩展名')
backup_parser.add_argument('--no-compress', action='store_true', help='不压缩备份文件')
backup_parser.add_argument('--keep', type=int, default=10, help='保留的备份数量')
restore_parser = subparsers.add_parser('restore', help='恢复数据库')
restore_parser.add_argument('--file', type=str, help='要恢复的备份文件')
list_parser = subparsers.add_parser('list', help='列出所有备份')
cleanup_parser = subparsers.add_parser('cleanup', help='清理旧备份')
cleanup_parser.add_argument('--keep', type=int, default=10, help='保留的备份数量')
clean_db_parser = subparsers.add_parser('clean-db', help='清理数据库中未使用的表和字段')
clean_db_parser.add_argument('--execute', action='store_true', help='执行实际清理(不使用此选项则只进行模拟运行)')
clean_db_parser.add_argument('--orphaned', action='store_true', help='仅清理孤立记录')
clean_db_parser.add_argument('--schema', action='store_true', help='仅清理未使用的表和字段')
clean_db_parser.add_argument('--backup-first', action='store_true', help='清理前先进行备份')
clean_db_parser.add_argument('--drop-tables', type=str, help='指定要删除的表,用逗号分隔')
args = parser.parse_args()
if args.command == 'backup':
await backup_database(args.name, not args.no_compress if hasattr(args, 'no_compress') else True)
await cleanup_old_backups(args.keep if hasattr(args, 'keep') else 10)
elif args.command == 'restore':
if args.file:
await restore_database(args.file)
else:
await interactive_restore()
elif args.command == 'list':
backups = await list_backups()
if backups:
print("\n可用的备份文件:")
for backup in backups:
file_path = os.path.join(BACKUP_DIR, backup)
size = os.path.getsize(file_path) / (1024 * 1024) # 转换为MB
print(f"{backup} ({size:.2f} MB)")
else:
print("没有找到可用的备份")
elif args.command == 'cleanup':
keep = args.keep if hasattr(args, 'keep') else 10
await cleanup_old_backups(keep)
elif args.command == 'clean-db':
dry_run = not args.execute
if args.backup_first:
print("清理前进行数据库备份...")
await backup_database(f"pre_cleanup_{int(asyncio.get_event_loop().time())}", True)
if args.drop_tables:
from scripts.cleanup_db import get_mysql_connection, drop_specific_tables
conn = await get_mysql_connection()
if conn:
try:
tables_to_drop = [t.strip() for t in args.drop_tables.split(',')]
await drop_specific_tables(conn, tables_to_drop, dry_run)
finally:
conn.close()
else:
if not args.orphaned:
print("\n分析数据库架构...")
await cleanup_database(dry_run)
if not args.schema:
print("\n检查孤立记录...")
await remove_orphaned_records(dry_run)
if dry_run:
print("\n这是一次模拟运行,没有执行任何实际更改。")
print("要执行实际的清理操作,请使用 --execute 选项。")
else:
parser.print_help()
if __name__ == "__main__":
asyncio.run(main())