mysql根据.frm和.ibd文件恢复表结构和数据的具体代码实现,能够批量恢复数据

本文详细介绍了一种半自动化的MySQL数据恢复方法,通过分析.frm和.ibd文件,逐步恢复数据库结构和数据。包括创建临时表、分析错误日志、恢复完整表结构、解除和重新绑定.ibd文件等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文是为了让这篇博客 https://blog.youkuaiyun.com/hzw19920329/article/details/78045864 能够进行半自动的实现数据恢复。让恢复速度快起来


package com.mysql.data.recover;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * mysql根据.frm和.ibd文件恢复表结构和数据
 * @author Administrator
 *
 */
public class MysqlDataRecover {

	final static String databaseName = "marrys"; 
	/**
	 * 1、先创建对应的表,至于具体有多少个列及各个列的消息消息先不用管,同一创建为包含列a的表。
	 * @throws Exception
	 */
	public static void firstCreateTempTable() throws Exception {
		
		List<String> tables = getAllTables();
		for (String table : tables) {
			String c = "create table "+table;
			c += "( a int );";
			System.out.println(c);
		}
	}
	
	/**
	 * 2、创建完成后,将数据库关闭,将所有的.frm文件移动备份都某个文件夹中去。
	 *    将你想要还原的表中的所有.frm文件移动到此数据库中来。
	 *    在my.ini或者my.cnf文件中添加如下配置: innodb_force_recovery = 6
	 *    然后重启数据库
	 */
	
	/**
	 * 3、分析错误日志文件
	 * 错误日志文件一般会有如下的错误日志输出: 
	 * [Warning] InnoDB: table marry/rc_marry contains 1 user defined columns in InnoDB, but 88 columns in MySQL. Please check INFORMATION_SCHEMA.INNODB_SYS_COLUMNS and http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html for how to resolve it
	 * 具体信息解释为:  数据库下面的rc_marry表定义只有1个列(见第一步),然而在.frm中有88个列。
	 * 从这里我们可以得到信息是:  rc_marry表有88个列。
	 * 故我们通过这个错误信息又去创建相同表,而且此表有88个列,具体各个列的信息依旧不用关心。列数匹配即可。
	 * 这里输出的sql是先删除,在创建表。
	 * 需要将第二步骤的备份文件恢复回来,否则将会导致无法执行删除操作。
	 * 在my.ini或者my.cnf文件中注释如下配置: #innodb_force_recovery = 6
	 * @throws Exception
	 */
	public static void errorLogParseCreateTables() throws Exception {
		
		Map<String,Integer> tables = getTableColumnsNum();
		for (Entry<String, Integer> table : tables.entrySet()) {
			
			String c = "drop table if exists "+table.getKey()+";\n";
			c += "create table "+table.getKey();
			c+= "( ";
			for (int i = 0; i < table.getValue(); i++) {
				c+= "a"+i+" int,";
			}
			c = c.substring(0, c.length()-1);
			c+="  );";
			System.out.println(c);
		}
	}
	
	/**
	 *  4、经过上面三个步骤,我们可以通过navcat工具将完整的表结构信息导出来,或者通过sql语句。
	 *    然后在重新执行导出的语句,到此为止就算是将数据库结构ddl表结构恢复了。
	 */
	public static void showCreateTables() throws Exception {
		
		//通过navcat自己导出表结构即可。
	}
	
	/**
	 *  5、解除所有表的.ibd文件与.frm文件绑定
	 * 
	 */
	//.ibd文件与原先的.frm文件解除绑定
	public static void discardTablespace() throws Exception {
		
		List<String> tables = getAllTables();
		for (String table : tables) {
			String c = "alter table "+table+" discard tablespace;";
			System.out.println(c);
		}
		
	}
	/**
	 *  6、将需要恢复的表的.ibd文件拷贝到数据库文件中,
	 *    然后在重新执行绑定即恢复了数据
	 */
	//.ibd文件与原先的.frm文件解除绑定
	public static void importTablespace() throws Exception {
		
		List<String> tables = getAllTables();
		for (String table : tables) {
			String c = "alter table "+table+" import  tablespace;";
			System.out.println(c);
		}
		
	}
	
	
	
	

