前言
这个小小的数据库操作封装框架是参考IBM开发网上的两篇文章并在其基础上扩充了一些功能而得到的所以首先要感谢两篇文章的作者
学习JDBC以来一直想实现一个简单的封装来方便编程但是由于水平有限一直没有较好的办法看了IBM开发网上的两篇文章以后感觉作者的设计思想很好一定能扩充成一个实用的JDBC封装所以我在文章提供的源码基础上加了一些功能这些功能包括支持多种数据类型处理了空值利用反射方便的在Row对象和值对象之间进行转换还有加了一个我自认为通用的DAO类来方便用户的操作
我把源码提供出来有两个目的一个是希望能帮助比我还初学的初学者熟悉JDBC另外就是请各位高手不吝赐教改进程序中的错误如果能将你们的对JDBC的封装方法提供出来那就更好了(不要说你们只用EJB或者HibernateJDO什么的?)
IBM开发网的那两篇文章分别是《一个简单的 JDBC 包装器》《对一个简单的 JDBC 包装器的扩展及应用》我的邮箱是xcn有事请与我联系
设计思想
把DBMS抽象成类Database这个类负责管理数据库连接以及提供表对象
把数据库中的一张或多张表抽象成类Table这个类中提供对表的添加修改删除的JDBC封装
将数据库表中的一条记录抽象成类Row这个类用HashMap保存关系数据库中表格中一行数据的字段名和值并提供一些相关操作另外这个类还提供了两个静态方法用于在Row对象和ValueObject之间进行方便的转换
把对个Row的集合抽象成RowSet这个类中用一个vector把多个Row对象保存起来并提供一些相关操作
代码分析
由于已经给出源码所以我只对代码中关键的和需要注意的地方加以说明大家可以执行源码一边演示一边体会
Database类源码如下
package comgdrjutildatabase;
import javasql*;
import javaxsql*;
import comgdrjutilservicelocator*;
public class Database {
/**
* 这个数据库连接成员只有在与数据库直接建立连接的情况下是有效的
*/
private Connection conn = null;
/**
* 当这个参数有效时表明程序是直接与数据库建立的连接而不是从连接池里取得连接
*/
private String url user password;
/**
* 当这个参数有效时表明程序是从连接池里取得连接
*/
private String datasource;
/**
* 用数据库地址用户名密码初始化数据库对象这个构造器用于程序是直接
* 与数据库建立连接的情况
* @param url
* @param user
* @param password
*/
public Database(String url String user String password) {
thisurl = url;
thisuser = user;
thispassword = password;
}
/**
* 用JNDI数据源名初始化数据库对象这个构造器用于从连接池取数据库连接的情况
* @param datasource
*/
public Database(String datasource) {
thisdatasource = datasource;
}
/**
* 得到数据库连接对于是否从连接池里取连接做了自动处理即根据用户调用了哪个构造器
* 来判断是否直接与数据库建立连接还是从连接池里取连接
* 对于用户来说不用考虑程序是从那里取得连接他只管正确的初始化数据库对象
* @return
* @throws SQLException
*/
public Connection getConnection() throws Exception {
if (datasource == null) { //直接与数据库建立连接
if (conn == null) {
conn = DriverManagergetConnection(url user password);
}
}
else { //从应用服务器的连接池里取得连接
ServiceLocator sl = ServiceLocatorgetInstance();
DataSource ds = slgetDataSource(datasource);
return dsgetConnection();//每调用一次都返回一个连接池中的数据库连接
}
return conn;
}
/**
* 释放连接如果是直接与数据库连接的情况则什么也不做
* 如果是从连接池中取得的连接那么释放传来的连接
* @param conn
*/
public void disConnect(Connection connection) {
if (datasource != null) { //只处理从连接池取连接的情况
try {
if (connection != null) {
connectionclose();
}
}
catch (Exception ex) {}
}
}
/**
* 得到与参数名对应的表对象注意这里不作任何数据库操作
* @param name
* @return
*/
public Table getTable(String name) {
return new Table(this name);
}
}
这个类是对DBMS的抽象所以使用时应用程序中只要有一个Database对象就够了如果你是以与数据库之间建立连接的方式使用那么你用Database(String url String user String password)构造器进行初始化如果是从应用服务器的连接池中取得连接的方式使用那么用Database(String datasource)构造器初始化这样以后你使用这个对象进行getConnection和disConnection时就不用去考虑始终保持一个连接(C/S方式)还是将连接返回连接池了因为在disConnection中已经做了处理集体使用方法将Table类在getConnection中的从连接池中取连接的代码你只要参考以下《JEE核心模式》中的服务定位器模式就知道是怎么回事了你在用Database(String url String user String password)初始化时其中的代码不起作用
?Table类源码如下
package comgdrjutildatabase;
import javasql*;
import javautil*;
import comgdrjutil*;
public class Table {
/**
* 通过这个数据库对象得到数据库连接
*/
private Database database;
/**
* 数据库中一个或多个(只限查询)表的名
*/
private String name;
/**
* 初始化表对象此时不作任何数据库相关操作
* 一般通过database的getTable调用
* @param database
* @param name
*/
public Table(Database database String name) {
thisdatabase = database;
thisname = name;
}
/**
* 查询某一行
* @return
*/
public Row getRow(String fields String criteria Object[] args) throws
DBAccessException {
RowSet rows = executeQuery(fields criteria args);
if (rows == null) {
return null;
}
return rowsget();
}
/**
* 得到一个多行记录
* @param criteria 查询条件
* @param args 查询条件的参数列表
* @return
*/
public RowSet getRows(String fields String criteria Object[] args) throws
DBAccessException {
return executeQuery(fields criteria args);
}
/**
* 执行SQL查询
* @param fields 要查询的字段如果传入null则表示查询表中所有字段
* @param criteria用户输入的查询Where条件
* @param args 用到的参数数组
* @return 返回符合结果行集
*/
private RowSet executeQuery(String fields String criteria Object[] args) throws
DBAccessException {
Connection conn = null;
RowSet rows = new RowSet();
String sql = null;
if (fields == null) {
fields = *;
}
try {
conn = databasegetConnection(); //取得数据库连接在方法内部对不同的连接情况进行了处理
sql = select + fields + from + name +
( (criteria == null) ? :
( where + criteria));
PreparedStatement pstmt = connprepareStatement(sql);
if (args != null) { //如果有查询参数则设置参数
for (int i = ; i < args.length; i++) {
pstmt.setObject(i + 1, args[i]);
}
}
ResultSet rs = pstmt.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int cols = rsmd.getColumnCount();
/**@todo 判断是否为零*/
if (cols == 0) {
return null;
}
while (rs.next()) {
Row row = new Row();
for (int i = 1; i <= cols; i++) {
String name = rsmd.getColumnName(i);
Object value = rs.getObject(i); //作通用类型处理,这