在稍大一些的项目中,我们总是需要管理各种各样的类型类型数据(如商品类型、游戏类型。。。)。对于这些类型的管理类似,如果为每一种类型都建立一张表去维护(而在项目中,正常出现50种类型),那工作量是可想而之大,并且我们不得不去了解每一个类型表的名字,以去关联它。 因此,我们需要一种数据模型以完成对多种多样类型管理的需求。 =========================================================================================================字典表设计及应用举例 为了响应志峰兄弟的需求,今天抽了点时间写点关于字典表设计的东西,顺便结合一个小的应用对设计做个用例体验。 咱先来看看什么叫字典。 也就是说,我们有“维护字典信息”的需求,那么我们在设计字典信息表结构的时候就要考虑到这个需求。 具体表数据特征请看下面的例子。 ATID(自动增长的ID,没有实际作用) 这样,在我们的业务信息表中,存放的和字典相关的字段的值就是Dic_Data中的ID的值,那么就涉及到在界面上显示信息的问题,如果不做处理,显示出来的肯定就是原始的字典信息的ID,肯定不是用户希望得到的,基于这个需求, 应用举例。 字典内容表设计如下(Dic_Data): 性别类型字典的视图(VW_Sex): 假设学生信息表如下T_Student: 取学生列表信息可通过如下方法实现: 结果如下:
时间仓促,写的粗糙了点,还请见谅,有时间再补充。。。 绿色通道:好文要顶关注我收藏该文与我联系
================================================================================================================================
我们现在在进行数据库字典表设计时,有二种方式,其一是传统的方式,每个字典表都有ID、Name两字段。第二种方式是将所有字典表的数据放在同一张表中,结构如下: TypeTable(typeID,typeName)【主表,用来记录字典表表名信息】;DataTable(typeID,DataId,DataName)【从表,记录所有字典表数据信息】 如性别、婚姻状态,在TypeTable中是两条记录,{02,性别},{06,婚姻状态};而在DataTable中各有三条记录{02,0,女 / 02,1,男 / 02,9,其它},{06,0,未婚 / 06,1,已婚 / 06,9,离异} 另有一张病人列表patient(patientID,SexID,MarryStatusID…) 现在需要查询病人信息,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’
(当然在实际业务中可能类似的字典表约达5-10个,patient的数据量约500w条)
================================================================================================================================ 楼上的可能没明白楼主的意思。 不是指学历表和国籍表数据量大,而是指人员表所具有的属性可能太多(这里不一定指人员表,也可能是其它的实体,即随着系统的复杂程度增加,实体的属性增加)。这里以人员为例,说了国籍和学历两个属性,如果人员还有职位,那么必然多出职位表,如果还有其它... 那即,当取得一条实例的完全数据时,那将进行几十个表的join,楼主考滤的应该是这个问题。 person_info(person_id,name,country_id,education_id,position_id,....)
补充: 在 应用开发中,总会遇到许多数据字典项,比如对象状态、对象类型等等,这些项一般都是固定的若干可选值选项,比如对象状态可能有新建、修改、删除等状态,这 些数据字典项一旦定义完毕改动的频率非常低;在应用开发中,为了处理方便,一般要对这些数据字典项值选项进行数字编码(例如: 0表示新建,1表示修改,2表示删除等),以方便应用程序中使用。而UI显示对象信息时不能显示对象状态等的编码,对于编码值设计人员知道代表什么意思,但用户就不明白了,所以需要进行编码转换,从编码转换为文字描述(名称),也就是需要把状态编码0转换为“新建”,把1转换为“修改”,把2转换为“删除”等显示给用户,用户才明白对象当前的状态是什么。 下面介绍一下常用的实现方法: 实现方案: 一、在java文件中定义数据字典项 我们习惯上把应用中遇到的数据字典项都定义到一个java文件中,这是最常用的方法,实现起来比较简单,但维护起来就非常繁琐,特别是数据字典项比较多的情况下,相应的java文件就会比较大,一旦数据字典项有更新那么维护起来就比较费时费力。 在java文件中定义数据字典项通常情况下定义为static,举例来说,类ReportConstants中定义了以下数据字典项: 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 = “无职称“; 那么我们在实现中就可以直接引用相应的数据字典项编码及名称,另外,一般情况下需要定义数据字典项编码和名称的转换方法,比如: 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; } 这个方法实现了通过数据字典项编码获得数据字典项名称的功能。那么还需要实现一个对应的方法,getCodeByName(String name),即通过数据字典项名称获取数据字典项编码功能(代码这里省略,请读者自己完成)。这样就可以实现数据字典项编码和名称的相互转换。 但是一旦出现数据字典项名称或编码需要更改(“无职称”项编码需要由“4”改为“0”),或增加减少数据字典项,都需要更新java文件代码。是否有简便的方法在满足上述需求的情况下又不更新java文件代码?答案是肯定的。下面我们来介绍两种实现方法:一中使用xml文件,一种在数据库定义。 二、在xml文件中定义 第一种方案是应用xml配置文件来定义数据字典项。使用xml配置文件,以便最大限度的减小维护的工作量,避免java代码的频繁修改。 下面我们分步骤详细介绍一下使用xml配置文件的实现方案 第一步:定义xml数据字典项配置文件 首先新建一个xml文件,命名为DataDictionaryConfig.xml(名字可以自己定义),把应用的用到的数据字典项分组定义到xml文件中,举例如下,我们定义了下列数据字典项: <?xml version=”1.0″ encoding=”GB2312″?> <data-dictionaries> <data-dictionary> <group value = “0” name=”ObjectStatus”> <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=”ObjectTypes”> <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文件可以根据需要进行扩展,满足更复杂应用的需要。 第二步,定义数据字典项对象类和数据字典项分组对象类: 对于数据字典项这里我们定义了一个数据字典项对象类,一组数据字典选项集我们定义了一个数据字典项分组对象类,如下: (1)、数据字典项类: 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)、数据字典项分组类 public class DataDictionaryItems { public DataDictionaryItems() { } //数据字典项分组编码 private String groupCode; //数据字典项分组名称 private String groupName; //数据字典项详细 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; } //设置数据字典项 public void setDataDictionaryItem(DataDictionaryItem item) { if(this.items == null) this.items = new java.util.ArrayList(); this.items.add(item); } //设置数据字典项 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); } //获得数据字典项组对象 public java.util.ArrayList getDataDictioanryItems() { return this.items; } 第三步,定义Xml数据字典项配置文件解析类,这里我们使用Dom4J,相应的jar可以在http://www./上找到 import org.dom4j.*; import org.dom4j.io.*; import java.util.*; public class XMLDDItemParser { //数据字典项结构 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() { } /** * 获得分组数据字典项集 * @param groupName String * @return DataDictionaryItems */ public static DataDictionaryItems getDataDictionaryItems(String groupName) { if(dataItems == null) dataItems = parseXML(groupName); return dataItems; } /** * 根据分组名称解析xml文件,获得该分组下数据字典项集 * @param gName String * @return DataDictionaryItems 数据字典项分组对象 */ 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); //设置分组名称编码 dataItems.setGroupName(GroupName); dataItems.setGroupCode(GroupValue); //取组内数据字典项 if (gName.equals(GroupName)) { //取数据字典项名称编码 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; } 第四步,提供数据字典项编码转换方法类: public class DataDictionaryUtils { public DataDictionaryUtils() { } /** * 根据数据项名称转换为数据项编码 * @param groupName String * @param itemName String * @return String 数据项编码 */ 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; } /** * 根据数据项编码转换为数据项名称 * @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; } 至此,我们已经完成了该方案的设计。使用xml文件,增加删除数据字典项等只需要更新xml文件即可,不涉及java文件的更新。 Xml可以根据应用的具体需要进行扩展设计。这里仅仅抛砖引玉,提供一种思路。 三、使用数据库表 上一种方法我们使用xml文件定义数据字典项,现在我们把数据字典项定义在数据库表中,下面我们来详细介绍实现方式: 第一步:定义数据字典项数据表结构 根据前面xml文件定义,这里我们定义两张表,一张是数据字典分组信息表,一张是数据字典项详细信息表。如下: 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); 这两张表可以根据应用的具体需求进行扩充,这里不再赘述。 第二步:根据定义的数据字典表结构定义数据字典实体类。 (请参照二、在xml文件中定义的第二步) 第三步:实现数据库表中数据字典项的查询功能 /** * 实现从数据库查询数据字典项 * @param gName String * @return DataDictionaryItems */ public static DataDictionaryItems getFromDB(String gName) { dataItems = new DataDictionaryItems(); try { //获取数据连接 java.sql.Connection conn = getConnection(); if(conn != null) { //查询数据库,根据组名称查询组编号,根据组编号获取该组内数据字典项信息 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; } 第四步:提供数据字典项编码转换方法类: (请参照二、在xml文件中定义的第四步) 四、进一步完善 1、两种方式都可以提供数据字典项维护界面,直接在维护界面上操作数据字典项,避免由于误操作导致xml文件或数据库数据错误。具体的实现也是比较简单,不再详细说明。 2、 使用数据库表方式时,如果想减少频繁查询数据库,可以将数据字典项信息在系统启动后第一次访问时加载内存中,如果数据字典项数据量比较大,可实现一自维护 线程,采用最近最少使用算法,将频繁使用的数据字典项驻留内存,将长期不用的数据字典项从内存中删除,每次自动检查内存中的数据字典项,如果存在则从内存 中读取,如果不存在则查询数据库,替换内存中最少使用的数据字典项。 3、增加运行日志记录,可以使用log4J来记录运行日志 |
|