创建JDBC框架及原理分析

  
  

对于Java数据库的连接,由最初学习的每次全部手工代码,到后面的不断利用知识简化代码量;这是不断学习的过程,就像人类由原始社会的钻木取火到当代的文明,都是一步步过来的!

本文不从最开始的JDBC入门开始总结,只总结被很多人忽略的地方:自己写框架,或者更确切说是框架的原理!

先说使用框架的好处,也可以说是使用工具的好处,就如同使用记事本编程和eclipse之间的区别,很明显使用工具大大的提高了我们的编程效率,使我们在编程时候可以几乎避免垃圾代码或重复代码的痛苦!

但是这样做其实也有不好的地方:不少的程序员,尤其是初学者,贪恋短时间出成果的短暂虚荣,学习不求原理,只求方便。也就造成了很多有识之士口中所说的:离开SSH框架,你还能做出来什么?诚然编程工具可以促进我们的学习,但是如果我们沉溺于简单的皮毛,一辈子也就是碌碌无为的码农!其实一句话:向往高处走,底层必须学!

本文总结:自己如何编写JDBC框架,实现重复代码的简化?

本文默认使用C3P0连接池,从用C3P0连接池写过增删改查四个操作分析比较后开始!

之前我们写的CRUD操作,可以看到重复了很多的代码,我们想我们能否提炼这三个方法使其成为一个方法,只是根据不同的参数来确定去执行什么操作?

实现这一设想,我们首先来学习一些必备的知识:就是说我们如何知道我们数据库中的表的信息,当然如果你是表的创始人你知道,但是假如现在我们是框架师,我们对sql,对表一无所知,(或者说我们了解SQL知识,但是对数据库内容根本无法知晓)我们只是使用一些技术实现对数据库的操作,所以如何得到数据库相关信息的呢?

通过元数据!

先了解元数据

所谓元数据就是指数据库、表、列的定义信息,(描述数据的数据)如何获得元数据呢?

DataBaseMetaData(数据库元数据)

使用connection.getDatabasemetaData()方法,那这个DataBaseMetaData对象到底有什么属性或者方法呢?

数据库的元数据

getURL():返回一个String类对象,代表数据库的URL。

getUserName():返回连接当前数据库管理系统的用户名。

getDatabaseProductName():返回数据库的产品名称。

getDatabaseProductVersion():返回数据库的版本号。

getDriverName():返回驱动驱动程序的名称。

getDriverVersion():返回驱动程序的版本号。

isReadOnly():返回一个boolean值,指示数据库是否只允许读操作。

ParameterMetaData(获取参数元数据)

可用于获取关于PreparedStatement 对象中每个参数标记的类型和属性信息的对象。使用PreparedStatement.getParameterMetaData()方 法 获 得 代 表PreparedStatement元 数 据 的ParameterMetaData对象。

它有两个最重要的方法:

getParameterCount() 获得指定参数的个数

getParameterType(intparam) 获得指定参数的sql类型(MySQL驱动不支持该方法)

ResultSetMetaData(获取结果集元数据)

可用于获取关于ResultSet对象中列的类型和属性信息的对象。有关 ResultSet 中列的名称和类型的信息。 

那么如果是向把返回的结果遍历一下封装到bean当中我们如何设置呢,我们又不知道keyvalue,这个时候我们就需要另外一个元数据了,ResultSetMetaData它可以获得使用ResultSet对象元数据的对象,主要方法包括:

getColumnCount() 返回resultset对象的列数

getColumnName(intcolumn) 获得指定列的名称

getColumnTypeName(intcolumn) 获得指定列的类型

实例:(我们的框架)

CUD操作,我们集成到一个update方法去,根据参数的不同,进行不同的操作!

//利用元数据+反射优化CRUD操作!这个的原理和DBUtils的几乎一样!

创建JavaBean,用来封装数据。(查询时候用的上)

package com.itheima.domain;

public class User {

private int id;

private String username;

private String password;

private java.util.Date birthday;

private float salary;

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

public java.util.Date getBirthday() {

return birthday;

}

public void setBirthday(java.util.Date birthday) {

this.birthday = birthday;

}

public float getSalary() {

return salary;

}

public void setSalary(float salary) {

this.salary = salary;

}

}

package com.itheima.dao;

import java.sql.Connection;

import java.sql.ParameterMetaData;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.ResultSetMetaData;

import java.sql.SQLException;

import org.apache.commons.beanutils.BeanUtils;

import com.itheima.domain.User;

import com.itheima.util.JdbcUtil;

