在稍大一些的項目中,我們總是需要管理各種各樣的類型類型數(shù)據(jù)(如商品類型、游戲類型。。。)。對于這些類型的管理類似,如果為每一種類型都建立一張表去維護(而在項目中,正常出現(xiàn)50種類型),那工作量是可想而之大,并且我們不得不去了解每一個類型表的名字,以去關(guān)聯(lián)它。 因此,我們需要一種數(shù)據(jù)模型以完成對多種多樣類型管理的需求。 =========================================================================================================字典表設(shè)計及應(yīng)用舉例 為了響應(yīng)志峰兄弟的需求,今天抽了點時間寫點關(guān)于字典表設(shè)計的東西,順便結(jié)合一個小的應(yīng)用對設(shè)計做個用例體驗。 咱先來看看什么叫字典。 也就是說,我們有“維護字典信息”的需求,那么我們在設(shè)計字典信息表結(jié)構(gòu)的時候就要考慮到這個需求。 具體表數(shù)據(jù)特征請看下面的例子。 ATID(自動增長的ID,沒有實際作用) 這樣,在我們的業(yè)務(wù)信息表中,存放的和字典相關(guān)的字段的值就是Dic_Data中的ID的值,那么就涉及到在界面上顯示信息的問題,如果不做處理,顯示出來的肯定就是原始的字典信息的ID,肯定不是用戶希望得到的,基于這個需求, 應(yīng)用舉例。 字典內(nèi)容表設(shè)計如下(Dic_Data): 性別類型字典的視圖(VW_Sex): 假設(shè)學生信息表如下T_Student: 取學生列表信息可通過如下方法實現(xiàn): 結(jié)果如下:
時間倉促,寫的粗糙了點,還請見諒,有時間再補充。。。 綠色通道:好文要頂關(guān)注我收藏該文與我聯(lián)系
================================================================================================================================
我們現(xiàn)在在進行數(shù)據(jù)庫字典表設(shè)計時,有二種方式,其一是傳統(tǒng)的方式,每個字典表都有ID、Name兩字段。第二種方式是將所有字典表的數(shù)據(jù)放在同一張表中,結(jié)構(gòu)如下: TypeTable(typeID,typeName)【主表,用來記錄字典表表名信息】;DataTable(typeID,DataId,DataName)【從表,記錄所有字典表數(shù)據(jù)信息】 如性別、婚姻狀態(tài),在TypeTable中是兩條記錄,{02,性別},{06,婚姻狀態(tài)};而在DataTable中各有三條記錄{02,0,女 / 02,1,男 / 02,9,其它},{06,0,未婚 / 06,1,已婚 / 06,9,離異} 另有一張病人列表patient(patientID,SexID,MarryStatusID…) 現(xiàn)在需要查詢病人信息,sql語句如下: Select b.DataName as SexName,c.DataName as MarryStatusName from patient a left join DataTable b on b.DataId=a.SexID and b.typeID=’02’ left join DataTable c on c.DataId=a.MarryStatusId and b.typeID=’06’
(當然在實際業(yè)務(wù)中可能類似的字典表約達5-10個,patient的數(shù)據(jù)量約500w條)
================================================================================================================================ 樓上的可能沒明白樓主的意思。 不是指學歷表和國籍表數(shù)據(jù)量大,而是指人員表所具有的屬性可能太多(這里不一定指人員表,也可能是其它的實體,即隨著系統(tǒng)的復雜程度增加,實體的屬性增加)。這里以人員為例,說了國籍和學歷兩個屬性,如果人員還有職位,那么必然多出職位表,如果還有其它... 那即,當取得一條實例的完全數(shù)據(jù)時,那將進行幾十個表的join,樓主考濾的應(yīng)該是這個問題。 person_info(person_id,name,country_id,education_id,position_id,....)
補充: 在 應(yīng)用開發(fā)中,總會遇到許多數(shù)據(jù)字典項,比如對象狀態(tài)、對象類型等等,這些項一般都是固定的若干可選值選項,比如對象狀態(tài)可能有新建、修改、刪除等狀態(tài),這 些數(shù)據(jù)字典項一旦定義完畢改動的頻率非常低;在應(yīng)用開發(fā)中,為了處理方便,一般要對這些數(shù)據(jù)字典項值選項進行數(shù)字編碼(例如: 0表示新建,1表示修改,2表示刪除等),以方便應(yīng)用程序中使用。而UI顯示對象信息時不能顯示對象狀態(tài)等的編碼,對于編碼值設(shè)計人員知道代表什么意思,但用戶就不明白了,所以需要進行編碼轉(zhuǎn)換,從編碼轉(zhuǎn)換為文字描述(名稱),也就是需要把狀態(tài)編碼0轉(zhuǎn)換為“新建”,把1轉(zhuǎn)換為“修改”,把2轉(zhuǎn)換為“刪除”等顯示給用戶,用戶才明白對象當前的狀態(tài)是什么。 下面介紹一下常用的實現(xiàn)方法: 實現(xiàn)方案: 一、在java文件中定義數(shù)據(jù)字典項 我們習慣上把應(yīng)用中遇到的數(shù)據(jù)字典項都定義到一個java文件中,這是最常用的方法,實現(xiàn)起來比較簡單,但維護起來就非常繁瑣,特別是數(shù)據(jù)字典項比較多的情況下,相應(yīng)的java文件就會比較大,一旦數(shù)據(jù)字典項有更新那么維護起來就比較費時費力。 在java文件中定義數(shù)據(jù)字典項通常情況下定義為static,舉例來說,類ReportConstants中定義了以下數(shù)據(jù)字典項: public static final int CODE_USERINF_TECHELEVEL_GJ = 1; public static final String CODE_USERINF_TECHELEVEL_GJ_KEY = “高級“; public static final int CODE_USERINF_TECHELEVEL_ZJ = 2; public static final String CODE_USERINF_TECHELEVEL_ZJ_KEY = “中級“; public static final int CODE_USERINF_TECHELEVEL_CJ = 3; public static final String CODE_USERINF_TECHELEVEL_CJ_KEY = “初級“; public static final int CODE_USERINF_TECHELEVEL_WJ = 4; public static final String CODE_USERINF_TECHELEVEL_WJ_KEY = “無職稱“; 那么我們在實現(xiàn)中就可以直接引用相應(yīng)的數(shù)據(jù)字典項編碼及名稱,另外,一般情況下需要定義數(shù)據(jù)字典項編碼和名稱的轉(zhuǎn)換方法,比如: public static String getCodeName(int lCode) { //初始化返回值 String strReturn = “未知“; switch (lCode) { case CODE_USERINF_TECHELEVEL_GJ : strReturn = CODE_USERINF_TECHELEVEL_GJ_KEY; break; case CODE_USERINF_TECHELEVEL_ZJ : strReturn = CODE_USERINF_TECHELEVEL_ZJ_KEY; break; case CODE_USERINF_TECHELEVEL_CJ : strReturn = CODE_USERINF_TECHELEVEL_CJ_KEY; break; case CODE_USERINF_TECHELEVEL_WJ : strReturn = CODE_USERINF_TECHELEVEL_WJ_KEY; break; } return strReturn; } 這個方法實現(xiàn)了通過數(shù)據(jù)字典項編碼獲得數(shù)據(jù)字典項名稱的功能。那么還需要實現(xiàn)一個對應(yīng)的方法,getCodeByName(String name),即通過數(shù)據(jù)字典項名稱獲取數(shù)據(jù)字典項編碼功能(代碼這里省略,請讀者自己完成)。這樣就可以實現(xiàn)數(shù)據(jù)字典項編碼和名稱的相互轉(zhuǎn)換。 但是一旦出現(xiàn)數(shù)據(jù)字典項名稱或編碼需要更改(“無職稱”項編碼需要由“4”改為“0”),或增加減少數(shù)據(jù)字典項,都需要更新java文件代碼。是否有簡便的方法在滿足上述需求的情況下又不更新java文件代碼?答案是肯定的。下面我們來介紹兩種實現(xiàn)方法:一中使用xml文件,一種在數(shù)據(jù)庫定義。 二、在xml文件中定義 第一種方案是應(yīng)用xml配置文件來定義數(shù)據(jù)字典項。使用xml配置文件,以便最大限度的減小維護的工作量,避免java代碼的頻繁修改。 下面我們分步驟詳細介紹一下使用xml配置文件的實現(xiàn)方案 第一步:定義xml數(shù)據(jù)字典項配置文件 首先新建一個xml文件,命名為DataDictionaryConfig.xml(名字可以自己定義),把應(yīng)用的用到的數(shù)據(jù)字典項分組定義到xml文件中,舉例如下,我們定義了下列數(shù)據(jù)字典項: <?xml version=”1.0″ encoding=”GB2312″?> <data-dictionaries> <data-dictionary> <group value = “0” name=”O(jiān)bjectStatus”> <option value=”0″ name=”detached”/> <option value=”1″ name=”new”/> <option value=”2″ name=”updated”/> <option value=”3″ name=”deleted”/> </group> <group value = “1” name=”O(jiān)bjectTypes”> <option value=”0″ name=”對象類型選項0″/> <option value=”1″ name=”對象類型選項1″/> <option value=”2″ name=”對象類型選項2″/> <option value=”3″ name=”對象類型選項3″/> <option value=”4″ name=”對象類型選項4″/> </group> </data-dictionary> </data-dictionaries> 這個xml文件可以根據(jù)需要進行擴展,滿足更復雜應(yīng)用的需要。 第二步,定義數(shù)據(jù)字典項對象類和數(shù)據(jù)字典項分組對象類: 對于數(shù)據(jù)字典項這里我們定義了一個數(shù)據(jù)字典項對象類,一組數(shù)據(jù)字典選項集我們定義了一個數(shù)據(jù)字典項分組對象類,如下: (1)、數(shù)據(jù)字典項類: public class DataDictionaryItem { public DataDictionaryItem() { } private String code; private String name; public void setCode(String code) { this.code = code; } public String getCode() { return this.code; } public void setName(String name) { this.name = name; } public String getName() { return this.name; } } (2)、數(shù)據(jù)字典項分組類 public class DataDictionaryItems { public DataDictionaryItems() { } //數(shù)據(jù)字典項分組編碼 private String groupCode; //數(shù)據(jù)字典項分組名稱 private String groupName; //數(shù)據(jù)字典項詳細 private java.util.ArrayList items; public void setGroupCode(String code) { this.groupCode = code; } public String getGroupCoude() { return this.groupCode; } public void setGroupName(String name) { this.groupName = name; } public String getGroupName() { return this.groupName; } //設(shè)置數(shù)據(jù)字典項 public void setDataDictionaryItem(DataDictionaryItem item) { if(this.items == null) this.items = new java.util.ArrayList(); this.items.add(item); } //設(shè)置數(shù)據(jù)字典項 public void setDataDictionaryItem(String itemName, String itemCode) { if(this.items == null) this.items = new java.util.ArrayList(); DataDictionaryItem item = new DataDictionaryItem(); item.setCode(itemCode); item.setName(itemName); this.items.add(item); } //獲得數(shù)據(jù)字典項組對象 public java.util.ArrayList getDataDictioanryItems() { return this.items; } 第三步,定義Xml數(shù)據(jù)字典項配置文件解析類,這里我們使用Dom4J,相應(yīng)的jar可以在http://www./上找到 import org.dom4j.*; import org.dom4j.io.*; import java.util.*; public class XMLDDItemParser { //數(shù)據(jù)字典項結(jié)構(gòu) public static DataDictionaryItems dataItems ; private static String GROUP_NAME = “name”; private static String GROUP_CODE = “value”; private static String ITEM_NAME = “name”; private static String ITEM_CODE = “value”; public XMLDDItemParser() { } /** * 獲得分組數(shù)據(jù)字典項集 * @param groupName String * @return DataDictionaryItems */ public static DataDictionaryItems getDataDictionaryItems(String groupName) { if(dataItems == null) dataItems = parseXML(groupName); return dataItems; } /** * 根據(jù)分組名稱解析xml文件,獲得該分組下數(shù)據(jù)字典項集 * @param gName String * @return DataDictionaryItems 數(shù)據(jù)字典項分組對象 */ public static DataDictionaryItems parseXML(String gName) { try { org.dom4j.io.SAXReader saxReader = new org.dom4j.io.SAXReader(); Document document = saxReader.read(“DataDictionaryConfig.xml”); dataItems = new DataDictionaryItems(); List list = document.selectNodes(“//group”); Iterator iter = list.iterator(); while (iter.hasNext()) { Node node = (Node) iter.next(); if (node instanceof Element) { //document Element element = (Element) node; String GroupName = element.attributeValue(GROUP_NAME); String GroupValue = element.attributeValue(GROUP_CODE); //設(shè)置分組名稱編碼 dataItems.setGroupName(GroupName); dataItems.setGroupCode(GroupValue); //取組內(nèi)數(shù)據(jù)字典項 if (gName.equals(GroupName)) { //取數(shù)據(jù)字典項名稱編碼 Iterator elemIter = element.elementIterator(); while (elemIter.hasNext()) { Element elem = (Element) elemIter.next(); dataItems.setDataDictionaryItem(elem.attributeValue(ITEM_NAME), elem.attributeValue(ITEM_CODE)); } } } } } catch (Exception ex) { ex.printStackTrace(); } return dataItems; } 第四步,提供數(shù)據(jù)字典項編碼轉(zhuǎn)換方法類: public class DataDictionaryUtils { public DataDictionaryUtils() { } /** * 根據(jù)數(shù)據(jù)項名稱轉(zhuǎn)換為數(shù)據(jù)項編碼 * @param groupName String * @param itemName String * @return String 數(shù)據(jù)項編碼 */ public static String getItemCode(String groupName, String itemName) { String code = “-1″; DataDictionaryItems dataItems = XMLDDItemParser.getDataDictionaryItems(groupName); java.util.ArrayList items = dataItems.getDataDictioanryItems(); if(items != null) { DataDictionaryItem item; for(int i = 0; i < items.size(); i++) { item = (DataDictionaryItem) items.get(i); if(item != null) { String name = item.getName(); if(name.equals(itemName)) { code = item.getCode(); break; } } } } return code; } /** * 根據(jù)數(shù)據(jù)項編碼轉(zhuǎn)換為數(shù)據(jù)項名稱 * @param groupName String * @param itemCode String * @return String */ public static String getItemName(String groupName, String itemCode) { String name = “未知“; DataDictionaryItems dataItems = XMLDDItemParser.getDataDictionaryItems(groupName); java.util.ArrayList items = dataItems.getDataDictioanryItems(); if (items != null) { DataDictionaryItem item; for (int i = 0; i < items.size(); i++) { item = (DataDictionaryItem) items.get(i); if (item != null) { String code = item.getCode(); if (code.equals(itemCode)) { name = item.getName(); break; } } } } return name; } 至此,我們已經(jīng)完成了該方案的設(shè)計。使用xml文件,增加刪除數(shù)據(jù)字典項等只需要更新xml文件即可,不涉及java文件的更新。 Xml可以根據(jù)應(yīng)用的具體需要進行擴展設(shè)計。這里僅僅拋磚引玉,提供一種思路。 三、使用數(shù)據(jù)庫表 上一種方法我們使用xml文件定義數(shù)據(jù)字典項,現(xiàn)在我們把數(shù)據(jù)字典項定義在數(shù)據(jù)庫表中,下面我們來詳細介紹實現(xiàn)方式: 第一步:定義數(shù)據(jù)字典項數(shù)據(jù)表結(jié)構(gòu) 根據(jù)前面xml文件定義,這里我們定義兩張表,一張是數(shù)據(jù)字典分組信息表,一張是數(shù)據(jù)字典項詳細信息表。如下: drop table datadic_groups; create table datadic_groups( group_code varchar2(20) primary key, group_name varchar2(50) ); drop table datadic_items; create table datadic_items( dataitem_code varchar2(20) primary key, dataitem_name varchar2(50), group_code varchar2(20) ); alter table datadic_items add constraint dataitem_foreignkey foreign key (group_code) references datadic_groups(group_code); 這兩張表可以根據(jù)應(yīng)用的具體需求進行擴充,這里不再贅述。 第二步:根據(jù)定義的數(shù)據(jù)字典表結(jié)構(gòu)定義數(shù)據(jù)字典實體類。 (請參照二、在xml文件中定義的第二步) 第三步:實現(xiàn)數(shù)據(jù)庫表中數(shù)據(jù)字典項的查詢功能 /** * 實現(xiàn)從數(shù)據(jù)庫查詢數(shù)據(jù)字典項 * @param gName String * @return DataDictionaryItems */ public static DataDictionaryItems getFromDB(String gName) { dataItems = new DataDictionaryItems(); try { //獲取數(shù)據(jù)連接 java.sql.Connection conn = getConnection(); if(conn != null) { //查詢數(shù)據(jù)庫,根據(jù)組名稱查詢組編號,根據(jù)組編號獲取該組內(nèi)數(shù)據(jù)字典項信息 String strSql = “select items.dataitem_code, items.dataitem_name, items.group_code, dgroups.group_name from datadic_items items, datadic_groups dgroups where items.group_code = dgroups.group_code and dgroups.group_name='”+gName+”'”; java.sql.Statement stmt = conn.createStatement(); java.sql.ResultSet rs = stmt.executeQuery(strSql); while(rs.next()) { String dataitem_code = rs.getString(1); String dataitem_name = rs.getString(2); dataItems.setDataDictionaryItem(dataitem_name, dataitem_code); String group_code = rs.getString(3); String group_name = rs.getString(4); dataItems.setGroupCode(group_code); dataItems.setGroupName(group_name); } } } catch(Exception ex) { ex.printStackTrace(); } return dataItems; } 第四步:提供數(shù)據(jù)字典項編碼轉(zhuǎn)換方法類: (請參照二、在xml文件中定義的第四步) 四、進一步完善 1、兩種方式都可以提供數(shù)據(jù)字典項維護界面,直接在維護界面上操作數(shù)據(jù)字典項,避免由于誤操作導致xml文件或數(shù)據(jù)庫數(shù)據(jù)錯誤。具體的實現(xiàn)也是比較簡單,不再詳細說明。 2、 使用數(shù)據(jù)庫表方式時,如果想減少頻繁查詢數(shù)據(jù)庫,可以將數(shù)據(jù)字典項信息在系統(tǒng)啟動后第一次訪問時加載內(nèi)存中,如果數(shù)據(jù)字典項數(shù)據(jù)量比較大,可實現(xiàn)一自維護 線程,采用最近最少使用算法,將頻繁使用的數(shù)據(jù)字典項駐留內(nèi)存,將長期不用的數(shù)據(jù)字典項從內(nèi)存中刪除,每次自動檢查內(nèi)存中的數(shù)據(jù)字典項,如果存在則從內(nèi)存 中讀取,如果不存在則查詢數(shù)據(jù)庫,替換內(nèi)存中最少使用的數(shù)據(jù)字典項。 3、增加運行日志記錄,可以使用log4J來記錄運行日志 |
|