peacess

          統(tǒng)計(jì)

          留言簿(14)

          積分與排名

          閱讀排行榜

          評(píng)論排行榜

          清空數(shù)據(jù)庫數(shù)據(jù)(表)的一個(gè)解決方案


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

          (在同行的建議下作了一些改進(jìn),又增加了一些功能,見類注釋)
          代碼:
          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,返回清空(刪除)數(shù)據(jù)庫表的先后順序
          ?* 2,找出數(shù)據(jù)庫中的外鍵環(huán)
          ?* 3,找出數(shù)據(jù)庫中的對(duì)同一個(gè)表的重復(fù)外鍵關(guān)聯(lián)
          ?*
          ?* 注:外鍵環(huán)(不知道在數(shù)據(jù)庫中,對(duì)此情況有沒有別的命名)
          ?*? 情況1,外鍵表是自己 (自外鍵環(huán)、小外鍵環(huán)、單外鍵環(huán))
          ?*? 情況2,aTable的外鍵表是bTable,而bTable的外鍵表又是aTable(雙外鍵環(huán))
          ?*? 情況3,就是多個(gè)表之間形成的外鍵環(huán)(多外鍵環(huán))
          ?* @author wpeace
          ?*
          ?*/
          public class ExportedKeysTools
          {
          ??? public static void main(String[] args)
          ??? {
          ??????? //得到一個(gè)數(shù)據(jù)庫的連接,這里就不細(xì)說了
          ??????? Connection connection = null;
          ???????
          ??????? List<String> tables = ExportedKeysTools.getDeleteOrder(connection);
          ???????
          ??????? System.out.print(tables);
          ??????? //清空數(shù)據(jù),以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);
          ???????
          ??????? //提示關(guān)閉連接!!!

          ??? }
          ??? 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);
          ??? }
          ??? /**
          ???? * 返回清空(刪除)數(shù)據(jù)庫表的先后順序
          ???? * @param connection jdbc連接
          ???? * @param userName 如果為null的話,在oracle數(shù)據(jù)庫下面是所有的用戶的所有表。
          ???? * 在mysql下是當(dāng)前用用戶的,這個(gè)與數(shù)據(jù)庫廠商的jdbc驅(qū)動(dòng)有關(guān)系
          ???? * @return 返回清空(刪除)數(shù)據(jù)庫表的先后順序
          ???? */
          ??? public static List<String> getDeleteOrder(Connection connection,String userName)
          ??? {
          ??????? ResultSet reTables = null;
          ??????? ResultSet refk = null;
          ??????? try
          ??????? {
          ??????????? DatabaseMetaData dm = connection.getMetaData();
          ??????????? //如果是oracle數(shù)據(jù)庫的話,清空閃回表
          ??????????? 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)) //去掉主外鍵是自己的小環(huán)
          ??????????????????? {
          ??????????????????????? 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())
          ??????????????? {
          ??????????????????? //一次循環(huán)完成后,如果tableMeta的長度(也不為零)沒有減少,
          ??????????????????? //那么說明在tableMeta中的表之間有循環(huán)外鍵關(guān)聯(lián)的“環(huán)”,要退出整個(gè)循環(huán)
          ??????????????????? //不然此處就會(huì)有一個(gè)死循環(huán),此時(shí)在tableMeta中的表的設(shè)計(jì)也許是有問題的
          ??????????????????? //如果要分析
          ??????????????????? 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;
          ??? }
          ??? /**
          ???? * 返回外鍵環(huán)
          ???? * @param connection 連接
          ???? * @param userName 用戶名,可以為空
          ???? * @return 返回外鍵環(huán)
          ???? */
          ??? public static List<String> getExportedKeysLoop(Connection connection,String userName)
          ??? {
          ??????? ResultSet reTables = null;
          ??????? ResultSet refk = null;
          ??????? try
          ??????? {
          ??????????? DatabaseMetaData dm = connection.getMetaData();
          ??????????? //如果是oracle數(shù)據(jù)庫的話,清空閃回表
          ??????????? 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)) //去掉主外鍵是自己的小環(huán)
          ??????????????????? {
          ??????????????????????? 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())
          ??????????????? {
          ??????????????????? //一次循環(huán)完成后,如果tableMeta的長度(也不為零)沒有減少,
          ??????????????????? //那么說明在tableMeta中的表之間有循環(huán)外鍵關(guān)聯(lián)的“環(huán)”,要退出整個(gè)循環(huán)
          ??????????????????? //不然此處就會(huì)有一個(gè)死循環(huán),此時(shí)在tableMeta中的表的設(shè)計(jì)也許是有問題的
          ??????????????????? //如果要分析
          ??????????????????? 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;
          ??? }
          ??? /**
          ???? * 有重復(fù)外鍵的表
          ???? * @param connection 連接
          ???? * @param userName 用戶名,可以為空
          ???? * @return 有重復(fù)外鍵的表
          ???? */
          ??? public static List<String> getRepeatExportedKeys(Connection connection,String userName)
          ??? {
          ??????? ResultSet reTables = null;
          ??????? ResultSet refk = null;
          ??????? try
          ??????? {
          ??????????? DatabaseMetaData dm = connection.getMetaData();
          ??????????? //如果是oracle數(shù)據(jù)庫的話,清空閃回表
          ??????????? 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) 評(píng)論(10)  編輯  收藏 所屬分類: 數(shù)據(jù)庫設(shè)計(jì)篇

          評(píng)論

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

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

          方法中聲明的ResultSet也沒有關(guān)閉
          好像有點(diǎn)不妥吧

          不需要關(guān)閉么?

            回復(fù)  更多評(píng)論   

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

          記錄集是應(yīng)該關(guān)閉的,數(shù)據(jù)庫連接就不用了,是從從面從入的  回復(fù)  更多評(píng)論   

          # 不需要關(guān)閉么? 2006-11-09 21:22 中東

          謝謝你的提示,我再修改了一上,減少它的錯(cuò)誤  回復(fù)  更多評(píng)論   

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

          標(biāo)準(zhǔn)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: 從父表刪除或更新且自動(dòng)刪除或更新子表中匹配的行。ON DELETE CASCADE和ON UPDATE CASCADE都可用。在兩個(gè)表之間,你不應(yīng)定義若干在父表或子表中的同一列采取動(dòng)作的ON UPDATE CASCADE子句。

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

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

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

          一句話頂你幾百行代碼,呵呵。  回復(fù)  更多評(píng)論   

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

          讓外鍵約束失效,再進(jìn)行刪除,這種方法很好。
          我用的是軟件方法,不破壞原來數(shù)據(jù)庫的結(jié)構(gòu),各有優(yōu)點(diǎn)啊!!!!!  回復(fù)  更多評(píng)論   

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

          可以試一下,dbunit  回復(fù)  更多評(píng)論   

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

          我看你的封裝就很失敗。

          truncate table table1

          快速。不會(huì)產(chǎn)生回滾段。又能釋放表空間。。  回復(fù)  更多評(píng)論   

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

          踩個(gè)腳印;truncate table 是oracle的吧,這兒是通用的吧  回復(fù)  更多評(píng)論   

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

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

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

          @jeffjie
          這位提的很好,這個(gè)類有一個(gè)問題,就是表間的外鍵構(gòu)成一個(gè)“環(huán)”(主外鍵自己的也是一個(gè)小環(huán))時(shí),程序會(huì)出現(xiàn)死循環(huán)。這個(gè)問題我再改進(jìn)一下,看能不能找出解決方法,主外鍵自己的小環(huán)應(yīng)該好辦,主要是幾個(gè)表之間的環(huán),就不好處理了,不過,一般設(shè)計(jì)數(shù)據(jù)庫應(yīng)該不會(huì)有這樣的情況,因?yàn)閹讉€(gè)表之間構(gòu)成環(huán),也就是相互依懶,插入數(shù)據(jù)都插不進(jìn)去?  回復(fù)  更多評(píng)論   

          主站蜘蛛池模板: 正蓝旗| 浪卡子县| 安化县| 祁门县| 元阳县| 岳普湖县| 云南省| 象州县| 卫辉市| 龙江县| 黄骅市| 贺兰县| 册亨县| 肇源县| 孙吴县| 长顺县| 瓦房店市| 黔西县| 饶阳县| 松阳县| 哈巴河县| 安岳县| 广平县| 绥棱县| 巩义市| 苍山县| 栾川县| 龙山县| 洛宁县| 永丰县| 德钦县| 敖汉旗| 东乡| 马边| 广州市| 泉州市| 尚志市| 建平县| 淳化县| 确山县| 新晃|