93 lines
4.2 KiB
Python
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())
|