OpenHandX-real 是 一个小巧的JDBC轻量级封装的工具包,其最核心的特性是查询结果集、以及增、删、改的封装。可以直接将查询出来的结果集封装成JavaBean、编辑表 数据时自动匹配字段和数据类型,这就为开发者做了最枯燥乏味、最容易出错的工作。还提供了spring的支持,由spring统一管理数据库事务。除此之 外还提供一些常用应用工具类,如:树型结构类、枚举常量类、业务日志类、系统信息类、业务编号类。
首先主流ORM是一种比较优秀的框架,随着面向对象的软件开发 方法发展而产生的,通过使用描述对象 和数据库之间映射的元数据 ,将java程序 中的对象自动持久化到关系数据库中,ORM实际上是对象-关系映射 。
ORM 优势:
1 、隐藏了数据访问细节,“封闭”的通用数据库交互,ORM的核心。他使得开发者的通用数据库交互变得简单易行,并且完全不用考虑SQL语句;
2 、 ORM使开发者构造固化数据结构变得简单易行。在ORM年表的史前时代,开发者需要将对象模型转化为一条一条的SQL语句,通过直连或是DB helper在关系数据库构造开发者的数据库体系。而现在,基本上所有的ORM框架都提供了通过对象模型构造关系数据库结构的功能。
ORM 缺点:
1 、自动化映射和关联管理,是牺牲性能代价,虽然有延迟加载技术,也存在N+1的困扰,并且延迟加载不能跨越到分布式部署的web层等问题;
2 、虽然隐藏了数据层面的业务抽象,但并不能完全的屏蔽掉数据库层的设计,并且无疑将增加学习成本;
3 、对于复杂查询,ORM仍然力不从心。虽然可以实现,但是不值的。
OpenHandX-real 是在ORM优缺点中找一个平衡点,通过使用统一数据对象 与数据库数据之间自动转换,将统一数据对象 非常容易地持久化到关系数据库中。OpenHandX-real也有两大优点:
1 、 增、删、改操作的SQL本身不复杂,而且SQL性能没有什么可优化的余地,即使优化也是关系数据库本身索引和合理性。所以对于增、删、改的操 作,OpenHandX-Real自动完成SQL和数据的组装并执行,开发者不用写SQL和操作PreparedStatement;
2 、 相反对于查询操作,随着信息技术的不断发展,要求越来越高,多表关联查询,翻页查询,性能优化的程度很大。因此对于查询OpenHandX-Real直接 通过SQL操作,由开发者自行决定SQL或数据库的优化,因此可以他的性能完全可以做到最优。对于查询结果集的返回由OpenHandX-Real工具自 动完成,将开发成本降到最低;
OpenHandX-real 的目的不是取代ORM框架,而是ORM框架的补充。为那些追求良好的性能、数据库设计经验丰富的人提供有力的支持。
OpenHandX-Real 1.0 需要 :
l Java 5
l open-common
l commons-lang-2.1
l commons-beanutils-1.7
l commons-logging-1.0.4
l spring2.0 以上及相关(可选)
l db-derby-10.5.3.0 (可选)
l 数据对象 : OpenHandX-common 提供的单条数据存储对象RecordVO、多条数据存储对象RecordSetVO、PersistenceRecordSetVO、复合数据存储对象MulripleVO
l SQL 生成和数据的组装 - 自动生成增、删、改操作的SQL和数据的组装, 使数据库开发变得简单易行;
l 查询结果集封装和持续优化的执行效率 - 允许开发者自己写查询SQL,SQL的效率完全控制在开发者手里,并能根据实际情况持续优化;
l 结果集的数据加工功能 - 结果集返回是RecordSetVO对象, RecordSetVO对象本身具有排序、分组、检索、统计、不重复值等功能
l 海量数据的支持 - 集成了OpenHandX-common特有持久PersistenceRecordSetVO对象,能一次从数据库中取出所有数据(只要应用服务器硬盘的剩余空间足够大),取出这些海量数据不占当前应用服务器的内存;
l JDBC 支持 - 由开发者自己管控数据库连接、事务,充分发挥开发者的想象力,提供开发者的高自由度,剩下繁琐的工作就由 OpenHandX-real 完成;
l SPRING 支持 - OpenHandX-real 与Spring做了无缝的集成,由spring管理DAO和Service类、数据库连接池、数据库事务;
l XML 的 SQLMAP 支持 - OpenHandX-real 提供轻巧的SQL管理功能,允许开发者将SQL保存在XML配置文件中,便于统一规范和管理;
l SQL 字段映射 - 很多时候依靠OpenHandX-real自动字段匹配功能不能完成的工作时,如:数据对象多个字段对应数据库中同一个字段时需要通过字段映射强制指定
l 常用工具类 -OpenHandX-real 提供了树型结构类、常量类、业务日志类、系统信息类、业务编号类的DAO和Service的实现类,也分别提供了JDBC和spring的实现
要用好OpenHandX-real首先要学会OpenHandX-common的数据对象,这方面资料请查看《OpenHandX-Common》的数据模型 章节。
OpenHandX-real JDBC 支 持类在open.real.jdbc下,分别提供了DeleteSupport数据删除支持类、InsertSupport数据新增支持类、 UpdateSupport数据更新支持类、QuerySupport数据查询支持类、任意SQL执行支持类ExecuteSupport。
public static int delete (Connection cnn,String tableName,String condKey,Object value) 删除符合一个条件的数据,经常用于删除单主键的数据 |
public static int delete(Connection cnn,String tableName,RecordVO vo) 删除符合一条条件的数据,经常用于删除复合主键的数据 |
public static int delete (Connection cnn,String tableName,IRecordSetVO vo) 删除符合多条条件的数据,经常用于多条数据 |
public static int insert(Connection cnn,String tableName,RecordVO vo) 插入一条数据 |
public static int insert (Connection cnn,String tableName,IRecordSetVO vo) 插入多条数据 |
public static int update (Connection cnn,String tableName,IRecordSetVO rsvo,String... condNames) 修改多条数据,只更新rsvo里的字段,其他字段不更新,rsvo中与condNames的同名字段为条件值 |
public static int update (Connection cnn,String tableName,RecordVO vo,RecordVO cond) 更新一条数据,只更新vo里的字段,其他字段不更新,vo包含要更新的值,cond为条件值 |
public static int update (Connection cnn,String tableName,RecordVO vo,String... condNames) 更新一条数据,只更新vo里的字段,其他字段不更新,vo中与condNames的同名字段为条件值 |
public static int updateAllField(Connection cnn,String tableName,IRecordSetVO rsvo,String... condNames) 修改多条数据,只更新rsvo里的字段,其他字段设置为null,rsvo中与condNames的同名字段为条件值 |
public static int updateAllField (Connection cnn,String tableName,RecordVO vo,RecordVO cond) 更新一条数据,只更新vo里的字段,其他字段设置为null,vo包含要更新的值,cond为条件值 |
public static int updateAllField (Connection cnn,String tableName,RecordVO vo,String... condNames) 更新一条数据,只更新vo里的字段,其他字段设置为null,vo中与condNames的同名字段为条件值 |
public static int execute (Connection cnn,String sql) 执行一条sql |
public static int execute (Connection cnn,String... sqls) 执行多条sql |
public static RecordVO find (Connection cnn,String sql) 执行sql得到结果,并读取第一条数据 |
public static Long findForLong (Connection cnn,String countSql) 查询一个整数值,要求第一个字段必须为整数,经常用于查询数据库数据总数 |
public static MulripleVO pageQuery 根据SQL做翻页查询,返回MulripleVO,其中RecordVO为统计信息,IRecordSetVO为数据 |
public static RecordSetVO query 执行sql得到结果,并读取所有数据 |
public static PersistenceRecordSetVO queryPersistenc e 执行sql得到结果,并读取所有数据,海量数据查询方法 |
SqlMapSupport 将SQLMAP和SQL字段映射结合在一起,SqlMapSupport传入的参数不在是SQL本身,而是SQLMAP的SQL-id。具体参考后面的章节
1 、 DeleteSupport、InsertSupport、UpdateSupport字段的匹配原则:OpenHandX-real将数据对象里的字段 与tableName表名中一致的字段进行匹配,自动生成SQL并操作PreparedStatement赋值,最后执行SQL
2 、 DeleteSupport、InsertSupport、UpdateSupport、ExecuteSupport提供了setBatchCache 静态方法,该方法用于删除、修改、更新、执行多条SQL的批量提交SQL数量(默认为10),开发者可以根据数据库的实际情况自己设定。
DeleteSupport 、 InsertSupport、UpdateSupport的字段匹配使用了jdbc的ResultSetMetaData类,如果每次匹配都先查询表结构 会影响性能,open.real.core.RealTableMetaData本身可以缓存表结构,方法为setCacheTableMeta静态方法 (默认为不缓存)
依靠OpenHandX-real自动字段匹配功能不能完成的工作时,或者数据对象与表中字段名不匹配时需要使用SQL字段映射
SQL 字段映射是完成sql中宏变量与数据对象字段的对应,生成新的SQL。宏的格式为:#字段名#
SqlAlludeExecuteSupport 类提供数据维护类的方法
SqlAlludeQuerySupport 类提供数据查询类的方法
具体使用如下:
String sql= ”update TABLE1 set f2=#f2# where f1=#f1# ”; RecordVO vo 为 f1= ” 0001 ” ,f2= ” test ” int[] types 为{ java.sql.Types.VARCHAR, java.sql.Types.VARCHAR} SqlAlludeExecuteSupport. execute(cnn, sql, vo, types) 组装成 SQL为 update TABLE1 set f2=? where f1=? 并以PreparedStatement的st.setString(1,"test");st.setString(1,"0001"); 其中#f2#对应到vo的f2字段,#f1#对应到vo的f1字段 |
也可以 update TABLE1 set ID=#CODE1# where ID=#CODE2# ,用于修改主键
Types 参数可以为{ java.sql.Types.VARCHAR, java.sql.Types.VARCHAR} ,也可以为{1,1}
允许开发者将SQL保存在XML配置文件中,便于统一规范和管理。同时支持多个XML的SQLMAP文件。
SQLMAP 文件格式如下:
< config nameSpace = " 命名空间 " > < file name = " 其他 SQLMAP 文件及路径 " /> … < sql id = " 唯一编号 " sql = "sql 语句 " type = " 如果有字段映射请指定数据类型 " /> … </ config > |
例如:
<? xml version = "1.0" encoding = "UTF-8" ?> < config nameSpace = "space001" > < file name = "sqlmap1.xml" /> < sql id = "sql001" sql = "select * from TestTable" /> < sql id = "sql002" sql = "update TestTable set TS_INT=TS_INT" /> < sql id = "sql003" sql = "update TestTable set TS_INT=#TS_INT# and TS_LONG=#TS_LONG#" type = "4,5" /> </ config > |
注意:
1 、命名空间不是必须的;
2 、同一个命名空间下sql id不能重复;
3 、同一个SQLMAP文件可以指定多个file(其他SQLMAP文件及路径);
4 、其中type格式为: 数据类型1, 数据类型2, 数据类型3…,数据类型可以为数字,也可以为常量名( java.sql.Types 的常量名 )。如:"4,5"可以写为"INTEGER,SMALLINT"
使用SqlMapManager类对配置文件进行管理。
JDBC 方式如下:
第一步:给SqlMapManager设置SQLMAP的文件的路径,调用SqlMapManager. setRootPath方法 第二步:调用SqlMapManager.init方法初始化 |
例如: SqlMapManager.setRootPath ( "D:/OpenHandX/real/real/config" ); SqlMapManager.init (); |
Spring 方式如下:
在applicationContext.xml文件里配置好路径和初始化方法 |
例如: < bean id = "sqlMapConfigManager" class = "open.real.sqlmap.SqlMapManager" init-method = "init" > < property name = "path" value = "classpath:" /> </ bean > |
以上方法只要初始化一次即可,后面就有3种使用方法:
1 、直接使用SqlMapManager
取出SQL语句使用SqlMapManager.getSql方法
取出SQL的types使用SqlMapManager. getTypes方法
System. out .println(SqlMapManager.getSql ( "space002.sql003" )); System. out .println(SqlMapManager.getTypes ( "space001.sql004" )); |
由以上方法取出的SQL和types就可以调出相关的方法操作了
QuerySupport.query(Connection cnn, SqlMapManager.getSql ( "space002.sql001" )) SqlAlludeQuerySupport.query(cnn, SqlMapManager.getSql ( "space002.sql001" ), cond, SqlMapManager.getTypes ( "space002.sql001" )) |
2 、使用JDBC的SqlMapSupport类
3 、使用Spring的RealSqlMapTemplate模板类
OpenHandX-real SPRING 支持类在open.real.spring下,分别提供了RealTemplate基本支持类、RealSqlMapTemplate字段映射和SQLMAP支持类。用法很简单大家查考前面的6.1-6.3章节和相应的javadoc。
使用的时候只要继承RealTemplate或RealSqlMapTemplate类,掉父类相应的方法。
该工具类帮助开发者创建一个业务编号,比如:流水号、产品编号等。自动编号类需要在数据库创建一张表:
字段名 | 中文名 | 说明 |
TYPE | 自动编号类型 | 每个自动编号的主键,如:流水号为 1 、产品号为 2 |
EXP | 编号表达式 | 最终生成编号的模板 |
CURRNUM | 当前计数器 | 当前已生成第几个号 |
DES | 说明 | |
MINNUM | 最小计数器 | 当前计数器的允许最小值 |
MAXNUM | 最大计数器 | 当前计数器的允许最大值 |
STEP | 计数器步幅 | 每获取新编号 当前计数器时距上一个编号的当前计数器差距 |
CURRTIME | 当前时间 | 创建新编号时的时间 |
LEN | 计数器长度 | 允许计数器转化成字符串的长度 |
FILLCHAR | 填充字符 | 如果 LEN 大于 CURRNUM 的长度则用该,字符在前面补齐 |
AutoNumberService 方法如下:
public String getAutoNumber(Connection cnn,Integer type) 获取某个业务类型为type的一个编号 |
public List<String> getAutoNumber(Connection cnn,Integer type,int count) 获取某个业务类型为type的count个编号 |
public List<String> getAutoNumber(Connection cnn,Integer type,int count,RecordVO vo) 获取某个业务类型为type的一个编号,需要使用vo数据作为模板 |
public String getAutoNumber(Connection cnn,Integer type,RecordVO vo) 获取某个业务类型为type的count个编号,需要使用vo数据作为模板 |
例如:
在数据库里定义一个自动编号为: TYPE=1 ,EXP= "PRD{number}",LEN=10,FILLCHAR=0 如果此时CURRNUM为23, getAutoNumber ( cnn , 1 ) 获取后的编码为:PRD0000000024 |
在数据库里定义一个自动编号为: TYPE=1 ,EXP= " FB{prdCode}{number}",LEN=7,FILLCHAR=0 vo 的数据为prdCode="001" 如果此时CURRNUM为23, getAutoNumber ( cnn , 1,vo ) 获取后的编码为:FB0010000024 |
用于记录通常业务操作发生的时间、地点、事件,必要的时候可以记录操作人
字段名 | 中文名 | 说明 |
LOGCODE | 日志编号 | 主键 |
LOGTIME | 日志时间 | 生成业务日志时的时间 |
LOGTYPE | 信息类型 | 业务日志的类型 |
LOGTITLE | 信息标题 | 业务日志的简述 |
LOGMESSAGE | 日志信息 | 业务日志的内容 |
AutoNumberService 方法如下:
public int insertBusLog (Connection cnn,RecordVO vo) |
public int |