对jdbc的封装的总结

记得自己刚开始学习java的时候,操作数据库都是写一大堆的代码,getXX ,setXX 的代码到处都是,而且 每次都是从ResultSet中一个个的取出数据 set到vo 中,等学习了hibernate后,由于hibernate出色的设计,已经不用再那么麻烦的写重复而繁琐的数据库操作代码。
不过基于对初识java时候jdbc留下的深刻印象,自己业余时候对jdbc进行了下简单的封装,下面就是代码:

[color=red]用于dao继承的jdbc的封装对象 JdbcTemplate,使用的时候 继承此类即可。[/color]

package org.jutil.jdbc.base;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.sql.DataSource;

public abstract class JdbcTemplate<T extends Object> {

private static int commit = 100; // 每100条记录一提交
private static boolean hasNext = false;
private DataSource dataSource;

/**
* 注入数据源
*
* @param dataSource
*/
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}

private DataSource getDataSource() {
return dataSource;
}

/**
* 获得接口中泛型的实例
*
* @param index
* @return
*/
@SuppressWarnings("unchecked")
private Class getGenericType(int index) {
Type genType = getClass().getGenericSuperclass();
if (!(genType instanceof ParameterizedType)) {
return Object.class;
}
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if (index >= params.length || index < 0) {
throw new RuntimeException("Index outof bounds");
}
if (!(params[index] instanceof Class)) {
return Object.class;
}
return (Class) params[index];
}

/**
* 得到Connection
*
* @return
* @throws SQLException
*/
private Connection getConnection() throws SQLException {
Connection connection = getDataSource() == null ? null: getDataSource().getConnection();
return connection == null ? JdbcUtil.getInstance().getConnection(): connection;
}

/**
* 根据泛型T实体的给出的字段、查询语句、参数得到一个有数据的T实体对象
* 注:bean的字段名称必须与数据库查询结果列名一致
*
* @param sql 查询语句
* @param args 参数
* @return T
* @throws Exception
*/
public T uniqueResult(String sql,Object... args) {
return this.uniqueResult(null, null, sql, args);
}

/**
* 根据泛型T实体的给出的字段、查询语句、参数得到一个有数据的T实体对象
*
* @param fieldNames 要设置值的字段
* @param sql 查询语句
* @param args 参数
* @return T
* @throws Exception
*/
@SuppressWarnings("unchecked")
public T uniqueResult(String[] fieldNames, String[] rsClums, String sql,Object... args) {
sqlValidate(sql);
Object obj = null;
Connection conn = null;
PreparedStatement pstat = null;
ResultSet rs = null;
try {
conn = getConnection();
pstat = conn.prepareStatement(sql);
for (int i = 1; i <= args.length; i++) {
pstat.setObject(i, args[i - 1]);
}
rs = pstat.executeQuery();
if(fieldNames==null||rsClums==null){
obj = convertObject(rs);
}else{
obj = convertObject(fieldNames, rsClums, rs);
}
pstat.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
free(rs, pstat, conn);
}
return (T) obj;
}

/**
* 执行SQL语句方法,添加,修改,删除。没有 预编译
*
* @param sql
* @return
*/
public boolean execute(String sql, Object... args) {
sqlValidate(sql);
Connection conn = null;
PreparedStatement pstat = null;
boolean flag = false;
try {
conn = getConnection();
pstat = conn.prepareStatement(sql);
for (int i = 1; i <= args.length; i++) {
pstat.setObject(i, args[i - 1]);
}
flag = pstat.execute();
} catch (SQLException e) {
e.printStackTrace();
} finally {
free(null, pstat, conn);
}
return flag;
}

/**
* 执行SQL查询语句方法,返回结果集对象
*
* @param sql
* @return
*/
public ResultSet executeQuery(String sql, Object... args) {
sqlValidate(sql);
Connection conn = null;
PreparedStatement pstat = null;
ResultSet rs = null;
try {
conn = getConnection();
pstat = conn.prepareStatement(sql);
for (int i = 1; i <= args.length; i++) {
pstat.setObject(i, args[i - 1]);
}
rs = pstat.executeQuery();
} catch (Exception e) {
e.printStackTrace();
} finally {
free(null, pstat, conn);
}
return rs;
}

