在数据迁移的过程中,可能涉及到要清除数据库中表数据,大家在做删除操作的过程中经常遇到,想要删除的表往往有很多外键相关联的表,必须将这些有关联的表的数据清空掉以后,才能将需要删除的表数据清空。
如:delete from testXX;报错外键约束 ‘FK_XX_XX’ 这样需要查询是那张表,select * from user_constraints t where lower(t.constraint_name) like 'fk_xx_xx%' 往往这个过程有些复杂,执行删除语句,发现是哪个外键引用,然后找到表,然后清除这个引用表的数据,然后继续以上步骤。。。
基于此类繁琐的操作,要删除的表少了还可以手动测试,最后整理需要顺序删除的语句,但是如果表很多,这个过程就相当繁琐了,所以决定写一个测试类,来解决这个问题,让程序自动运行,自动删除表,遇到有外键约束的表优先删除后,再进行删除需要删除的表。
代码如下:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.UnavailableException;
/**
* @author Bicashy
*/
public class TableOperate {
static Statement stmt = null;
static Connection conn = null;
static Map map = new HashMap(); //用来保存已经删除了的表的集合
static Map filterMap = new HashMap(); //用来保存需要过滤的表的集合
static String schema ;
/**
* 获得数据库链接
* @return
*/
private static Connection getConnection(){
try {
Class.forName( "oracle.jdbc.driver.OracleDriver").newInstance();
//String url= "jdbc:oracle:thin:@10.45.10.177:1521:highway";
String url= "jdbc:oracle:thin:@127.0.0.1:1521:highway";
String user= "sa";
String password= "123456";
schema = user;
conn = DriverManager.getConnection(url,user,password);
return conn;
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* 获得该用户的所有表,并删除表(除了要过滤的表)
*/
private static void findDeleteTableSQL(){
if(conn!=null){
try {
stmt=conn.createStatement();
String sql = "select * from user_tables";
//找到该链接用户的所有表
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()){
String tabName = rs.getString("table_name");
//如果map中包含了表名,说明已经删除过了
//如果filterMap中包含了表名,则不删除
if(!map.containsKey(tabName)&&!filterMap.containsKey(tabName)){
printDeleteTableSQL(tabName);
}
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
*
* 删除表,并将删除表的语句输出到控制台(记录后方便在数据库客户端执行)
* @param l
* @param tableName
* @return
*/
private static void printDeleteTableSQL(String tableName){
String sql = "DELETE FROM "+tableName.toUpperCase();
try {
stmt=conn.createStatement();
stmt.execute(sql);
stmt.close();
System.out.println(sql+";"); //将删除语句输出到控制台
map.put(tableName,null);
} catch (Exception e) {
// TODO Auto-generated catch block
String error = e.toString();
String errorStart = "java.sql.SQLException: ORA-02292: 违反完整约束条件 ("+schema.toUpperCase()+".";
int start = errorStart.length();
int end = error.length()-") - 已找到子记录 ".length();
//截取错误信息得到外键约束名称
String fk_constraints = error.substring(start,end);
deleteTableNameFromFK(fk_constraints);
//删除外键约束表后,就可以将本表删掉
printDeleteTableSQL(tableName);
}
}
/**
* 删除通过外键约束找到的有子记录的表
* @param fk_constraints
*/
private static void deleteTableNameFromFK(String fk_constraints){
String sql = "select table_name from user_constraints where constraint_name='"+fk_constraints+"'";
try {
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()){
String tabN = rs.getString("table_name");
printDeleteTableSQL(tabN);//递归
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 初始化需要过滤表的集合(该表如果是别的表的外键关联表也有可能被删除)
*/
private static void initFilterMap(){
String[] tables = {"ETC_USER","etc_dic_data","MENU"};
for (int j = 0; j < tables.length; j++) {
filterMap.put(tables[j].toUpperCase(),null);
}
}
public static void main(String[] args) {
getConnection();
//initFilterMap();//初始化不需要删除的表
//删除该用户下所有表(除了需要过滤的),并获得删除语句
//findDeleteTableSQL();
//删除某一个表(有外键约束的表将先删除),并获得删除语句
printDeleteTableSQL("obu_mast");
}
}