数据持久化能够提供获取和长久保存数据的能力, 采用合适的持久化技术构建性能良好、易于扩展和维护的持久化层是各类应用系统设计中必须考虑的重要问题之一. 在以Java EE技术为平台的应用中存在着两种主要的数据持久化解决方案: 一种以SQL技术为基础, 代表是JDBC和MyBatis框架[1,2]; 另一种是以对象/关系映射(ORM)技术为基础, 代表是Hibernate框架[3]. Hibernate是对JDBC的轻量级封装, 以面向对象的域模型为基础, 通过配置文件或注解自动实现POJO对象与数据库表的映射, 避免传统方式的建库、建表、设置主外键等关系操作[4]. 但是MyBatis和Hibernate都是在设计模式+Java反射机制基础上形成的第三方框架, 其学习成本较高, 对开发人员具有较高的素质要求, 尤其Hibernate框架如果使用不当, 在频繁访问数据库、并发量大的场景下, 会出现严重的性能问题. JDBC通过SQL语句直接操作数据库, 相对于ORM缺少了“翻译”过程, 经过精心设计与优化后, 具有较高的执行效率. 但是, 传统的JDBC也存在缺陷: 需要考虑数据库底层细节、业务逻辑与持久化逻辑高度耦合、相似持久化逻辑的代码冗余度较高、在出现网络故障的情况下, 需要人工重启Web容器来解决数据库连接对象失效等问题.
近年来已有不少学者针对上述问题进行了相关研究, 主要集中在JDBC基本理论、复用性、访问效率等方面. 文献[5,6]主要研究了JDBC访问数据库的一般算法和事务控制, 分析了JDBC与ODBC的区别. 文献[7]从策略模式和模板模式入手对JDBC进行了改进, 并以改进后的JDBC设计了某电信客户关系管理系统的数据持久层. 文献[8]针对JDBC中的Connection对象在网络环境异常情况下无法自动重连的问题, 利用循环检测方法提出一种Connection自动连接策略. 文献[9,10]从多方面研究了JDBC的缓存方案, 提高了数据库访问效率.
本文针对传统JDBC存在的不足, 在前人研究基础上, 综合应用单例模式、模板模式、策略模式、DAO模式、工厂模式和配置文件, 并在数据库驱动加载过程中引入重连机制, 在DAO工厂中增加缓存机制, 对JDBC进行了改进. 并以改进的JDBC框架为基础, 完成了某高校绩效考核管理系统持久层的设计与开发. 并为以JDBC作为数据持久化技术的Java EE应用系统的开发提供了一定的参考.
1 JDBC体系结构与核心APIJDBC是Java EE应用中用来访问关系型数据库的一组API. 主要包括: JDBC API、驱动管理器、JDBC驱动程序以及驱动程序的注册机制[11]. 其中, 开发人员使用JDBC API访问数据库; 数据库厂商提供JDBC驱动程序; 驱动管理器负责加载驱动程序, 在JDBC API和驱动程序之间形成一个中转, 允许JDBC API通过驱动程序来操作关系型数据库, 如图1所示.
JDBC API通过提供的几个核心接口供开发人员使用, 主要是Connection、Statement、PreparedStatemnt、CallableStatement和ResultSet. Connection代表应用程序与数据库之间的连接, 是创建其它JDBC接口的基础并处理数据库事务. Statement用于执行普通的SQL语句. PreparedStatement是Statement的子接口, 能够对SQL语句进行预编译并检查语法错误, 对于相同SQL语句的多次执行能够提高效率. CallableStatement是PreparedStatement的子接口, 用于执行数据库端的存储过程. ResultSet用来封装查询语句所返回的结果集, 并提供了对结果集进行遍历、访问和定位的相关方法. 上述各接口的使用步骤是: ① 通过反射机制加载驱动程序; ② 由DriverManager根据所访问数据库的URL、用户名和密码创建Connection对象; ③ 根据SQL语句所访问的对象, 由Connection创建不同的Statement对象; ④ 相关Statement对象负责执行具体的SQL语句, 并处理执行的结果; ⑤ 释放相关资源.
JDBC通过提供相关接口的方式, 有效地在执行过程中明确了责任, 屏蔽了各具体关系型数据库的差异, 降低了应用程序与数据库的耦合度. 由于持久化逻辑具有相似但又不完全相同的特点, 相似性表现在任何一个持久化操作都要经过上述的5个步骤; 不同性表现在具体执行的SQL语句和处理结果不同. 所以传统JDBC存在着一些缺陷: 不同实体对象的持久化操作具有很大的相似性, 如果不进行封装, 会导致代码冗余度高, 复用率低; 业务逻辑与持久化逻辑耦合度高, 存在一些不必要的重复性操作(例如驱动程序的多次加载等); 数据库的改变需要修改源代码, 包括数据库驱动获取、连接配置和SQL语句等部分, 违背了“开-闭”原则.
2 改进的JDBC框架 2.1 改进的JDBC架构设计本文针对传统JDBC框架存在的复用性低、耦合度高、不易移植等缺陷, 设计了改进的JDBC框架, 通过DAO模式向业务逻辑层提供调用持久化逻辑的接口, 解耦合业务逻辑与持久化逻辑; 利用模板、策略和工厂模式封装DAO的具体实现, 实现具体持久化代码的统一性并减少代码的冗余度; 利用XML+Property配置文件来描述数据库配置、DAO配置、SQL语句等信息, 实现代码的调优和解耦. 改进的JDBC框架如图2所示.
设计模式是在特定背景下, 解决某个问题的最佳实践, 具体表现为一组精心设计的接口与类的组合[12,13]. 在编码中应用设计模式能够确保可重用性、可靠性, 并易于被别人理解. 根据模式的目的, 一共分为: 创建型、结构型和行为型3类. 其中, 工厂模式属于创建型模式, 用于将对象的创建和使用相分离, 在该JDBC框架中用于生成DAO和具体策略对象. DAO模式作为业务逻组建访问数据持久层的入口, 屏蔽数据持久化的细节. 模板方法模式属于行为型, 用于定义一个操作步骤的骨架, 将其中可变的操作延迟到子类中完成. 在改进的JDBC框架中, 将执行SQL操作这个步骤延迟到子类完成. 策略模式属于行为型, 通常定义一个算法族, 由子类实现每个具体的算法并相互之间能够转换. 在改进的JDBC框架中, 将Connection对象的创建和资源释放这两个操作由策略模式实现, 其中一个具体策略是通过传统的DriverManager获取, 资源释放方式是销毁; 另一个具体策略是通过数据库连接池获取Connection, 资源释放是交回给连接池. 综合应用上述设计模式对JDBC框架进行改进, 可以把持久化操作中相似的功能进行封装, 进一步分离业务逻辑和持久化逻辑, 使业务逻辑层和持久化层的耦合度进一步降低, 提高代码复用率.
2.2 改进的JDBC架构的执行流程改进的JDBC框架的调用时序图如图3所示. 业务层组件通过DAOFactory和配置文件获取对应实体的DAO对象; DAO对象中创建JDBCTemplate对象, JDBCTemplate对象通过策略工厂对象得到JDBCStrategy对象, 在创建过程中需要策略接口和配置文件的帮助; 并且JDBCTemplate封装了JDBC操作的公共逻辑, 在JDBCStrategy对象的配合下完成对数据库的访问, 并将操作结果返回给业务层组件.
3 改进的JDBC框架的应用
以下给出改进的JDBC框架在高校绩效考核管理系统中的应用实例. 系统环境是Window Server 2012作为服务器, MyEclipse16.1是集成开发工具, 数据库服务器是MySQL5.7.
3.1 系统流程设计采用绩效考核系统对高校人员进行量化评价是采用信息化手段进行人力资源管理的一种变革, 能够使每位人员得到公正、公平的考评结果, 为提高教学质量、工作效率, 并为学校领导层提供正确的决策数据. 系统的考核对象主要分为: 教师系列、行政人员系列和工程实验技术人员系列. 以教师系列为例, 实际的考核流程如图4所示.
首先由各二级学院布置年度考核工作安排, 教师按照年度制定的目标责任书中的内容, 逐条将自己相关的内容录入系统. 然后各二级学院召开考核评议会, 由业务考评组根据考核内容进行量化打分, 按照统计分数进行排名并定性评价. 在此基础上划分优、良、合格和不合格比例. 考核小组在院系内公布考核结果, 如有异议, 教师在三日内到院系考核小组进行复审. 以院系为单位将教师考核相关汇总资料报送教务处和科技处, 最后由教务处将各院系考核材料报送学校考核工作委员会审核, 最终确定各教师本年度绩效考核成绩.
3.2 关键技术定义JDBCStrategy作为抽象策略接口, 包括获取连接和释放资源两个操作. DBPoolStrategy和DMStrategy是两个具体策略类. 在单元测试阶段使用DMStrategy策略, 因为它不需要Web容器的支持, 可以提高测试效率. DBPoolStrategy用在整体测试和项目运行阶段, 它以JNDI方式获取连接和回收资源[14]. 该策略需要在Web服务器中配置数据库连接池, 因为连接池方式能够对Connection进行复用, 避免反复创建和释放连接对象而造成的性能消耗. DMStrategy通过驱动管理者类获取连接和释放资源. 这两个策略类在获取连接对象时都加入了数据库重连机制. 以DMStrategy策略为例, 在一个while循环中通过DriverManager获取Connection. 如果发生异常就让当前线程对象休息一段时间后重新获取Connection对象, 直到获取成功就退出循环, 这样就可以避免重启Web服务器或应用程序所带来的麻烦.
具体策略类利用静态代码段加载JDBC驱动, 避免了传统方式中多次加载的弊端, 提高了执行效率. 数据库驱动名称、URL、用户名和密码等信息都写在了DBConfig.properties配置文件中, 数据库的变更不用修改具体策略类代码, 便于系统的移植. FileUtil类采用单例模式来实现, 用来把配置文件中的<K,V>键值信息保存到静态的Properties对象中, 便于在具体策略类和工厂类中共享.
JDBCStrategyFactory是策略工厂, 根据配置文件来创建不同的具体策略对象. 具体策略切换时, 只需要修改配置文件中的值,工厂类的代码不需任何改动; 当增加新的连接获取方式时, 只需要定义具体的策略类, 原有的代码不需要任何修改, 很好的满足了“开-闭”原则.
定义JDBCTemplate作为模板封装数据表通用的增、删、改、查方法, 利用关联的工厂对象获取具体策略, 利用RowObjMapper接口中的rowObjMapping()方法将查询结果集转换为实体对象. 以find()方法为例, 相关代码如下所示.
public class JDBCTemplate
{ private JDBCStrategy jdbcStrategy=JDBCStrategyFactory.getJDBCStrategy();
public Object find(String sql, Object[] args, RowObjMapper mapping)
{ Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {conn = jdbcStrategy.getConnection();
ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++)
ps.setObject(i + 1, args[i]);
rs = ps.executeQuery();
Object obj = null;
if (rs.next()) {
obj = mapping.rowObjMapping(rs);
}return obj;
} catch (SQLException e)
{throw new DaoException(e.getMessage(), e);}
finally
{ jdbc.close(rs, ps, conn); }
}}
利用DAO模式将业务逻辑与持久化逻辑解耦. DAO接口定义相关实体对象的持久化方法, DAOImp实现DAO与RowObjMapper接口, 通过关联的JDBCTemplate完成持久化操作. 为了进一步解耦SQL语句与Java代码, 将DAO对应的SQL语句写到Peroperty类型的配置文件中, 如果出现持久化逻辑错误只需修改配置文件即可.
通过上述设计, 改进后的JDBC框架将传统JDBC操作中的加载驱动、创建连接、创建Statement对象和释放资源等操作交由JDBCStratey、JDBCTemplate和RowObjMapper完成, 开发人员只需专注DAO的开发. 从而能够降低持久化代码的编写量, 提高开发效率.
3.3 改进的JDBC框架应用评价分别使用传统JDBC和改进的JDBC对绩效考评系统中的持久化层代码进行设计, 采用JUnit框架测试持久化层代码的执行时间, 并统计出各自代码的复用情况, 具体数据见表1.
执行时间是指从业务逻辑层调用持久层代码的执行时间, 分别调用1次和调用100次, 执行5次取平均值. 可以看出在单次执行的情况下, 改进的JDBC执行时间较长, 开销主要在两个方面: ① 设计模式增加了对象的调用开销; ② 工厂对象要解析并读取配置文件. 在多次调用的情况下, 改进的JDBC节省了执行时间, 主要是因为: ① 传统JDBC会多次加载驱动, 改进的JDBC只加载一次; ② 改进的JDBC在DAO工厂中增加了缓存机制. 由此可见, 改进的JDBC不但降低了时间复杂度, 并且有效提高了代码的复用率.
4 结论与展望JDBC是目前Java EE应用中数据持久化操作的一种常见解决方案, 针对传统JDBC存在的缺陷, 将策略模式、工厂模式、模板模式和数据库重连机制对传统JDBC进行了改进, 并成功地将改进的JDBC框架应用于某高校绩效考核系统的数据持久层设计中. 通过项目实践表明改进的JDBC框架能够提高数据持久层的开发效率和可复用率, 降低了与业务逻辑层和数据持久层的耦合性, 为Java EE数据库持久层的设计与开发提供了相应的借鉴.
[1] |
陈小虎, 邓惠俊. 基于mybatis的数据持久层研究. 成都工业学院学报, 2020, 23(2): 29-32. |
[2] |
王艳清, 陈红. 基于SSM框架的智能Web系统研发设计. 计算机工程与设计, 2012, 33(12): 4751-4757. DOI:10.3969/j.issn.1000-7024.2012.12.066 |
[3] |
夏赟, 李志蜀. 基于Hibernate框架的数据持久化层的研究及其应用. 计算机应用, 2008, 28(9): 2446-2448. |
[4] |
申斌, 李利民. 基于MVC模式S2SH框架的库存管理系统. 实验室研究与探索, 2014, 33(11): 113-117. DOI:10.3969/j.issn.1006-7167.2014.11.026 |
[5] |
郭广军, 陈代武, 胡玉平, 等. 基于JDBC的数据库访问技术的研究. 南华大学学报(自然科学版), 2005, 19(2): 50-54, 57. |
[6] |
崔丽群, 宋词. 基于策略模式和静态工厂结合的事务管理. 辽宁工程技术大学学报(自然科学版), 2009, 28(3): 427-430. DOI:10.3969/j.issn.1008-0562.2009.03.027 |
[7] |
张俐, 张维玺. 改进的JDBC框架在数据持久层的应用. 计算机工程与设计, 2010, 31(8): 1746-1749. |
[8] |
刘云玉, 段中兴, 原晋鹏. JDBC数据库重连机制的研究与实现. 计算机应用与软件, 2011, 28(7): 38-40. DOI:10.3969/j.issn.1000-386X.2011.07.012 |
[9] |
韩兵, 沈冲, 方英兰. 基于JDBC的缓存数据细粒度管理的研究. 计算机技术与发展, 2019, 29(12): 66-71. DOI:10.3969/j.issn.1673-629X.2019.12.012 |
[10] |
韩兵, 江燕敏, 方英兰. 基于JDBC的数据访问优化技术. 计算机工程与设计, 2017, 38(8): 1991-1996, 2031. |
[11] |
欧阳宏基, 葛萌, 陈伟. 基于JDBC的数据持久化层性能优化研究. 网络新媒体技术, 2016, 5(5): 9-15. DOI:10.3969/j.issn.2095-347X.2016.05.002 |
[12] |
李晓伟, 徐冰霖, 张银发, 等. 设计模式在测控通信构件设计中的应用. 飞行器测控学报, 2012, 31(6): 63-67. |
[13] |
李增智, 王宇, 李钢, 等. 面向对象可复用软件设计思想分析. 小型微型计算机系统, 2003, 24(5): 835-839. DOI:10.3969/j.issn.1000-1220.2003.05.011 |
[14] |
欧阳宏基, 葛萌. 基于Struts2+Ajax+JDBC的企业级Java Web架构. 计算机系统应用, 2017, 26(8): 77-82. DOI:10.15888/j.cnki.csa.005883 |