资源描述
通用DAO
开发手册
文档历史
日期
作者
版本
注释
目 录
1. 概述 4
2. DAO框架 4
2.1 配置文件 5
2.1.1 配置文件说明 5
2.1.2 配置文件解析 7
2.2 数据访问 10
2.3 CommDao 11
2.4 异常类 13
3. 实现 14
3.1 JAVA文件 14
3.2 配置文件 14
4. 使用 15
4.1 Xml的使用 15
4.2 前台的使用 17
4.3 后台的使用 18
4.4 权限控制 22
4.5 日志输出 22
4.6 FAQ 23
1. 概述
在每一个具体项目中都有大量对数据库表的操作,例如对某个表的增加、修改、删除等。这样的操作对系统所有的表几乎都有要求。而无论采用那一种后台处理方式(ENTITY BEANS、JDO、DAO),都会有很大的重复性劳动。另外一个常用功能是,需要为每张表写很多查询(根据不同的参数)。ENTITY BEANS(CMP)可能在这两个方面做的很好,但是他是以牺牲系统资源和降低系统性能为代价换来的。
各种方式都个有所长,从各个项目经验中,STALESS SESSION BEANS + DAO是实现后台实体操作的最佳方式。
为此设计通用DAO,将数据库操作封装在DAO中,解决上述问题。
2. DAO框架
DAO在1.00版本上形成了dao的开发框架,且经过不少的项目运行,验证性能、使用等都反映良好,为了更好的适应厦门地税,在V1.00基础上,做了以下改进:
1. 将数据库访问的sql全部移到xml的配置文件上,以方便调整和优化访问数据库的sql
2. 增加对权限的支持
3. 增加对模糊查询的支持
4. 结合log4j,实现灵活控制执行sql的打印
5. 加入对PL/SQL访问的支持
6. 加入了对多个xml文件的支持
7. 加入了对xml文件解析的校验
8. 加入对查询记录数据条数的控制
9. 加入一个dao的配置文件dao-config.properties
10. 加入对批量数据处理,分次提交的算法
11. 加入Model继承一层的功能
12. 加入一个不用session的数据分页标签,使DAO只返回指定页的数据
通用DAO主要包括三部分,DAO配置文件、数据访问、CommDao。
2.1 配置文件
2.1.1 配置文件说明
通用DAO包含多个配置文件dao-config.xml,这个整个DAO的核心,需要在开发系统时逐渐完善该文件。dao-config.xml的DTD说明:
<?xml version="1.0" encoding="GB2312" ?>
<!ELEMENT daoModels (model*) remark CDATA #REQUIRED >
<!ELEMENT model (table, fields,primaryKeys?,uniques?,sync?, querys?,updates?,deletes?,insert? ,procedures?, extends,remark CDATA # REQUIRED) >
<!ATTLIST model
name CDATA #REQUIRED>
<!ELEMENT table (#PCDATA)>
<!ELEMENT fields (field*)>
<!ELEMENT field (#PCDATA)>
<!ATTLIST field
name CDATA #REQUIRED
tabField CDATA "">
<!ELEMENT querys (query*)>
<!ELEMENT query (#PCDATA)>
<!ATTLIST query
methodName CDATA #REQUIRED >
<!ELEMENT updates (update*)>
<!ELEMENT update (#PCDATA)>
<!ATTLIST update
methodName CDATA #REQUIRED >
<!ELEMENT deletes (delete*)>
<!ELEMENT delete (#PCDATA)>
<!ATTLIST delete
methodName CDATA #REQUIRED >
<!ELEMENT inserts (insert*)>
<!ELEMENT insert(#PCDATA)>
<!ATTLIST insert
methodName CDATA #REQUIRED >
<!ELEMENT procedures (procedure*)>
<!ELEMENT procedures(#PCDATA)>
<!ATTLIST procedure
methodName CDATA #REQUIRED >
<!ELEMENT primaryKeys (primaryKey*)>
<!ELEMENT primaryKey (#PCDATA)>
<!ATTLIST primaryKey
tabField CDATA #REQUIRED>
<!ELEMENT uniques (unique*)>
<!ELEMENT unique (#PCDATA)>
<!ATTLIST unique
tabField CDATA #REQUIRED>
<!ELEMENT sync (#PCDATA)>
<!ATTLIST sync
dataType (timestamp|string) "timestamp"
tabField CDATA #REQUIRED>
说明如下:
1. <ebisModels>是XML文件的根节点。下面包含多个<model>节点,每个<model>节点对应一个数据访问对象(ValueObject)。Name是数据访问对象(ValueObject)引用名称。
2. <model>节点包含<table>、<fields>、<primaryKeys>、<uniques>、<sync>、<querys>、<updates>、<deletes>、<inserts>、<procedures>十个节点。该节点定义了具体的访问数据库实体的相关信息。
3. <table>节点定义了数据库表的名称。
4. <fields>节点定义了数据库表的字段名称。该节点包含name、tabField、type三个属性。Name属性字段的引用名称,TabField属性是数据库的字段名称,Type属性是字段的类型,取值范围及含义如下表:
取值
含义
说明
0
数据库字段
默认字段为此类型
1
保留
目前未用
2
非数据库字段
该字段不参与insert、update操作
5. <querys>节点定义该表的查询方法,在dao-config.xml中可以定义多个查询方法,类是于ENTITY BEANS的HOME接口中的FIND方法。可以将查询条件定义在dao-config.xml中。输入参数用?号表示,在调用查询方法时输入参数顺序要和定义的参数顺序相同。其中,”<<””>>”内的内容为模糊查询部分,“{{””}}”内容为数据权限部分的字段,例如<< id = ? >>,当该字段传入值为空时,该条件不起作用。{{swjg_dm}},当传入的数据数据分区为’001001’,’001202’,’100012’时,组织的sql支持数据权限的sql是:(swjg_dm like ‘001001%’ or swjg_dm like ‘001202%’ swjg_dm like ‘100012%’)
6. <updates>节点定义该表的update方法,在dao-config.xml中可以定义多个update方法,可以将update定义在dao-config.xml中。输入参数用?号表示,在调用更新方法时输入参数顺序要和定义的参数顺序相同。
7. <deletees>节点定义该表的delete方法,在dao-config.xml中可以定义多个delete方法,可以将delete定义在dao-config.xml中。输入参数用?号表示,在调用更新方法时输入参数顺序要和定义的参数顺序相同。
8. <inserts>节点定义该表的insert方法,在dao-config.xml中可以定义多个insert方法,可以将insert定义在dao-config.xml中。输入参数用?号表示,在调用insert方法时输入参数顺序要和定义的参数顺序相同。
9. < procedures>节点定义该表的pl/sql方法,在dao-config.xml中可以定义多个pl/sql方法,可以将定义在dao-config.xml中。输入参数用?号表示,在调用pl/sql方法时输入参数顺序要和定义的参数顺序相同。
10. <primaryKeys>节点定义数据库表中的主键。允许是联合主键。
11. <uniques>节点定义数据库表中字段的唯一性检查。允许定义多个。
12. <sync>节点定义该表是否要求做同步检查。要求做同步检查的表必须要有一个做数据同步的字段,并且数据类型为Timestamp或String,缺省是Timestamp。如果定义了要求表同步操作,当系统提交更新操作之前被其他人已做过更新,系统将给出提示。目前,在社保的核心系统中还没有把这部分考虑进去。
2.1.2 配置文件解析
配置文件解析部分共有五个对象,这些对象是通用DAO内部使用对象,建议在业务程序不要直接使用这些对象。
下面是各对象的关系:
2.2 数据访问
对象的关系:
· DBAccessor对象负责保存数据连接DBReader对象和DBWriter对象。
· DBReader对象负责从数据库中获取数据信息。提供了分页处理,目前只支持ORACLE。
· DBWriter对象负责向数据库写入数据信息。
2.3 CommDao
CommDao部分,包括CommDao、BaseDAO、ObjectValue。这些对象是通用DAO对外接口,可以直接使用这些类,完成操作。
· CommDao对象是通用DAO的核心。他提供了丰富的API提供数据访问。该类可以通过不同数据访问对象(ObjectValue对象的子类)作为参数,调用CommDao的同一方法即可实现对不同表的操作。因为,在数据访问对象(ObjectValue对象的子类)中已经包含了数据库表的相关信息,通过调用CommDao对象增加、删除、修改方法实现数据库操作。
· BaseDAO对象实现数据访问的基本方法。
· ObjectValue对象是所有应用中数据访问对象的基类。同时他是ContentModel对象的子类。
2.4 异常类
异常类是DAO操作失败时抛出的错误信息,不同的异常标识了不同的含义。类图如下:
· FinderException当查询主键不存在或没有查询结果时,抛出该异常。
· DoublePrimaryKeyException当向数据库增加数据时,如果主键重复将抛出该异常。
· NotUniqueException当唯一键重复时,抛出该异常。
· SynchronizationException当发生同步错误时,抛出该异常。
· MethodNotFoundException当调用的查询方法没有定义在dao-config.xml时,抛出该异常
· OverQryRowsException 查询条数超过系统设置的最大值的异常
· ConfigException,dao系统配置异常
3. 实现
3.1 JAVA文件
作业调度服务在mons.dao包下,下面讲述每个包的含义:
· db:定义了数据库访问的管理方法,包括读数据和写数据。
· tablemodel:Dao的模型,定义了访问对象的结构。
· taglib:一个不依赖session的通用分页标签实现。
· xml:GenXml工具的实现类。
· util:常用工具类,包括常量类,StringUitl,数据权限接口等。
3.2 配置文件
配置文件包括放在classpath下的dao-config.properties文件,其内容如下:
配置文件:
#1、文件放的目录,同时这个也成为dao的命名空间,多个文件之间用英文件逗号(,)分开。
xmlpaths=/test-remark-dao-config.xml,/dao-config.xml
#2、默认最大的查询条数
qrymaxrows=1000
#3、默认批量操作提交的条数
batchcommitrows=1000
#4、运行模式:development(开发模式,支持xml的动态装载,方便开发,但频繁装载xml影响系统效率),product(运行,不支持xml的动态装载)
runmode=development
4. 使用
4.1 Xml的使用
1. 通过GenXml工具生成xml
2. xml文件命名规范:建议以以下形式命名数据库定义文件:dao-config-XXX.xml,其中XXX表示模块名,sql定义文件命名如下:dao-config-XXX-ext.xml,其中XXX表示模块名。
3. 需要自定义sql方法的,再用ext-dao-config.xml做模板建立一个xml文件,增加自己的方法。
4. 需要继承model的,加入:extends=“model1;model2”,多个父model中间用”;”隔开;如果继承的父model和子model名称一样,将把两个model合并,如果继承的父model和子model的名称不一样,仅仅合并model的fields。
5. 根据需要书写自己的sql方法,加入remark内容。
6. 对于查询方法,支持”<<条件>>”的写法,表示条件仅在有输入值传入时起作用。
7. 支持”{{数据分区字段1;数据分区字段2}}”的写法,表示数据分区1和数据分区2是数据分区的分区字段,将根据这两个字段和调用该SQL时传入的用户对象中的权限分区集合,生成带有数据权限的sql。
dao-config.xml示例:
<?xml version="1.0" encoding="GB2312" ?>
<webSiteModels remark="这是网站系统数据访问的集合">
<model name="SysParamModel" remark="这是表SysParamModel的访问集合 ">
<table>sys_param</table>
<fields>
<field name="id" tabField="id"/>
<field name="name" tabField="name"/>
<field name="value" tabField="value"/>
<field name="display" tabField="display"/>
<field name="visible" tabField="visible"/>
<field name="editable" tabField="editable"/>
<field name="updatedBy" tabField="updated_by"/>
<field name="updatedDate" tabField="updated_date"/>
</fields>
<primaryKeys>
<primaryKey tabField="id"/>
</primaryKeys>
<uniques>
<unique tabField="name"/>
</uniques>
<sync tabField="updated_date" dataType="timestamp"/>
<querys>
<query methodName="findByid"
remark=" 这是根据ID查询sys_param的方法">
<sql><![CDATA[ select id ,name,value from sys_param
where <<id = ? >> and << name = ? >>
and {{a.sqjg_dm , b.swjg_dm}}
]]></sql>
</query>
</querys>
<updates>
<update methodName="updateByName" >
<sql><![CDATA[ update sys_param set value = ?
where name = ?
]]></sql>
</update>
</updates>
<deletes>
<delete methodName="updateByName" >
<sql><![CDATA[ delete from sys_param where name = ? ]]></sql>
</ delete >
</deletes>
<inserts>
<insert methodName="findByCsjllxDm" >
<sql><![CDATA[ insert into sys_param(id , name ) values(?,?) ]]></sql>
</insert>
</inserts>
<procedures>
<procedure methodName="findByCsjllxDm" >
<sql><![CDATA[ procedure 的sql ]]></sql>
</procedure>
</procedures>
</model>
</model>
<model name="LocationModel" remark=”这是对sys_param,dwxx表的访问方法集合”>
<table> sys_param,dwxx</table>
<fields>
<field name="id" tabField="id"/>
<field name="name" tabField="name"/>
<field name="description" tabField="description"/>
<field name="locationType" tabField="B.name"/>
<field name="parentName" tabField="C.name"/>
<field name="locationTypeId" tabField="location_type_id"/>
<field name="parentId" tabField="parent_id"/>
<field name="deleted" tabField="deleted"/>
<field name="createdBy" tabField="created_by"/>
<field name="createdDate" tabField="created_date"/>
<field name="updatedBy" tabField="updated_by"/>
<field name="updatedDate" tabField="updated_date"/>
</fields>
<querys>
<query methodName="findByid"
remark=" 这是根据ID和name模糊查询sys_param和dwxx的方法">
<sql><![CDATA[ select a.id ,a.name,b.value
from sys_param a , dwxx b
where <<a.id = ? >> and << a.name = ? >>
and {{a.sqjg_dm , b.swjg_dm}}
]]></sql>
</query>
</querys>
</model>
</webSiteModels>
4.2 前台的使用
l form中定义ValueObject作为属性,例如:ValueObject vo = new ValueObject(“Test_dao“);
下面是Jsp中的用法:
l 如果字段为String、double、int,写法为:vo.string(COL1);
l 如果为”yyyy”的日期型数据,写法为:vo.dateyyyy(COL2);
l 如果为”yyyy-MM”的日期型写法为:vo.dateyyyyMM(COL3);
l 如果为”yyyy-MM-dd”的日期型写法为:vo.dateyyyyMMdd(COL4);
l 如果为“yyyy-MM-dd hh:mm:ss”的日期型写法为:vo.date (COL5);
4.3 后台的使用
l 详细的类方法,参见javadoc,以下列出了在开发中会使用的类
l 操作保存数据对象ValueObject方法统一在ValueObject中,其中:
n 对String,double、int、long的付值直接使用setString和getString方法;
n 对date的访问使用setDate、setDateyyyyMM、setDateyyyyMMdd、setDate、setPatternDateStr等方法
l 访问数据库的方法统一在Commdao中,该类在构建时需要将数据库链接作为参数传入,事务由外部控制。具体方法参见以下说明:
访问数据库类型
是否支持权限操作
是否支持仅在有输入参数时才作为条件,否则忽略条件
方法返回值
方法
查询表
否
否
RowSet
RowSet commSearch(String sql, List values) 查询数据库的记录
通用DAO提供访问数据库的一般方法,当sql不能在xml中定义时,直接在外部写SQL语句
更新表(包括增、删、改)
int
int commUpdate(String sql, List values)
更新数据库的记录
通用DAO提供访问数据库的一般方法,当sql不能在xml中定义时,直接在外部写SQL语句
删除表
否
否
Boolean 是否成功 仅当更新的条数和valueObjectList的size相等时为true
deleteBatchByPk(java.util.ArrayList valueObjectList)
批量删除valueobject的ArrayList
删除表
否
否
int[]
deleteBatchByPk(java.util.ArrayList valueObjectList, int onceCommitSizes)
批量删除valueobject的ArrayList,该删除方法将按照系统配置的一次提交的条数来提交
删除表
否
否
int
deleteByMethod(java.lang.String modelName, java.lang.String deleteMethodName, java.util.List paramentValue)
根据model名称和方法名,将paramentValue 更新到需要delete的字段
删除表
否
否
boolean
deleteByPk(ValueObject valueObject)
根据主键delete valueobject中的字段,valueobject中的主键必须存在
查询表
否
否
java.util.ArrayList
find(ValueObject valueObject)
根据指定值对象查询某个表,该对象中如果字段有赋值,该字段就做为查询条件
查询表
是
是
java.util.ArrayList
findByMethod(ValueObject valueObject, java.lang.String queryMethodName, java.util.List paramentValue)
根据dao配置的查询方法查询对象,生成Valueobject的ArrayList,返回的记录条数不能超过系统定义的参数
查询表
是
是
java.util.ArrayList
findByMethodAndRows(ValueObject valueObject, java.lang.String queryMethodName, java.util.List paramentValue, int maxRows)
根据dao配置的查询方法查询对象,生成Valueobject的ArrayList,返回的记录条数不能超过该方法传的参数
查询表
否
否
ValueObject
findByPk(ValueObject valueObject)
根据ValueObject的主键查出该对象,返回该主键对应的ValueObject
通过该方法可以查看到解析xml的model结果
N/A
N/A
static TableModel
getTableModel(java.lang.String modelName)
根据model 名称返回model
查询表
是
是
java.util.ArrayList
grantedFindByMethod(ValueObject valueObject, java.lang.String queryMethodName, java.util.List paramentValue, DataGrant dataGrant)
根据dao配置的查询方法查询对象,生成Valueobject的ArrayList,返回的记录条数不能超过系统定义的参数
查询表
是
是
java.util.ArrayList
grantedFindByMethodAndRows(ValueObject valueObject, java.lang.String queryMethodName, java.util.List paramentValue, int maxRows, DataGrant dataGrant)
根据dao配置的查询方法查询对象,生成Valueobject的ArrayList,返回的记录条数不能超过该方法传的参数
插入表
否
否
boolean
insert(ValueObject valueObject)
根据主键insert valueobject中的字段,valueobject中的主键必须存在
插入表
否
否
Boolean 是否成功 仅当更新的条数和valueObjectList的size相等时为true
insertBatch(java.util.ArrayList valueObjectList)
批量插入valueobject的ArrayList, 该插入方法将用系统设置的一次提交的条数来提交
插入表
否
否
int[]
insertBatch(java.util.ArrayList valueObjectList, int onceCommitSizes)
批量插入valueobject的ArrayList, 该插入方法将OnceCommitSizes设置的一次提交的条数来提交
插入表
否
否
int
insertByMethod(java.lang.String modelName, java.lang.String insertMethodName, java.util.List paramentValue)
根据model名称和方法名,将paramentValue 更新到需要insert的字段
存储过程
否
否
void
procedureNoOutByMethod(java.lang.String modelName, java.lang.String procedureMethodName, java.util.List paramentValue)
根据model名称和方法名,将paramentValue 传给sql
存储过程
否
否
java.util.ArrayList
procedureOfResultByMethod(java.lang.String modelName, java.lang.String procedureMethodName, java.util.List paramentValue)
根据model名称和方法名,将paramentValue 传给sql
该方法不再使用
N/A
N/A
void
setDebugLevel(int debugLevel)
Deprecated.
更新表
否
否
Boolean 是否成功 仅当更新的条数和valueObjectList的size相等时为true
updateBatchByPk(java.util.ArrayList valueObjectList, boolean updateValuesIgnoreNull)
批量更新valueobject的ArrayList,如果updateValuesIgnoreNull为true,将忽略对null的更新
更新表
否
否
int[]
updateBatchByPk(java.util.ArrayList valueObjectList, int onceCommitSizes, boolean updateIgnoreNull)
批量更新valueobject的ArrayList,
更新表
否
否
int
updateByMethod(java.lang.String modelName, java.lang.String updateMethodName, java.util.List paramentValue)
根据model名称和方法名,将paramentValue 更新到需要update的字段
更新表
否
否
boolean
updateByPk(ValueObject valueObject, boolean updateIgnoreNull)
根据主键update valueobject中的字段,valueobject中的主键必须存在
4.4 权限控制
系统数据权限的控制是体现在DAO中,DAO控制数据权限的方式通过在SQL中支持“{{数据分区字段1;数据分区字段2}}”的写法,表示“数据分区1”和“数据分区2”是数据分区的分区字段,将根据这两个字段和调用该SQL时传入的用户对象中的权限分区集合,生成带有数据权限的SQL。
如果该SQL不需要控制数据权限就不需要在SQL中用以上写法。
4.5 日志输出
通过log4j,给CommDao和调用dao的级别设置为debug,当调用commdao时即可看到一个log4j输出commdao的信息,一个例子为:
2004-11-04 11:39:10 DEBUG (CommDao.java:1390) - dao message is :
call dao location is :
TestCommDao.java:261:testGrantedFindByMethodAndRows() (调用dao的类的和方法的位置)
execute model name is : TEST_DAO ;(执行的model的名称)
execute sql is : select COL1 , COL2 from TEST_DAO where COL6 = '1' (执行的sql语句)
execute time cost is : 6s(当执行成功,执行花费的时间)
WARN : sql need optimize !(当执行时间超过5秒,显示警告信息,执行的sql需要优化 )
4.6 FAQ
1. 如何书写正确的xml
用工具生成访问单表的基本的xml,然后手工书写扩展的xml,可以通过以下方法检验xml的正确性
l 看运行时后台的异常堆栈信息,会报告错误的情况
l 用ie打开xml,看解析是否通过
l 检查model和各种自定义的访问数据库的方法是否加入了remark
2. 如何使用多表查询
例如:select a.col1 as col1 , b.col1 as col2 from table1 a , table2 b where a.col2 = b.col2 and a.col3 = ?
同时在model的field中,写出col1和col2,不能写成 a.col1,b.col1
3. 如何使model仅作为保存数据的类,不用于访问数据库
在xnml中与数据库有关的内容不需要配置即可
4. 如
展开阅读全文