日期:2014-05-16  浏览次数:20654 次

根据数据库表的外键依赖顺序对表进行简单排序

最近在使用DB2的时候,老是出现57016的错误(由于表不活动,不能对表进行访问),特别是在数据导入和导出的时候,必定会出现,每次都要执行reorg一下。在reorg的过程中,如果该表有外键依赖,且外键表也不活动,就需要先对外键表进行reorg。

一次数据的导入,接近30%的表不能访问了,而且还有部分表的外键检查也被disable了,在reorg前,还要先恢复外键检查,非常麻烦。一个简单的办法是先删除所有外键,在reorg所有表之后再加上外键,但是这样还是可能在最后加外键的过程中表又不活动了。

所有我想对数据库的所有表按照外键依赖顺序进行排序,这样在reorg一张表之前,保证其依赖的外键表已经被reorg了。但是还是有一个问题,就是有些表有循环的外键依赖:对于这样的问题,只能通过先删除外键,reorg之后再加上。

下面是我用JAVA写的排序算法,包含了循环依赖检查(TableFK是一个非常简单的类,就不列出了):

package test;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class ReorgAllTable {

	private static final String SCHEMA = "TEST";

	private final static String DB_URL = "jdbc:db2://localhost:50000/SIMPLE";
	private final static String DB_DRIVER = "com.ibm.db2.jcc.DB2Driver";
	private final static String DB_USERNAME = "TEST";
	private final static String DB_PASSWORD = "TEST";

	private Map<String, List<TableFK>> tableFKListMap = new HashMap<String, List<TableFK>>();

	private Map<String, TableFK> tableFKMap = new HashMap<String, TableFK>();

	private List<String> sortedTableList = new ArrayList<String>();
	private Set<String> cycleFKSet = new HashSet<String>();

	static {
		try {
			Class.forName(DB_DRIVER);
		} catch (Exception e) {
			throw new ExceptionInInitializerError(e);
		}
	}

	/**
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		ReorgAllTable reorgAllTable=new ReorgAllTable();
		reorgAllTable.sortTableSet();
		String sql = reorgAllTable.createSortedSql();
		System.out.println(sql);
	}
	
	public void sortTableSet() throws Exception {
		fetchTableFkListMap();
		Set<String> tableSet=tableFKListMap.keySet();
		Iterator<String> tableSetIter = tableSet.iterator();
		while (tableSetIter.hasNext()) {
			String table = tableSetIter.next();
			sortTable(table, null);
		}
	}
	
	private void sortTable(String table, Set<String> pCycleCheckSet) {
		List<TableFK> tableFKList = getTableFKList(table);
		if (tableFKList == null || tableFKList.isEmpty()) {
			addTable(table);
			return;
		}
		for (TableFK tableFK : tableFKList) {
			String pTable = tableFK.PKTABLE_NAME;
			if (!sortedTableList.contains(pTable)) {
				// 循环依赖检查
				Set<String> cycleCheckSet = new HashSet<String>();
				if (pCycleCheckSet != null) {
					cycleCheckSet.addAll(pCycleCheckSet);
				}
				String fkName = tableFK.FK_NAME;
				if (!cycleCheckSet.contains(fkName)) {
					cycleCheckSet.add(fkName);
				} else {
					cycleFKSet.add(fkName);
					continue;
				}
				// 递归查找
				sortTable(pTable, cycleCheckSet);
				//
				cycleCheckSet.clear();
				cycleCheckSet = null;
			}
		}
		addTable(table);
	}
	
	private void addTable(String table) {
		if (!sortedTableList.contains(table)) {
			sortedTableList.add(table);
		}
	}

	private Map<String, List<TableFK>> fetchTableFkListMap() throws Exception {
		Connection connection = DriverManager.getConnection(DB_URL, DB_USERNAME, DB_PASSWORD);
		DatabaseMetaData metaData = connection.getMetaData();
		List<String> tableList = fetchTableList(connection,metaData);
		for (String table : tableList) {
			List<TableFK> tableFKList = new ArrayList<TableFK>();
			ResultSet importedKeys = metaData.getImportedKeys(null, SCHEMA, table);
			while (importedKeys.next()) {
				TableFK tableFK = new TableFK();
				tableFK.table = table;
				tableFK.PKTABLE_SCHEM = importedKeys.getString("PKTABLE_SCHEM");// 引用的外键表模式
				tableFK.PKTABLE_NAME = importedKeys.getString("PKTABLE_NAME");// 引用的外键表名
				tableFK.PKCOLUMN_NAME = importedKeys.getString("PKCOLUMN