peacess

          統計

          留言簿(14)

          積分與排名

          閱讀排行榜

          評論排行榜

          清空數據庫數據(表)的一個解決方案


          ???? 在做數據庫開發中,經常都要清空(delete)數據或刪除(drop)所有的表。然而,外鍵的存在,給這個工作帶來了很大的不便。這里用jdbc寫一個通用的類,產生出清空或刪除表的順序。
          以下代碼在mysql與oracle下面運行正常

          (在同行的建議下作了一些改進,又增加了一些功能,見類注釋)
          代碼:
          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;

          /**
          ?* 外鍵工具
          ?* 1,返回清空(刪除)數據庫表的先后順序
          ?* 2,找出數據庫中的外鍵環
          ?* 3,找出數據庫中的對同一個表的重復外鍵關聯
          ?*
          ?* 注:外鍵環(不知道在數據庫中,對此情況有沒有別的命名)
          ?*? 情況1,外鍵表是自己 (自外鍵環、小外鍵環、單外鍵環)
          ?*? 情況2,aTable的外鍵表是bTable,而bTable的外鍵表又是aTable(雙外鍵環)
          ?*? 情況3,就是多個表之間形成的外鍵環(多外鍵環)
          ?* @author wpeace
          ?*
          ?*/
          public class ExportedKeysTools
          {
          ??? public static void main(String[] args)
          ??? {
          ??????? //得到一個數據庫的連接,這里就不細說了
          ??????? Connection connection = null;
          ???????
          ??????? List<String> tables = ExportedKeysTools.getDeleteOrder(connection);
          ???????
          ??????? System.out.print(tables);
          ??????? //清空數據,以oracle為例
          ??????? StringBuilder scrip = new StringBuilder();
          ??????? for(String it : tables)
          ??????? {
          ??????????? scrip.append(String.format("delete from %s;\r\n", it));
          ??????? }
          ??????? System.out.print(scrip);
          ??????? //刪除所有表,以oracle為例
          ???????
          ??????? for(String it : tables)
          ??????? {
          ??????????? scrip.append(String.format("drop table %s;\r\n", it));
          ??????? }
          ??????? System.out.print(scrip);
          ???????
          ??????? //提示關閉連接!!!

          ??? }
          ??? 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);
          ??? }
          ??? /**
          ???? * 返回清空(刪除)數據庫表的先后順序
          ???? * @param connection jdbc連接
          ???? * @param userName 如果為null的話,在oracle數據庫下面是所有的用戶的所有表。
          ???? * 在mysql下是當前用用戶的,這個與數據庫廠商的jdbc驅動有關系
          ???? * @return 返回清空(刪除)數據庫表的先后順序
          ???? */
          ??? public static List<String> getDeleteOrder(Connection connection,String userName)
          ??? {
          ??????? ResultSet reTables = null;
          ??????? ResultSet refk = null;
          ??????? try
          ??????? {
          ??????????? DatabaseMetaData dm = connection.getMetaData();
          ??????????? //如果是oracle數據庫的話,清空閃回表
          ??????????? if(dm.getDatabaseProductName().toUpperCase().indexOf("ORACLE")>=0)
          ??????????? {
          ??????????????? Statement state = connection.createStatement();
          ??????????????? state.execute("PURGE RECYCLEBIN");
          ??????????????? state.close();
          ??????????? }
          ??????????? //取得表
          ??????????? 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);
          ??????????????? //取得外鍵表
          ??????????????? 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)) //去掉主外鍵是自己的小環
          ??????????????????? {
          ??????????????????????? 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;)
          ??????????? {
          ??????????????? //沒有外鍵了
          ??????????????? if(!tableMeta.isFKTable())
          ??????????????? {
          ??????????????????? iterator.remove();
          ??????????????????? deleteOrder.add(tableMeta.tableName);
          ???????????????????
          ??????????????????? //清除表所使用的所有外鍵表
          ??????????????????? for(TableMeta it : tableMetaList)
          ??????????????????? {
          ??????????????????????? it.deleteFK(tableMeta.tableName);
          ??????????????????? }
          ??????????????? }

          ??????????????? if(!iterator.hasNext())
          ??????????????? {
          ??????????????????? //一次循環完成后,如果tableMeta的長度(也不為零)沒有減少,
          ??????????????????? //那么說明在tableMeta中的表之間有循環外鍵關聯的“環”,要退出整個循環
          ??????????????????? //不然此處就會有一個死循環,此時在tableMeta中的表的設計也許是有問題的
          ??????????????????? //如果要分析
          ??????????????????? 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;
          ??? }
          ??? /**
          ???? * 返回外鍵環
          ???? * @param connection 連接
          ???? * @param userName 用戶名,可以為空
          ???? * @return 返回外鍵環
          ???? */
          ??? public static List<String> getExportedKeysLoop(Connection connection,String userName)
          ??? {
          ??????? ResultSet reTables = null;
          ??????? ResultSet refk = null;
          ??????? try
          ??????? {
          ??????????? DatabaseMetaData dm = connection.getMetaData();
          ??????????? //如果是oracle數據庫的話,清空閃回表
          ??????????? if(dm.getDatabaseProductName().toUpperCase().indexOf("ORACLE")>=0)
          ??????????? {
          ??????????????? Statement state = connection.createStatement();
          ??????????????? state.execute("PURGE RECYCLEBIN");
          ??????????????? state.close();
          ??????????? }
          ??????????? //取得表
          ??????????? 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);
          ??????????????? //取得外鍵表
          ??????????????? 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)) //去掉主外鍵是自己的小環
          ??????????????????? {
          ??????????????????????? 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;)
          ??????????? {
          ??????????????? //沒有外鍵了
          ??????????????? if(!tableMeta.isFKTable())
          ??????????????? {
          ??????????????????? iterator.remove();???????????????????
          ??????????????????? //清除表所使用的所有外鍵表
          ??????????????????? for(TableMeta it : tableMetaList)
          ??????????????????? {
          ??????????????????????? it.deleteFK(tableMeta.tableName);
          ??????????????????? }
          ??????????????? }

          ??????????????? if(!iterator.hasNext())
          ??????????????? {
          ??????????????????? //一次循環完成后,如果tableMeta的長度(也不為零)沒有減少,
          ??????????????????? //那么說明在tableMeta中的表之間有循環外鍵關聯的“環”,要退出整個循環
          ??????????????????? //不然此處就會有一個死循環,此時在tableMeta中的表的設計也許是有問題的
          ??????????????????? //如果要分析
          ??????????????????? 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;
          ??? }
          ??? /**
          ???? * 有重復外鍵的表
          ???? * @param connection 連接
          ???? * @param userName 用戶名,可以為空
          ???? * @return 有重復外鍵的表
          ???? */
          ??? public static List<String> getRepeatExportedKeys(Connection connection,String userName)
          ??? {
          ??????? ResultSet reTables = null;
          ??????? ResultSet refk = null;
          ??????? try
          ??????? {
          ??????????? DatabaseMetaData dm = connection.getMetaData();
          ??????????? //如果是oracle數據庫的話,清空閃回表
          ??????????? if(dm.getDatabaseProductName().toUpperCase().indexOf("ORACLE")>=0)
          ??????????? {
          ??????????????? Statement state = connection.createStatement();
          ??????????????? state.execute("PURGE RECYCLEBIN");
          ??????????????? state.close();
          ??????????? }
          ???????????
          ??????????? List<String> repeatExportedKeys = new ArrayList<String>();
          ??????????? //取得表
          ??????????? 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);
          ??????????????? //取得外鍵表
          ??????????????? 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;
          ??????? //外鍵表
          ??????? 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);
          ??????? }
          ??????? //是否存在外鍵表
          ??????? public boolean isFKTable()
          ??????? {
          ??????????? return fkTable.size() > 0;
          ??????? }
          ??????? public void addFK(String table)
          ??????? {
          ??????????? //重名處理
          ??????????? if(!findFK(table))
          ??????????? {
          ??????????????? fkTable.add(table);
          ??????????? }
          ??????? }
          ??? }

          }






          posted on 2006-11-09 17:18 中東 閱讀(10155) 評論(10)  編輯  收藏 所屬分類: 數據庫設計篇

          評論

          # re: 清空數據庫數據(表)的一個解決方案 2006-11-09 17:39 馬嘉楠

          問一下
          在哪里關閉連接(Connection)?

          方法中聲明的ResultSet也沒有關閉
          好像有點不妥吧

          不需要關閉么?

            回復  更多評論   

          # re: 清空數據庫數據(表)的一個解決方案 2006-11-09 21:11 中東

          記錄集是應該關閉的,數據庫連接就不用了,是從從面從入的  回復  更多評論   

          # 不需要關閉么? 2006-11-09 21:22 中東

          謝謝你的提示,我再修改了一上,減少它的錯誤  回復  更多評論   

          # re: 清空數據庫數據(表)的一個解決方案 2006-11-09 21:38 海邊沫沫

          標準SQL語法:
          FOREIGN KEY [id] (index_col_name, ...)
          REFERENCES tbl_name (index_col_name, ...)
          [ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION}]
          [ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION}]
          其中:
          CASCADE: 從父表刪除或更新且自動刪除或更新子表中匹配的行。ON DELETE CASCADE和ON UPDATE CASCADE都可用。在兩個表之間,你不應定義若干在父表或子表中的同一列采取動作的ON UPDATE CASCADE子句。

          SET NULL: 從父表刪除或更新行,并設置子表中的外鍵列為NULL。如果外鍵列沒有指定NOT NULL限定詞,這就是唯一合法的。ON DELETE SET NULL和ON UPDATE SET NULL子句被支持。

          NO ACTION: 在ANSI SQL-92標準中,NO ACTION意味這不采取動作,就是如果有一個相關的外鍵值在被參考的表里,刪除或更新主要鍵值的企圖不被允許進行(Gruber, 掌握SQL, 2000:181)。 InnoDB拒絕對父表的刪除或更新操作。

          RESTRICT: 拒絕對父表的刪除或更新操作。NO ACTION和RESTRICT都一樣,刪除ON DELETE或ON UPDATE子句。(一些數據庫系統有延期檢查,并且NO ACTION是一個延期檢查。在MySQL中,外鍵約束是被立即檢查的,所以NO ACTION和RESTRICT是同樣的)。

          一句話頂你幾百行代碼,呵呵。  回復  更多評論   

          # re: 清空數據庫數據(表)的一個解決方案 2006-11-09 22:11 中東

          讓外鍵約束失效,再進行刪除,這種方法很好。
          我用的是軟件方法,不破壞原來數據庫的結構,各有優點啊!!!!!  回復  更多評論   

          # re: 清空數據庫數據(表)的一個解決方案 2006-11-09 23:22 stoneshao[匿名]

          可以試一下,dbunit  回復  更多評論   

          # re: 清空數據庫數據(表)的一個解決方案 2006-11-10 11:06

          我看你的封裝就很失敗。

          truncate table table1

          快速。不會產生回滾段。又能釋放表空間。。  回復  更多評論   

          # re: 清空數據庫數據(表)的一個解決方案 2006-11-10 11:33 壞男孩

          踩個腳印;truncate table 是oracle的吧,這兒是通用的吧  回復  更多評論   

          # re: 清空數據庫數據(表)的一個解決方案 2006-11-10 11:43 jeffjie

          DBUnit是解決不了這個問題的。
          這也是使用dbunit總不順手的原因。
          后來我自已也寫了個類似的程序。
          不過有個問題問問樓主:
          如果一個表的主鍵外鍵都是自已,你的程序能處理這個問題嗎?可以避免死循環?  回復  更多評論   

          # re: 清空數據庫數據(表)的一個解決方案 2006-11-13 11:12 peace

          @jeffjie
          這位提的很好,這個類有一個問題,就是表間的外鍵構成一個“環”(主外鍵自己的也是一個小環)時,程序會出現死循環。這個問題我再改進一下,看能不能找出解決方法,主外鍵自己的小環應該好辦,主要是幾個表之間的環,就不好處理了,不過,一般設計數據庫應該不會有這樣的情況,因為幾個表之間構成環,也就是相互依懶,插入數據都插不進去?  回復  更多評論   

          主站蜘蛛池模板: 庆阳市| 青州市| 新兴县| 乐陵市| 石柱| 南投市| 乌苏市| 新巴尔虎右旗| 宽甸| 铁岭县| 龙海市| 南皮县| 青海省| 富川| 当阳市| 收藏| 南川市| 锡林郭勒盟| 黔南| 闽侯县| 济源市| 化德县| 莱阳市| 天水市| 永康市| 射洪县| 天峻县| 图木舒克市| 涡阳县| 株洲市| 武鸣县| 武穴市| 丰顺县| 安宁市| 永德县| 海口市| 湖北省| 白城市| 志丹县| 紫金县| 新沂市|