public class Demo2 {

public static void main(String[] args) throws Exception {

/*//这是Insert

String sql = "insert into user (username,password,birthday,salary)values(?,?,?,?)";

Object params[] = {"zhangsan","125","2012-8-25",6000};

update(sql,params);*/

/*//尝试Update

String sql = "update user set username = ? where username = ?";

Object params[] = {"lisi","zhangsan"};

update(sql,params);

//此时就可以感受到好处:对某类操作(CUD)等只需要简单的sql语句变换(就是说很少的变化),减轻了代码量

*/

//尝试Delete

/*String sql = "delete from user where id = ?";

update(sql,new Object[]{2});

假如update也不是你写的,这样的话代码量就大大的减少了!这样就引出了框架

*/

/*

  * 进行的是查询操作

  * 查询为什么需要javabean?因为查询需要返回数据,不然怎么显示

 */

String sql = "select * from user where id = ?";

User user = (User)query(sql, new Object[]{1}, User.class);

System.out.println("用户名:" + user.getUsername());

System.out.println("密码:" + user.getPassword());

System.out.println("生日:" + user.getBirthday().toLocaleString());

System.out.println("薪水:" + user.getSalary());

}

private static Object query(String sql, Object[] params ,Class clazz) throws Exception {

Object obj = clazz.newInstance();

Connection conn = JdbcUtil.getMySqlConnection();

PreparedStatement pstmt = conn.prepareStatement(sql);

//获取参数元数据

ParameterMetaData psmd = pstmt.getParameterMetaData();

int size = psmd.getParameterCount();

//循环绑定

for (int i = 0; i < size; i++) {

pstmt.setObject(i+1, params[i]);

}

ResultSet rs = pstmt.executeQuery();

if(rs.next()){

//取得结果集元数据

ResultSetMetaData rsmd = rs.getMetaData();

//取得结果集列数目

size = rsmd.getColumnCount();

for (int i = 0; i < size; i++) {

//获取列名

String columnName = rsmd.getColumnName(i+1);

//取得结果集元数据之后通过BeanUtils框架为JavaBean设置值

BeanUtils.setProperty(obj, columnName, rs.getObject(i+1));

}

}

JdbcUtil.close(rs);

JdbcUtil.close(pstmt);

JdbcUtil.close(conn);

return obj;

}

//CUD操作(通用做法)

private static void update(String sql, Object[] params) throws SQLException {

Connection conn = JdbcUtil.getMySqlConnection();

PreparedStatement pstmt = conn.prepareStatement(sql);

ParameterMetaData psmd = pstmt.getParameterMetaData();

int size = psmd.getParameterCount();

System.out.println(size);

//循环绑定对象的值(就是将?与实际的传入参数绑定)绑定第一个,第二个...

for (int i = 0; i < params.length; i++) {

pstmt.setObject(i+1, params[i]);

}

//执行

pstmt.executeUpdate();

JdbcUtil.close(pstmt);

JdbcUtil.close(conn);

}

}

总结:此时我们可以看到,使用元数据确实很大程度上减少了重复代码量。但是针对我们自己的框架,肯定还有不完美的小问题。

这时候注意:java是一门开源的语言,这是java保持强大生命力的根本所在,既然我们能想到自己写一个框架来简化操作,那么肯定有开源组织也注意到了,而且做得更好!

再总结一个知识点:

O-R-Mapping  object-relative-mapping

对象关系映射。把关系型数据映射为对象(只要能将传统的关系数据库的操作,映射为面向对象方式操作的框架都可以称为OR-Mapping

常用O-R Mapping映射工具

Hibernate

Ibatis

Commons DbUtils(只是对JDBC简单封装)

ApacheDBUtils框架

简介:

commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。因此dbutils成为很多不喜欢hibernate的公司的首选。

API介绍:

org.apache.commons.dbutils.QueryRunner 

org.apache.commons.dbutils.ResultSetHandler

工具类

org.apache.commons.dbutils.DbUtils。   

QueryRunner类 

该类简单化了SQL查询,它与ResultSetHandler组合在一起使用可以完成大部分的数据库操作,能够大大减少编码量。

QueryRunner类提供了两个构造方法:

默认的构造方法(无参)

另一个需要一个 javax.sql.DataSource 来作参数的构造方法。

ResultSetHandler 接口的实现类

ArrayHandler:把结果集中的第一行数据转成对象数组。

ArrayListHandler:把结果集中的每一行数据都转成一个数组,再存放到List中。

BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。

BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。

ColumnListHandler:将结果集中某一列的数据存放到List中。

KeyedHandler(name):将结果集中的每一行数据都封装到一个Map<列名,列值>里,再把这些map再存到一个map里,其key为指定的key

MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。

MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List

利用DButils框架进行操作:(使用相当简单,但是注意理解原理)

package com.itheima.dao;

import java.sql.SQLException;

import org.apache.commons.dbutils.QueryRunner;

import org.apache.commons.dbutils.handlers.BeanHandler;

import com.itheima.domain.User;

import com.itheima.util.JdbcUtil;

public class Demo3 {

public static void main(String[] args) throws Exception {

//使用DButil框架

QueryRunner runner = new QueryRunner(JdbcUtil.getDataSource());

//String sql = "update user set username = ? where username = ?";

String sql = "insert into user (username,password,birthday,salary)values(?,?,?,?)";

//runner.update(sql, new Object[]{"wangwu","lisi"});

runner.update(sql, new Object[]{"zhangzetian","2356","2012-02-11",6000});

sql = "select * from user where id = ?";

User user = (User) runner.query(sql, 1, new BeanHandler(User.class));

System.out.println("用户名:" + user.getUsername());

}

}

这样的写法是不是相当的简单呢!

备注:配置文件,数据库,Utils工具类等已经提前准备好。

本文章只是自己学西过程中的总结,并不是讲解类型的博文,所以这些东西没有面面俱到的写出!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值