	/**
	 * 提取表名称和表具体字段数量的正则表达式
	 */
	final static String getTableNameAndColumnsNum = ".*table "+databaseName+"/(\\S+) contains 1 user defined columns in InnoDB, but (\\d+) columns in MySQL. Please check INFORMATION_SCHEMA.INNODB_SYS_COLUMNS.*"; 
	/**
	 * 通过具体的错误日志提取表名称及表的列数量
	 * @return
	 * @throws Exception
	 */
	private static Map<String, Integer> getTableColumnsNum() throws Exception {
		
		List<String> tables = getAllTables();
		BufferedReader reader = new BufferedReader(new FileReader("F:\\pdy\\path\\pdyerror.log"));
		String line = null;
		Map<String, Integer> result = new HashMap<>();
		try {
			while ((line = reader.readLine()) != null) {
				
				if(line.matches(getTableNameAndColumnsNum)) {
					Matcher m = Pattern.compile(getTableNameAndColumnsNum).matcher(line);
					while(m.find()) {
						String table = m.group(1);
						String cloumns = m.group(2);
						if(tables.contains(table)) {
							result.put(table, Integer.parseInt(cloumns));
						}
					}
				}
			}
		} finally {
			reader.close();
		}
		return result;
	
	}

	private static List<String> getAllTables() throws Exception {
		
		BufferedReader reader = new BufferedReader(new FileReader("F:\\pdy\\path\\ta.txt"));
		String line = null;
		
		List<String> frm = new ArrayList<String>();
		try {
			while ((line = reader.readLine()) != null) {
				
				String[] ss = line.split("\\s+");
				for (String s : ss) {
					if(s.endsWith(".frm")) {
//						System.out.println(s);
						frm.add(s.substring(0, s.length()-4));
					}
				}
			}
		} finally {
			reader.close();
		}
		return frm;
	}
	private static List<String> getAllTables(String path) throws Exception {
		
		BufferedReader reader = new BufferedReader(new FileReader(path));
		String line = null;
		
		List<String> frm = new ArrayList<String>();
		try {
			while ((line = reader.readLine()) != null) {
				
				String[] ss = line.split("\\s+");
				for (String s : ss) {
					if(s.endsWith(".frm")) {
//						System.out.println(s);
						frm.add(s.substring(0, s.length()-4));
					}
				}
			}
		} finally {
			reader.close();
		}
		return frm;
	}
	
	public static void main(String[] args) throws Exception {
		List<String> s = getAllTables();
		List<String> ss = getAllTables("F:\\pdy\\path\\pdy.log");
		for (String table : ss) {
			if(!s.contains(table)) {
				System.out.println("drop talbe "+table+";");
			}
		}
//		firstCreateTempTable();
//		errorLogParseCreateTables();

//		discardTablespace();
//		importTablespace();
	}
}

### MySQL数据量迁移的方法最佳实践 对于拥有上百万条记录的数据表,当其体积达到GB级别时,传统的`mysqldump`工具或图形界面客户端如Navicat可能不是最优的选择,因为这些方式可能会耗费大量的时间来完成整个过程[^1]。 #### 使用物理文件拷贝的方式迁移 直接复制粘贴数据库`data`目录下的`.frm`, `.ibd`等文件确实能够提供一种更加快捷的方式来实现数据的转移。不过,在采取这种方法之前有几个重要的注意事项: - **确保源库与目标库版本一致**:不同版本之间可能存在不兼容的情况; - **关闭MySQL服务后再操作**:防止因程序正在运行而导致文件损坏; - **备份原有环境中的配置参数**:比如字符集设置、存储引擎选项等,以便于新环境中保持相同设定; 这种方式适用于同构平台间的快速迁移需求,但在异构环境下则需谨慎考虑其他因素的影响。 #### SQL语句批量导入导出法 另一种可行方案是利用SQL命令来进行大批量数据的操作。例如可以通过构建复杂的`INSERT INTO ... SELECT FROM ... WHERE ...`结构化查询语言指令,将所需迁徙的内容高效地转移到新的位置。值得注意的是要保证外部文本文件采用UTF-8编码格式以避免可能出现的乱码现象[^2]。 ```sql -- 将表a中的部分符合条件的数据插入到b表中 INSERT INTO b (字段1, 字段2...) SELECT 字段1, 字段2... FROM a WHERE 条件; ``` 为了进一步提高效率并减少锁定期间对业务造成影响,建议分批次执行上述DML(Data Manipulation Language)语句,并合理调整每次处理的数量规模以及事务隔离级别。 #### 数据泵工具Percona XtraBackup的应用 除了以上两种较为基础的技术手段外,还有专门针对InnoDB/MyISAM类型的高性能在线热备解决方案——Percona XtraBackup。该软件能够在不影响现有应用正常工作的前提下安全可靠地完成大规模数据集的异地同步工作,尤其适合生产环境中实施零停机维护作业的需求。 综上所述,具体选择哪种方式进行MySQL大容量数据迁移取决于实际应用场景的要求技术栈的支持程度等因素综合考量的结果。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值