/**
* 功能描述:[新增、修改、删除]操作
*
* @param sql
* sql语句
* @param args
* 参数
* @return int 成功返回1 否则返回0
* @author <a href="mailto:seyaa-ls@hotmail.com">万大龙</a> create on:2011-1-21
*/
public int executeUpdate(String sql, Object... args) {
sqlValidate(sql);
Connection conn = null;
PreparedStatement pstat = null;
int r = 0;
try {
conn = getConnection();
pstat = conn.prepareStatement(sql);
for (int i = 1; i <= args.length; i++) {
pstat.setObject(i, args[i - 1]);
}
r = pstat.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
free(null, pstat, conn);
}
return r;
}

/**
* 功能描述:批量[新增、修改、删除]操作;默认100条记录提交一次
*
* @param sql
* 批量插入操作sql语句
* @param args
* 参数
* @return List<String> 操作成功后的标识集合
* @author <a href="mailto:seyaa-ls@hotmail.com">万大龙</a> create on:2011-1-21
*/
public boolean executeBatch(String sql, Object[][] args) {
return executeBatch(commit, sql, args);
}

/**
* 功能描述:批量[新增、修改、删除]操作
*
* @param commit
* 每多少条记录提交一次的参数 默认:100
* @param sql
* 批量插入操作sql语句
* @param args
* 参数
* @return List<String> 操作成功后的标识集合
* @author <a href="mailto:seyaa-ls@hotmail.com">万大龙</a> create on:2011-1-21
*/
public boolean executeBatch(int commit, String sql, Object[][] args) {
sqlValidate(sql);
Connection conn = null;
PreparedStatement pstat = null;
boolean flag = false;
try {
// 1. 建立与数据库的连接
conn = getConnection();
conn.setAutoCommit(false);
pstat = conn.prepareStatement(sql);
commBatchExcute(commit, sql, args, conn, pstat);
flag = true;
} catch (Exception e) {
flag = false;
commRollback(conn);
e.printStackTrace();
} finally {
free(null, pstat, conn);
}
return flag;
}

/**
* 回滚操作
*
* @param conn
*/
private void commRollback(Connection conn) {
// 若出现异常,对数据库中所有已完成的操作全部撤销,则回滚到事务开始状态
try {
if (!conn.isClosed()) {
conn.rollback();// 4,当异常发生执行catch中SQLException时,记得要rollback(回滚);
System.out.println("批量执行失败,事务回滚!");
conn.setAutoCommit(true);
}
} catch (SQLException e1) {
e1.printStackTrace();
}
}

/**
* 批量任务 核心 方法
*
* @param commit
* @param sql
* @param args
* @param conn
* @param pstat
* @throws Exception
*/
private void commBatchExcute(int commit, String sql, Object[][] args,
Connection conn, PreparedStatement pstat) throws Exception {
int rowsTmp = 0;
for (int i = 0; i < args.length; i++) {
Object[] temp = args[i];
for (int t = 1; t <= temp.length; t++) {
Object value = temp[t - 1];
pstat.setObject(t, value);
}
// 将上面的参数添加到此 PreparedStatement 对象的批处理命令中。
pstat.addBatch();
if (rowsTmp % commit == 0) {// 每500条记录一提交
pstat.executeBatch();
conn.commit();
if (null == conn) { // 如果连接关闭了 就在创建一个 为什么要这样 原因是
// conn.commit()后可能conn被关闭
conn = getConnection();
conn.setAutoCommit(false);
}
}
rowsTmp++;
}
// 将一批参数提交给数据库来执行,如果全部命令执行成功,则返回更新计数组成的数组。
pstat.executeBatch();
conn.commit();// 2,进行手动提交(commit)
conn.setAutoCommit(true);// 3,提交完成后回复现场将Auto commit,还原为true,
}

