在做数据库开发中Q经帔R要清I(deleteQ数据或删除QdropQ所有的表。然而,外键的存在,l这个工作带来了很大的不ѝ这里用jdbc写一个通用的类Q生出清空或删除表的顺序?br />以下代码在mysql与oracle下面q行正常
(在同行的下作了一些改q,又增加了一些功能,见类注释)
代码Q?br />package createData.tryDemo;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* 外键工具
* 1Q返回清I(删除Q数据库表的先后序
* 2Q找出数据库中的外键?br /> * 3Q找出数据库中的对同一个表的重复外键关?br /> *
* 注:(x)外键环(不知道在数据库中Q对此情冉|没有别的命名Q?br /> * 情况1Q外键表是自?Q自外键环、小外键环、单外键环)
* 情况2QaTable的外键表是bTableQ而bTable的外键表又是aTableQ双外键环)
* 情况3Q就是多个表之间形成的外键环Q多外键环)
* @author wpeace
*
*/
public class ExportedKeysTools
{
public static void main(String[] args)
{
//得到一个数据库的连接,q里׃l说?br /> Connection connection = null;
List<String> tables = ExportedKeysTools.getDeleteOrder(connection);
System.out.print(tables);
//清空数据,以oracleZ
StringBuilder scrip = new StringBuilder();
for(String it : tables)
{
scrip.append(String.format("delete from %s;\r\n", it));
}
System.out.print(scrip);
//删除所有表,以oracleZ
for(String it : tables)
{
scrip.append(String.format("drop table %s;\r\n", it));
}
System.out.print(scrip);
//提示关闭q接Q!Q?br />
}
public static List<String> getDeleteOrder(Connection connection)
{
String userName = null;
try
{
userName = connection.getMetaData().getUserName();
}
catch (SQLException e)
{
e.printStackTrace();
}
return ExportedKeysTools.getDeleteOrder(connection, userName);
}
/**
* q回清空Q删除)数据库表的先后顺?br /> * @param connection jdbcq接
* @param userName 如果为null的话Q在oracle数据库下面是所有的用户的所有表?br /> * 在mysql下是当前用用L(fng)Q这个与数据库厂商的jdbc驱动有关p?br /> * @return q回清空Q删除)数据库表的先后顺?br /> */
public static List<String> getDeleteOrder(Connection connection,String userName)
{
ResultSet reTables = null;
ResultSet refk = null;
try
{
DatabaseMetaData dm = connection.getMetaData();
//如果是oracle数据库的话,清空闪回?br /> if(dm.getDatabaseProductName().toUpperCase().indexOf("ORACLE")>=0)
{
Statement state = connection.createStatement();
state.execute("PURGE RECYCLEBIN");
state.close();
}
//取得?br /> reTables = dm.getTables(null, userName, null, new String[]{"TABLE","VIEW"});
List<TableMeta> tableMetaList = new ArrayList<TableMeta>();
while(reTables.next())
{
String tableName = reTables.getString("TABLE_NAME").trim();
if(tableName == null || tableName.length()<1)
{
continue;
}
TableMeta tem = new TableMeta(tableName);
tableMetaList.add(tem);
//取得外键?br /> refk = dm.getExportedKeys(null, userName, tableName);
while(refk.next())
{
String fkTableName = refk.getString("FKTABLE_NAME").trim();
if(fkTableName == null || fkTableName.length() < 1 ||
fkTableName.equals(tableName)) //Ld键是自己的小?br /> {
continue;
}
tem.addFK(fkTableName);
}
if(refk != null)refk.close();
}
Iterator<TableMeta> iterator = tableMetaList.iterator();
TableMeta tableMeta = iterator.next();
List<String> deleteOrder = new ArrayList<String>();
int counts = tableMetaList.size();
for(;true;)
{
//没有外键?br /> if(!tableMeta.isFKTable())
{
iterator.remove();
deleteOrder.add(tableMeta.tableName);
//清除表所使用的所有外键表
for(TableMeta it : tableMetaList)
{
it.deleteFK(tableMeta.tableName);
}
}
if(!iterator.hasNext())
{
//一ơ@环完成后Q如果tableMeta的长度(也不为零Q没有减,
//那么说明在tableMeta中的表之间有循环外键兌的“环”,要退出整个@?br /> //不然此处׃(x)有一个死循环Q此时在tableMeta中的表的设计也许是有问题?br /> //如果要分?br /> if(tableMetaList.size() == counts || tableMetaList.size() < 1)
{
break;
}
iterator = tableMetaList.iterator();
}
tableMeta = iterator.next();
}
return deleteOrder;
}
catch (SQLException e)
{
if(refk != null)
try
{
refk.close();
}
catch (SQLException e1)
{
e1.printStackTrace();
}
if(reTables != null)
try
{
reTables.close();
}
catch (SQLException e1)
{
e1.printStackTrace();
}
e.printStackTrace();
}
return null;
}
/**
* q回外键?br /> * @param connection q接
* @param userName 用户名,可以为空
* @return q回外键?br /> */
public static List<String> getExportedKeysLoop(Connection connection,String userName)
{
ResultSet reTables = null;
ResultSet refk = null;
try
{
DatabaseMetaData dm = connection.getMetaData();
//如果是oracle数据库的话,清空闪回?br /> if(dm.getDatabaseProductName().toUpperCase().indexOf("ORACLE")>=0)
{
Statement state = connection.createStatement();
state.execute("PURGE RECYCLEBIN");
state.close();
}
//取得?br /> reTables = dm.getTables(null, userName, null, new String[]{"TABLE","VIEW"});
List<TableMeta> tableMetaList = new ArrayList<TableMeta>();
while(reTables.next())
{
String tableName = reTables.getString("TABLE_NAME").trim();
if(tableName == null || tableName.length()<1)
{
continue;
}
TableMeta tem = new TableMeta(tableName);
tableMetaList.add(tem);
//取得外键?br /> refk = dm.getExportedKeys(null, userName, tableName);
while(refk.next())
{
String fkTableName = refk.getString("FKTABLE_NAME").trim();
if(fkTableName == null || fkTableName.length() < 1 ||
fkTableName.equals(tableName)) //Ld键是自己的小?br /> {
continue;
}
tem.addFK(fkTableName);
}
if(refk != null)refk.close();
}
Iterator<TableMeta> iterator = tableMetaList.iterator();
TableMeta tableMeta = iterator.next();
List<String> exportedKeysLoop = new ArrayList<String>();
int counts = tableMetaList.size();
for(;true;)
{
//没有外键?br /> if(!tableMeta.isFKTable())
{
iterator.remove();
//清除表所使用的所有外键表
for(TableMeta it : tableMetaList)
{
it.deleteFK(tableMeta.tableName);
}
}
if(!iterator.hasNext())
{
//一ơ@环完成后Q如果tableMeta的长度(也不为零Q没有减,
//那么说明在tableMeta中的表之间有循环外键兌的“环”,要退出整个@?br /> //不然此处׃(x)有一个死循环Q此时在tableMeta中的表的设计也许是有问题?br /> //如果要分?br /> if(tableMetaList.size() == counts || tableMetaList.size() < 1)
{
for(TableMeta it : tableMetaList)
{
exportedKeysLoop.add(it.tableName);
}
break;
}
iterator = tableMetaList.iterator();
}
tableMeta = iterator.next();
}
return exportedKeysLoop;
}
catch (SQLException e)
{
if(refk != null)
try
{
refk.close();
}
catch (SQLException e1)
{
e1.printStackTrace();
}
if(reTables != null)
try
{
reTables.close();
}
catch (SQLException e1)
{
e1.printStackTrace();
}
e.printStackTrace();
}
return null;
}
/**
* 有重复外键的?br /> * @param connection q接
* @param userName 用户名,可以为空
* @return 有重复外键的?br /> */
public static List<String> getRepeatExportedKeys(Connection connection,String userName)
{
ResultSet reTables = null;
ResultSet refk = null;
try
{
DatabaseMetaData dm = connection.getMetaData();
//如果是oracle数据库的话,清空闪回?br /> if(dm.getDatabaseProductName().toUpperCase().indexOf("ORACLE")>=0)
{
Statement state = connection.createStatement();
state.execute("PURGE RECYCLEBIN");
state.close();
}
List<String> repeatExportedKeys = new ArrayList<String>();
//取得?br /> reTables = dm.getTables(null, userName, null, new String[]{"TABLE","VIEW"});
while(reTables.next())
{
String tableName = reTables.getString("TABLE_NAME").trim();
if(tableName == null || tableName.length()<1)
{
continue;
}
TableMeta tem = new TableMeta(tableName);
//取得外键?br /> refk = dm.getExportedKeys(null, userName, tableName);
while(refk.next())
{
String fkTableName = refk.getString("FKTABLE_NAME").trim();
if(fkTableName == null || fkTableName.length() < 1)
{
continue;
}
if(tem.findFK(fkTableName))
{
repeatExportedKeys.add(tem.tableName);
break;
}
}
if(refk != null)refk.close();
}
return repeatExportedKeys;
}
catch (SQLException e)
{
if(refk != null)
try
{
refk.close();
}
catch (SQLException e1)
{
e1.printStackTrace();
}
if(reTables != null)
try
{
reTables.close();
}
catch (SQLException e1)
{
e1.printStackTrace();
}
e.printStackTrace();
}
return null;
}
public static class TableMeta{
//表名
public String tableName;
//外键?br /> private List<String> fkTable = new ArrayList<String>(1);
public TableMeta(String table)
{
this.tableName = table;
}
public boolean findFK(String table)
{
return fkTable.contains(table);
}
public void deleteFK(String table)
{
fkTable.remove(table);
}
//是否存在外键?br /> public boolean isFKTable()
{
return fkTable.size() > 0;
}
public void addFK(String table)
{
//重名处理
if(!findFK(table))
{
fkTable.add(table);
}
}
}
}

]]>