志當存高遠,功到自然成!

          少年強則中國強,少年進步則中國進步!

          BlogJava 首頁 新隨筆 聯系 聚合 管理
            53 Posts :: 2 Stories :: 2 Comments :: 0 Trackbacks

          有關讀數據庫的無刷新的三級聯動以及層次數據(樹形結構)在關系數據庫的存儲

          關鍵字: jsp 三級聯動 層次 樹形結構 數據庫

          我的標題真冗長:P

          最近一直在考慮這個問題,如何在現在常用的關系型數據庫(如mysql,mssql)中存儲含有層次結構(例如xml或者樹型結構)的數據,我最終要實現的結果是一個比較好的頁面三級聯動菜單。比較了一下現有的三級聯動,無非有兩種解決方案,1、將所有數據寫成靜態的,這樣的缺點在于對更新封閉;2、每改變一次去數據庫中獲取數據,填充到下一級菜單,這個缺點是對數據庫的開銷比較大,查詢一次數據要對數據庫做三次操作,而且數據庫設計的比較丑陋。上述兩種方法都讓我比較不能接受。

          我想的是一種比較優雅的解決方案:在數據庫中存儲的數據不要冗余,便于查詢,不要產生遞歸,對數據庫的開銷要盡可能的小,盡量做到一次將所有數據都讀出來,用戶也要有比較好的體驗。我最初的解決方案就是用xml來存儲聯動的數據,但是對于數據庫操作來說,最后還是要落實到對文件的I/O操作,從這方面來講,使用xml和數據庫并沒有什么本質的不同。另外一種解決方案就是在關系數據庫中存類xml的數據了。google了半天,最后發現了一片自己學院一位學長翻譯的文章www.nirvanastudio.org/category/database,講得就是如何在關系型數據庫存儲這種層次數據的。文中提出了兩種解決方案,一是“鄰接列表模型”或稱為“遞歸方法”,這種存在著數據冗余,而且遞歸出于眾所周知的原因,效率不高。第二種方法,也就是我現在采用的方法是"前序優先遍歷",表結構也很簡單,沒有冗余

          id name left right

          我覺得應該屬于一種深度優先。通過每個節點的左右兩個屬性獲得其子女的屬性,好處就在于獲得一個或幾個節點只需要一次查詢,而在更新的時候速度會比較慢,因為要更新多個后繼節點,不過話說回來,更新相對于獲取來說次數要少的多,可以忽略。

          下面是我的解決方案:


          java 代碼

           
          1. import java.io.IOException;  
          2. import java.sql.Connection;  
          3. import java.sql.ResultSet;  
          4. import java.sql.SQLException;  
          5. import java.sql.Statement;  
          6. import java.util.ArrayList;  
          7.   
          8. import com.netkc.struts.datasource.DataSource;  
          9. import com.netkc.struts.mapping.District;  
          10.   
          11. /** 
          12.  * @author SONG Yihan 
          13.  * @version 1.0 
          14.  * @date: Monday, April 09 2007 
          15.  */  
          16. public class DistrictTree {  
          17.       
          18.     private ArrayList tree;  
          19.     private Statement stmt1 = null;  
          20.     private Statement stmt2 = null;  
          21.     private Connection conn = null;  
          22.     private ResultSet rs = null;  
          23.       
          24.     public DistrictTree() {  
          25.         try {  
          26.             conn = DataSource.getConnection();  
          27.         } catch (IOException e) {  
          28.             // TODO Auto-generated catch block  
          29.             e.printStackTrace();  
          30.         } catch (SQLException e) {  
          31.             // TODO Auto-generated catch block  
          32.             e.printStackTrace();  
          33.         } catch (ClassNotFoundException e) {  
          34.             // TODO Auto-generated catch block  
          35.             e.printStackTrace();  
          36.         } catch (InstantiationException e) {  
          37.             // TODO Auto-generated catch block  
          38.             e.printStackTrace();  
          39.         } catch (IllegalAccessException e) {  
          40.             // TODO Auto-generated catch block  
          41.             e.printStackTrace();  
          42.         }   
          43.     }  
          44.       
          45.     public DistrictTree(Connection conn) {  
          46.         this.conn = conn;  
          47.     }  
          48.   
          49.     public boolean addNode(String parentId, String districtId, String districtName) {  
          50.         try {  
          51.             String sql = "SELECT * FROM district WHERE districtId='" + parentId + "';";  
          52.             conn.setAutoCommit(false);  
          53.             stmt1 = conn.createStatement();  
          54.             rs = stmt1.executeQuery(sql);  
          55.             if(rs.next()) {  
          56.                 int right = rs.getInt("rgt");  
          57.                 sql = "UPDATE district SET lft=lft+2 WHERE lft>=" + right;  
          58.                 stmt2.addBatch(sql);  
          59.                 sql = "UPDATE district SET rgt=rgt+2 WHERE rgt>=" + right;  
          60.                 stmt2.addBatch(sql);  
          61.                 sql = "INSERT INTO district (districtId, districtName, lft, rgt) VALUES ('"+districtId + "', '" + districtName + "', " +  
          62.                 (right) + ", " + (right+1) +");";  
          63.                 stmt2.addBatch(sql);  
          64.                 int[] flag = stmt2.executeBatch();  
          65.                 if(flag[flag.length - 1] == 1) {  
          66.                     conn.commit();  
          67.                     return true;  
          68.                 } else {  
          69.                     conn.rollback();  
          70.                     return false;  
          71.                 }             
          72.             }  
          73.               
          74.         } catch (SQLException e) {  
          75.             // TODO Auto-generated catch block  
          76.             e.printStackTrace();  
          77.         } finally {  
          78.   
          79.   
          80.         }  
          81.         return false;  
          82.     }  
          83.       
          84.     public boolean deleteNode(String districtId) {  
          85.         String sql = "SELECT * FROM district WHERE districtId='" + districtId + "';";  
          86.         try {  
          87.             conn.setAutoCommit(false);  
          88.             rs = stmt1.executeQuery(sql);  
          89.             if(rs.next())  
          90.             {  
          91.                 int left = rs.getInt("lft");  
          92.                 int right = rs.getInt("rgt");  
          93.                 int count = (right - left - 1) / 2 + 1;  
          94.                 int minus = count * 2;  
          95.                 sql = "DELETE FROM district WHERE lft BETWEEN " + left + " AND " + right + ";";  
          96.                 stmt2.addBatch(sql);  
          97.                 sql = "UPDATE district SET lft=lft-" + minus + " WHERE lft>"+right;  
          98.                 stmt2.addBatch(sql);  
          99.                 sql = "UPDATE district SET rgt=rgt-" + minus + " WHERE rgt>"+right;  
          100.                 stmt2.addBatch(sql);  
          101.                 int flag = stmt2.executeBatch()[0];  
          102.                 if(flag == 1) {  
          103.                     conn.commit();  
          104.                     return true;  
          105.                 } else {  
          106.                     conn.rollback();  
          107.                     return false;  
          108.                 }  
          109.                   
          110.             }  
          111.         } catch (SQLException e) {  
          112.             // TODO Auto-generated catch block  
          113.             e.printStackTrace();  
          114.         }  
          115.         return false;  
          116.     }  
          117.       
          118.     public void displayTree(String parentId) {  
          119.           
          120.           
          121.     }  
          122.       
          123.     public ArrayList getTree(String parentId) {  
          124.         String sql = "SELECT * FROM district WHERE districtId='" + parentId + "';";  
          125.         try {  
          126.             stmt1 = conn.createStatement();  
          127.             rs = stmt1.executeQuery(sql);  
          128.             if(rs.next()) {  
          129.                 int left = rs.getInt("lft");  
          130.                 int right = rs.getInt("rgt");  
          131.                 stmt2 = conn.createStatement();  
          132.                 sql = "SELECT * FROM district WHERE lft BETWEEN " + left + " AND " + right + " ORDER BY lft ASC";  
          133.                 rs = stmt2.executeQuery(sql);  
          134.                 tree = new ArrayList();  
          135.                 District district = null;  
          136.                 while(rs.next()) {  
          137.                     district = new District();  
          138.                     district.setDistrictId(rs.getString("districtId"));  
          139.                     district.setDistrictName(rs.getString("districtName"));  
          140.                     district.setLeft(rs.getInt("lft"));  
          141.                     district.setRight(rs.getInt("rgt"));  
          142.                       
          143.                     tree.add(district);  
          144.                 }     
          145.                 return tree;  
          146.                   
          147.             }  
          148.         } catch (SQLException e) {  
          149.             // TODO Auto-generated catch block  
          150.             e.printStackTrace();  
          151.         } finally {  
          152.             try {  
          153.                 if (rs != null) {  
          154.                     rs.close();  
          155.                 }  
          156.                 stmt1.close();  
          157.                 stmt2.close();  
          158.                 conn.close();  
          159.             } catch (SQLException e) {  
          160.                 // TODO Auto-generated catch block  
          161.                 e.printStackTrace();  
          162.             }  
          163.         }  
          164.           
          165.         return null;  
          166.     }  
          167.       
          168.     public ArrayList getChildren(String parentId) {  
          169.         if(tree == null) {  
          170.             tree = getTree(parentId);  
          171.         }  
          172.         ArrayList children = new ArrayList();  
          173.         int index = this.indexof(parentId);  
          174.         if(index != -1) {  
          175.             District d = tree.get(index);  
          176.             final int count = (d.getRight() - d.getLeft() - 1) / 2;  
          177.             for(int i = index + 1; i <= index + count; i++) {  
          178.                 d = tree.get(i);  
          179.                 children.add(d);  
          180.                 i += (d.getRight() - d.getLeft() - 1) / 2;  
          181.             }  
          182.         }  
          183.               
          184.         return children;  
          185.     }  
          186.       
          187.     private int indexof(String districtId) {  
          188.         for(int index = 0; index < tree.size(); index++) {  
          189.             if(districtId.equals(tree.get(index).getDistrictId())) {  
          190.                 return index;  
          191.             }  
          192.         }  
          193.         return -1;  
          194.     }  
          195.       
          196.     public boolean updateNode(String districtId, String districtName) {  
          197.         String sql = "UPDATE district SET districtName='" + districtName + "' WHERE districtId='" + districtId + "';";  
          198.         try {  
          199.             conn.setAutoCommit(false);  
          200.             stmt1 = conn.createStatement();  
          201.             int flag = stmt1.executeUpdate(sql);  
          202.             if(flag == 1) {  
          203.                 conn.commit();  
          204.                 return true;  
          205.             }  
          206.             else {  
          207.                 conn.rollback();  
          208.                 return false;  
          209.             }  
          210.                   
          211.         } catch (SQLException e) {  
          212.             // TODO Auto-generated catch block  
          213.             e.printStackTrace();  
          214.         } finally {  
          215.               
          216.         }  
          217.         return false;  
          218.     }  
          219. }

          這個最遺憾的地方就是在其中混雜了java代碼,這讓我及其不爽,但是我沒有找到向js傳值的好辦法:(


           

          js 代碼
           
          1. function District(id, name, left, right) {  
          2.             this.id=id;  
          3.             this.name=name;  
          4.             this.left=left;  
          5.             this.right=right;  
          6.         };  
          7.   
          8.         var tree = new Array();   
          9.               
          10.         <%  
          11.         for(District d : tree) {  
          12.         %>  tree.push(new District('<%=d.getDistrictId()%>', '<%=d.getDistrictName()%>', '<%=d.getLeft()%>', '<%=d.getRight()%>'));  
          13.         <%}%>  
          14.   
          15.         Array.prototype.indexof = function(id) {  
          16.             for(var index = 0; index < tree.length; index++) {  
          17.                 if(id == tree[index].id) {  
          18.                     return index;  
          19.                 }  
          20.             }  
          21.             return -1;  
          22.         };  
          23.           
          24.         function citychanged(id){  
          25.             document.getElementById('district').length = 0;  
          26.             document.getElementById('area').length = 0;  
          27.             var districts = getChildren(id);  
          28.             for(var i = 0; i < districts.length; i++){  
          29.                 document.getElementById('district').options[i] = new Option(districts[i].name, districts[i].id);  
          30.             }  
          31.         };  
          32.           
          33.         function districtchanged(id) {  
          34.             document.getElementById('area').length = 0;  
          35.             var area = getChildren(id);  
          36.             for(var i = 0; i < area.length; i++){  
          37.                 document.getElementById('area').options[i] = new Option(area[i].name, area[i].id);  
          38.             }  
          39.         };  
          40.           
          41.         function getChildren(id) {  
          42.             if(tree.length == 0) {  
          43.               
          44.             }  
          45.             var children = new Array();  
          46.             var index = tree.indexof(id);  
          47.             if(index != -1) {  
          48.                 var d = tree[index];  
          49.                 var count = (d.right - d.left - 1) / 2;  
          50.                 for(var i = index + 1; i <= index + count; i++) {  
          51.                     d = tree[i];  
          52.                     children.push(d);  
          53.                     i += (d.right - d.left - 1) / 2;  
          54.                 }  
          55.             }  
          56.             return children;  
          57.         };  

           


           

          jsp 頁面 代碼
           
          1.     "/fastfoodAct?method=query" styleId="queryFoodForm">  
          2.   
          3.         searchType : 
          4.         city : 
          5.             
          6.             
              
          7.         district : 
          8.         
              
          9.         area : 
          10.         
              
          11.         restaurantName : 
          12.   
          13.         searchType : 
          14.         foodName : 
          15.            
          16.       
          17.   

           

          以上就是我解決三級聯動和層次結構的一點想法:)

          • 24ad70e5-3ffb-466d-9696-388a28edbff8-thumb
          • 描述:
          • 大小: 3.7 KB
          • Ce3cfb44-5af9-44ca-bee0-3bd18e01a8c2-thumb
          • 描述:
          • 大小: 6.2 KB
          • 55492209-e671-4efa-863d-06730be46acd-thumb
          • 描述:
          • 大小: 3 KB
          主站蜘蛛池模板: 开化县| 美姑县| 连南| 蓬溪县| 富平县| 任丘市| 和硕县| 泾源县| 白沙| 增城市| 大厂| 泗水县| 嵊州市| 临澧县| 丹凤县| 泽州县| 泰来县| 望江县| 偃师市| 合作市| 巨鹿县| 阿图什市| 芜湖市| 龙井市| 呼和浩特市| 宜兰市| 万年县| 郯城县| 青冈县| 阿拉善右旗| 广丰县| 乌鲁木齐县| 方城县| 都江堰市| 余江县| 金平| 江安县| 秦皇岛市| 垫江县| 东宁县| 临桂县|