/**
* 功能描述:查询一行记录,返回以HashMap为一行记录
*
* @param sql
* 用于查询的sql语句
* @param args
* sql预编译的参数
* @return HashMap<String,Object> 结果集
* @author <a href="mailto:seyaa-ls@hotmail.com">万大龙</a> create on:2011-1-21
*/
public HashMap<String, Object> executeQueryToMap(String sql, Object... args) {
sqlValidate(sql);
Connection conn = null;
PreparedStatement pstat = null;
ResultSet rs = null;
HashMap<String, Object> result = new HashMap<String, Object>(0);
try {
conn = getConnection();
pstat = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
for (int i = 1; i <= args.length; i++) {
pstat.setObject(i, args[i - 1]);
}
rs = pstat.executeQuery();
ResultSetMetaData rsm = pstat.getMetaData();
while (rs.next()) {
for (int i = 1; i <= rsm.getColumnCount(); i++) {
Object value = rs.getObject(i);
result.put(rsm.getColumnName(i), value);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
free(rs, pstat, conn);
}
return result;
}

/**
*
* 功能描述:查询全部结果,返回以HashMap为一行记录结果的List集合
*
* @param sql
* 用于查询的sql语句
* @param args
* sql预编译的参数
* @return List<HashMap<String,Object>> 结果集
* @author <a href="mailto:seyaa-ls@hotmail.com">万大龙</a> create on:2011-1-21
*/
public List<HashMap<String, Object>> executeQueryAllToMap(String sql,
Object... args) {
sqlValidate(sql);
Connection conn = null;
PreparedStatement pstat = null;
ResultSet rs = null;
List<HashMap<String, Object>> result = new ArrayList<HashMap<String, Object>>(
0);
HashMap<String, Object> temp = null;
try {
conn = getConnection();
pstat = conn.prepareStatement(sql);
for (int i = 1; i <= args.length; i++) {
pstat.setObject(i, args[i - 1]);
}
rs = pstat.executeQuery();
ResultSetMetaData rsm = pstat.getMetaData();
while (rs.next()) {
temp = new HashMap<String, Object>();
for (int i = 1; i <= rsm.getColumnCount(); i++) {
Object value = rs.getObject(i);
temp.put(rsm.getColumnName(i), value);
}
result.add(temp);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
free(rs, pstat, conn);
}
return result;
}

/**
*
*
* 功能描述:查询全部结果,返回泛型中最终指明的对象的结果List集合
*
* @param sql用于查询的sql语句
* @param args sql预编译的参数
* @return List<T> 结果集
* @author <a href="mailto:seyaa-ls@hotmail.com">万大龙</a>
* create on: 2011-1-21
*
*/
public List<T> executeQueryAllToList(String sql, Object... args) {
return this.executeQueryAllToList(null,null,sql, args);
}

/**
*
*
* 功能描述:查询全部结果,返回泛型中最终指明的对象的结果List集合
*
* @param sql
* 用于查询的sql语句
* @param obj
* 要设置值的对象
* @param toSetFirlds
* 要设置值的字段
* @param toGetClums
* 要从ResultSet中取结果的列表 toGetClums必须与toSetFirlds参数按顺序一一对应,否则会出现数据错误
* @param args
* sql预编译的参数
* @return List<T> 结果集
* @author <a href="mailto:seyaa-ls@hotmail.com">万大龙</a> create on:
* 2011-1-21
*
*/
@SuppressWarnings("unchecked")
public List<T> executeQueryAllToList(String[] beanFields, String[] rsClums,String sql, Object... args) {
sqlValidate(sql);
Connection conn = null;
PreparedStatement pstat = null;
ResultSet rs = null;
List<T> result = new ArrayList<T>(0);
try {
conn = getConnection();
pstat = conn.prepareStatement(sql);
for (int i = 1; i <= args.length; i++) {
pstat.setObject(i, args[i - 1]);
}
rs = pstat.executeQuery();
while (rs.next()) {
hasNext = true;
Object obj = null;
if(beanFields==null||rsClums==null){
obj = convertObject(rs);
}else{
obj = convertObject(beanFields, rsClums, rs);
}
result.add((T) obj);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
free(rs, pstat, conn);
}
return result;
}

/**
* 将结果集中数据 转换到 bean 中
*
* @param beanFields
* bean要赋值的字段
* @param rsClums
* 要取值的列名
* @param rs
* ResultSet 结果集
* @return
* @throws Exception
*/
private Object convertObject(String[] beanFields, String[] rsClums,ResultSet rs) throws Exception {
Field[] fields;
Object obj = getGenericType(0) != null ? (getGenericType(0).newInstance()) : null;
if (obj != null) {
String[] colNames = getColNames(rs);
try {
if (!hasNext) {
rs.next();
}
fields = obj.getClass().getDeclaredFields();
int cl = beanFields.length > rsClums.length ? rsClums.length
: beanFields.length;
for (int j = 0; j < cl; j++) {
String clumName = colNames[j];// 该列的列名
Object clumValue = rs.getObject(j + 1);// 该列的值
String toGetClumName = rsClums[j];// 要从结果取出要取的列名
String fieldName = beanFields[j];// 要给对象设置字的字段名
String methodName = "set"+ fieldName.substring(0, 1).toUpperCase()+ fieldName.substring(1, fieldName.length());
if (clumName.equals(toGetClumName)) {
for (Field field : fields) {
field.setAccessible(true); // 设置些属性是可以访问的
if (field.getName().equals(fieldName)) {
Method m = obj.getClass().getMethod(methodName,clumValue == null ? null : clumValue.getClass());
m.invoke(obj, clumValue);// 调用obj对象的这个方法
break;
}
}
}
}
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
return obj;
}

/**
* 列表列名与bean对象字段名称相同的时候使用
* @param rs
* @return
*/
@SuppressWarnings("unchecked")
private Object convertObject(ResultSet rs) {
Object object = null;
try {
Class clazz = getGenericType(0);
String[] colNames;
colNames = getColNames(rs);
// 得到所有的列名
Method[] ms = clazz.getMethods();// 得到javaBean中所有set或get方法
if (rs.next()) {
object = clazz.newInstance();
for (int i = 0; i < colNames.length; i++) {
String colName = colNames[i];
String methodName = "set"+ colName.substring(0, 1).toUpperCase()+ colName.substring(1, colName.length());
for (Method m : ms) {
if (methodName.equals(m.getName())) {
m.invoke(object, rs.getObject(colName));// 调用set方法,将该列的值放到set方法当中去.
break;
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return object;
}

private void sqlValidate(String sql) {
if (sql == null || sql.trim().length() < 0) {
throw new RuntimeException("sql sentence is null or is '' ");
}
}

/**
* 从ResultSet中的到查询结果的列
*
* @param rs
* @return
* @throws SQLException
*/
private static String[] getColNames(ResultSet rs) throws SQLException {
ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
String[] colNames = new String[count];
for (int i = 1; i <= count; i++) {
colNames[i - 1] = rsmd.getColumnLabel(i);
}
return colNames;
}

// 释放资源
private void free(ResultSet rs, Statement sta, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (sta != null) {
try {
sta.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (conn != null) {
//如果dataSource 不为null 说明使用了 spring 或者其他数据源,这里关掉连接
if(dataSource!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}else{
//否则是使用了自定义的连接池,将连接重新放到连接池中
JdbcUtil.free(conn);
}
}
}
}
}
}
}
}



在上面的封装中,使用到 DataSource ,在使用sping的时候 直接出入DataSource 即可,如果没有spring 也不用担心,在网上找了个连接池的代码,修后如下:


package org.jutil.jdbc.base;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Properties;


public class DataSource{

private InputStream instream;
private Properties pro;

private static int initCount = 5;// 初始连接数
private static int maxCount = 10;// 数据库最大连接数
private static int currentConnt = 0;// 当前数据库的连接数
LinkedList<Connection> connectionPool = new LinkedList<Connection>();// 数据库连接池

// 同包才能方问该类
DataSource() {
instream = this.getClass().getClassLoader().getResourceAsStream("dbconfig.properties");
pro = new Properties();
try {
pro.load(instream);
String ininc = pro!=null&&pro.getProperty("initCount")==null?"5":pro.getProperty("initCount") ;
initCount = ininc==null?initCount:Integer.parseInt(ininc);
String maxc = pro!=null&&pro.getProperty("maxCount")==null?"5":pro.getProperty("maxCount") ;
maxCount = maxc==null?maxCount:Integer.parseInt(maxc);
try {
Class.forName(pro.getProperty("driverClass"));
for (int i = 1; i <= initCount; i++) {
this.connectionPool.addLast(this.createConnection());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("加载数据库驱动时出错!");
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("加载配置文件出错!");
}
}

/**
*
* Description: 创建数据库的连接
* @param
* @return Connection
* @throws
* @date 2011-3-5
* version 1.0
*/
private Connection createConnection() {
Connection conn = null;
try {
conn = DriverManager.getConnection(pro.getProperty("url"), pro.getProperty("username"), pro.getProperty("password"));
currentConnt++;
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("创建数据库连接失败!");
}
return conn;
}

// 得到数据库的连接
public Connection getConnection() {
synchronized (connectionPool) {
if (connectionPool.size() > 0) {
return connectionPool.removeFirst();
}
if (currentConnt < maxCount) {
Connection coon = this.createConnection();
this.connectionPool.addLast(coon);
return coon;
}
throw new RuntimeException("数据库已达到最大的连接数!");
}
}

public static void main(String[] args) {
DataSource d = new DataSource();
System.out.println(d.connectionPool.size());
}

}



数据源也有了,还需要另个工具类 JdbcUtil。


package org.jutil.jdbc.base;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;


@SuppressWarnings("serial")
public class JdbcUtil implements Serializable {

private static JdbcUtil util = null;
private static DataSource dataSource = null;

public static void main(String[] args) {
}

public static JdbcUtil getInstance() {
if (util == null) {
synchronized (JdbcUtil.class) {
util = new JdbcUtil();
}
}
return util;
}

private JdbcUtil(){
dataSource = new DataSource();
}

// 获得连接对象
public Connection getConnection() {
return dataSource.getConnection();
}

// 释放数据库的连接
public void freeConnection(Connection conn) {
this.connectionPool.addLast(conn); // 仍然放到数据库连接池中去了,也没有关掉,这样就可以重复使用
}
}



最后就是对上面的代码 进行测试了:
一个用测试的bean对象,


package org.jutil.jdbc.base;
/**
* @Title: TestBean.java
* @Package org.jutil.jdbc.base
* @Description: TODO(添加描述)
* @author {hnxyhcwdl1003@163.com} 万大龙
* @date 2011-3-5 下午11:39:59
* @version V1.0
*/
public class TestBean {

Integer id ;
String name;
Integer age;
public Integer getId() {

return id;
}
public void setId(Integer id) {

this.id = id;
}
public String getName() {

return name;
}
public void setName(String name) {

this.name = name;
}
public Integer getAge() {

return age;
}
public void setAge(Integer age) {

this.age = age;
}


}




dao继承的实现类:


package org.jutil.jdbc.base;
/**
* @Title: DaoImpl.java
* @Package org.jutil.jdbc.base
* @Description: TODO(添加描述)
* @author {hnxyhcwdl1003@163.com} 万大龙
* @date 2011-3-5 下午11:39:37
* @version V1.0
*/
public class DaoImpl extends JdbcTemplate<TestBean>{

}




单元测试(junit)类:



package org.jutil.jdbc.base;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;

import junit.framework.TestCase;
/**
* @Title: TestJdbc.java
* @Package org.jutil.jdbc.base
* @Description: TODO(添加描述)
* @author {hnxyhcwdl1003@163.com} 万大龙
* @date 2011-3-5 下午11:39:08
* @version V1.0
*/
public class TestJdbc extends TestCase{
DaoImpl impl = null;
private void init(){
impl = new DaoImpl();
}

public void stestExecute(){
init();
impl.execute("INSERT STU (id,name,age) VALUES(2,'wdl',22)");
}

public void stestExecuteBatch(){
init();
Object[][] args = {{3,"威震天",20000},{4,"大黄蜂",23000}};
impl.executeBatch("INSERT STU (id,name,age) VALUES(?,?,?)", args);
}

public void stestExecuteQuery(){
init();
Object[] args = {20000};
ResultSet r = impl.executeQuery("SELECT * FROM STU s WHERE s.age>= ? ", args);
try {
while(r.next()){
System.out.println("id:"+r.getObject(1)+" | name:"+r.getObject(2)+" | age:"+r.getObject(3));
}
} catch (SQLException e) {
e.printStackTrace();
}
}

public void stestExecuteQueryAllToList(){
init();
Object[] args = {20000};
List<TestBean> r = impl.executeQueryAllToList("SELECT * FROM STU s WHERE s.age>= ? ", args);
for(TestBean b:r){
System.out.println("id:"+b.getId()+" | name:"+b.getName()+" | age:"+b.getAge());
}
}

public void testExecuteQueryToMap(){
init();
Object[] args = {20000};
HashMap<String,Object> b = impl.executeQueryToMap("SELECT * FROM STU s WHERE s.age = ? ", args);
System.out.println("id:"+b.get("id")+" | name:"+b.get("name")+" | age:"+b.get("age"));
}

public void testExecuteQueryAllToMap(){
init();
Object[] args = {20000};
List<HashMap<String,Object>> r = impl.executeQueryAllToMap("SELECT * FROM STU s WHERE s.age>= ? ", args);
for(HashMap<String,Object> b:r){
System.out.println("id:"+b.get("id")+" | name:"+b.get("name")+" | age:"+b.get("age"));
}
}

public void testUniqueResult(){
init();
Object[] args = {20000};
TestBean b = impl.uniqueResult("SELECT * FROM STU s WHERE s.age>= ? ", args);
System.out.println("id:"+b.getId()+" | name:"+b.getName()+" | age:"+b.getAge());
}
}




最后再附上源码和测试的数据库,方便各位实验,如有问题,请指出,谢谢!

[color=red]
早上突然想起来,如果使用了spring 或者其他的什么数据源,连接会不能被释放。修改了断代码
[/color]
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值