mysql 5.7 删除ibdata1 、ib_logfile 文件的数据恢复

  • 简介:

  本文记录删除ibdata1 、ib_logfile 文件被意外删除且无法还原或损坏的解决方案,当删除后没有重启mysql 可以查询进程号,找到删除的文件可以还原回来。参考其他文章。本文介绍ibdata1 、ib_logfile 文件无法找到或异常没有备份的情况处理。

 

新安装一台mysql用作从库

注意安装版本与主库版本一致。

获取所有建表语句

如果原表所有建表语句都有保存最方便直接用即可。

如果没有保存需要使用工具mysqlfrm。在问题机器主库安装下:

#安装目录 自己创建
cd /data/      
#下载文件
wget  https://cdn.mysql.com/archives/mysql-utilities/mysql-utilities-1.6.5.tar.gz
#解压文件
tar -xf mysql-utilities-1.6.5.tar.gz
ls
#进入解压好的文件夹
cd mysql-utilities-1.6.5/
#build构建
python ./setup.py build
#install安装
python ./setup.py install
 
#安装成功查看命令
mysqlfrm --version
  • 模式介绍

  –basedir:需指定服务器的基本目录,相当于再生一个数据库实例,还需指定prot,user及.frm文件位置等信息,指定的prot不能与在运行的数据库冲突,可在原数据库无法打开情况下使用,在读取.frm文件后,再生的实例将被关闭,所有的临时文件将被删除。

  例:mysqlfrm --basedir=/mysql/mysqld/ --port=3333 --user=mysql /mysql/data/test/tables.frm --show-stats

  –server:需指定数据库的连接字符串,需在原数据库可以打开的情况下使用,指定数据库用户名,密码,端口号及.frm文件位置等信息。

  例:mysqlfrm --server=root:Root#123@localhost:3306 /mysql/data/test/tables.frm --port=3310 --user=mysql

  注意:如数据库还可以正常连接,推荐使用–server模式

  • 获取建表语句脚本 
#!/bin/bash

# 定义变量
output_file="Create.sql"                     # 输出文件名
mysql_root_password="123456"                 # MySQL root 用户密码
mysql_host="localhost"                         # MySQL 主机
mysql_port="3306"                             # MySQL 端口
mysql_user="mysql"                             # MySQL 用户名
data_dir="/data/mysql/"                        # MySQL 数据目录
excluded_dirs=(mysql sys performance_schema)   # 需要排除的目录列表

# 清空输出文件,如果文件不存在则创建
> $output_file

# 构建排除目录的 find 过滤条件
exclude_find=""
for dir in "${excluded_dirs[@]}"; do
    exclude_find+=" -path ${data_dir}${dir} -o"
done
exclude_find=${exclude_find::-2}  # 去掉最后一个 "-o"

# 查找所有的 .frm 文件,排除指定目录
find $data_dir -type d \( $exclude_find \) -prune -o -type f -name '*.frm' -print | while read frm_file; do
    # 提取建表语句(去掉注释)
    mysqlfrm --server=root:"$mysql_root_password"@$mysql_host:"$mysql_port" "$frm_file" --user=$mysql_user \
    | grep -v '^#' >> $output_file
    echo -e "\n" >> $output_file  # 添加换行符便于分隔
done

echo "建表语句已保存到 $output_file"

建表语句导入从库

从库先创建所有主库的库,执行Create.sql语句。

还原数据

修改从库配置文件添加:innodb_force_recovery=1,重启数据库。

建表语句创建好后,对每个表进行删除表空间,注意脚本不要放mysql默认4个库,脚本如下:

#!/bin/bash

# MySQL 用户名和密码
MYSQL_USER="root"
MYSQL_PASS="123456"

# 数据库列表
databases=(
    "aaa"
    "bbbb"
    "ccc"
    "ddd"
)

# 遍历数据库列表
for db in "${databases[@]}"; do
    echo "Processing database: $db"
    
    # 获取当前数据库中的所有表
    tables=$(mysql -u $MYSQL_USER -p"$MYSQL_PASS" -e "SHOW TABLES;" $db | awk '{print $1}' | grep -v '^Tables_in')

    # 遍历表列表并执行 DISCARD TABLESPACE
    for table in $tables; do
        echo "Discarding tablespace for table: $table in database: $db"
        mysql -u $MYSQL_USER -p$MYSQL_PASS -e "ALTER TABLE $table DISCARD TABLESPACE;" $db
    done
done

echo "Tablespace discard operation completed."

执行完删除表空间后导入主库的ibd文件。库很多可以使用脚本主库打包mysql目录放到从库中,使用脚本复制:

#!/bin/bash

# 源目录和目标目录
src_dir="/home/mysqlbak"
dest_dir="/home/mysql"

# 目录列表
dirs=(
    "aaa"
    "bbb"
)

# 遍历目录列表并复制文件
for dir in "${dirs[@]}"; do
    src_path="$src_dir/$dir"
    dest_path="$dest_dir/$dir"
    
    # 检查源目录是否存在
    if [ -d "$src_path" ]; then
        # 复制 .ibd 文件
        if [ "$(ls -A $src_path/*.ibd 2>/dev/null)" ]; then
            echo "Copying .ibd files from $src_path to $dest_path"
            # 创建目标目录(如果存在)
            if [ ! -d "$dest_path" ]; then
                echo "Directory $dest_path does not exist. Skipping copy."
                continue
            fi
            cp -a  "$src_path"/*.ibd "$dest_path/"
        else
            echo "No .ibd files found in $src_path"
        fi
    else
        echo "Source directory $src_path does not exist"
    fi
done

echo "File copy operation completed."

再次执行导入表空间命令,脚本和删除表空间基本一样,复制一份修改一个地方即可:

mysql -u $MYSQL_USER -p$MYSQL_PASS -e "ALTER TABLE $table DISCARD TABLESPACE;" $db

##改为

mysql -u $MYSQL_USER -p$MYSQL_PASS -e "ALTER TABLE $table IMPORT TABLESPACE;" $db

大功告成!检测从库数据是否恢复。
数据恢复后注意修改配置文件:innodb_force_recovery=1  删除,重启数据库。

posted @ 2024-09-12 11:08  记忆抹不去  阅读(378)  评论(0编辑  收藏  举报