黑马程序员—创建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当中我们如何设置呢,我们又不知道key和value,这个时候我们就需要另外一个元数据了,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简单封装)
Apache—DBUtils框架
简介:
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工具类等已经提前准备好。
本文章只是自己学西过程中的总结,并不是讲解类型的博文,所以这些东西没有面面俱到的写出!
黑马程序员—创建JDBC框架及原理分析的更多相关文章
- 黑马程序员_Java集合框架
集合类 1,为什么出现集合类? 面向对象语言对食物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式. 2,数组和集合类同是容器,有何不同? 数组 ...
- 黑马程序员——C语言开门片内存分析
iOS培训,iOS学习---------型技术博客.期待与您交流!------------ 一.各种进制的总结 1.二进制 (1) 在c语言中二进制以0b开头,输出二进制格式没有固定的格式,自定义输出 ...
- 黑马程序员——【Java高新技术】——代理
---------- android培训.java培训.期待与您交流! ---------- 一.“代理概述”及“AOP概念” (一)代理概述 1.问题:要为已存在的多个具有相同接口的目标类的各个方法 ...
- 黑马程序员:轻松精通Java学习路线连载1-基础篇!
编程语言Java,已经21岁了.从1995年诞生以来,就一直活跃于企业中,名企应用天猫,百度,知乎......都是Java语言编写,就连现在使用广泛的XMind也是Java编写的.Java应用的广泛已 ...
- 课程4:黑马程序员_spring2.5视频教程--视频列表
\黑马程序员_spring2.5视频教程\01Struts相关基础理论介绍.mp4; \黑马程序员_spring2.5视频教程\02搭建struts开发环境.mp4; \黑马程序员_spring2.5 ...
- 黑马程序员:Java基础总结----反射
黑马程序员:Java基础总结 反射 ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 反射 反射的基石:Class类 Class类代表Java类,它的各个实例对象又分别 ...
- 【黑马18期Java毕业生】黑马程序员Java全套资料+视频+工具
Java学习路线图引言: 黑马程序员:深知广大爱好Java的人学习是多么困难,没视频没资源,上网花钱还老被骗. 为此我们历时一个月整理这套Java学习路线图,不管你是不懂电脑的小 ...
- 黑马程序员+SQL基础(上)
黑马程序员+SQL基础 ---------------<a href="http://edu.csdn.net"target="blank">ASP ...
- 黑马程序员:Java基础总结----泛型(高级)
黑马程序员:Java基础总结 泛型(高级) ASP.Net+Android+IO开发 . .Net培训 .期待与您交流! 泛型(高级) 泛型是提供给javac编译器使用的,可以限定集合中的输入类型 ...
随机推荐
- Appium介绍
Appium介绍 Appium是一个移动端的自动化框架,可用于测试原生应用,移动网页应用和混合型应用,且是跨平台的.可用于IOS和Android以及firefox的操作系统.原生的应用是指用andro ...
- Java 模拟队列(一般队列、双端队列、优先级队列)
队列: 先进先出,处理类似排队的问题,先排的.先处理,后排的等前面的处理完了,再处理 对于插入和移除操作的时间复杂度都为O(1).从后面插入,从前面移除 双端队列: 即在队列两端都能够insert和r ...
- 32位Linux文件限制大小
线上程序不断重新启动,查看log发现是进程由于SIGXFSZ信号退出.对过大的文件进行操作的时候会产生此信号,一般仅仅在32位机器上出现,文件限制大小为2G.用lsof查看进程打开的文件,果然有一个文 ...
- SE 2014年4月14日
一. 概述BGP的特点 BGP协议是一种距离矢量协议,基于TCP的179端口,BGP协议不会动态的学习路由,只能将IGP协议学习到的或者静态路由注入到BGP中,成为BGP路由,BGP路由携带有丰富的路 ...
- 处理json中影响解析的多余引號
在xml中,敏感字符是尖括号,在json中,敏感字符是引號,上文中我们介绍了怎样处理xml中的敏感字符.本文说说怎样处理json中的敏感字符. 思路与上文同样,不再赘述.直接上代码: json–> ...
- Flex读取txt文件里的内容(二)
Flex读取txt文件里的内容 自己主动生成的文件 LoadTxt-app.xml: <?xml version="1.0" encoding="utf-8&quo ...
- OpenStack_Swift源代码分析——ObjectReplicator源代码分析(2)
1.Replicator运行代码具体分析 上篇问中介绍了启动Replicator的详细过程,以下解说Replicator的运行代码的详细实现,首先看replicate方法: def replicate ...
- VS2010 TFS
在本文的两个部分中,我将介绍Team Foundation Server的一些核心特征,重点介绍在本产品的日常应用中是怎样将这些特性结合在一起使用的. 作为一名软件开发者,在我的职业生涯中,我常常会用 ...
- 理解cookie的path和domain属性(转)
今天在做验证码时发现一个问题:A.B窗口都打开同一个页面,A先生成一个验证码,B再生成验证码,这时A所生成的验证码被B覆盖掉了.原因是使用了同名的cookie来存储验证码.一时找不到解决方法就参考了W ...
- sgu 286. Ancient decoration(最小环覆盖)
给你一个n个点,每个点度为k(k为偶数)的无向图,问是否能将图中的n条边染色,使得每个点都拥有两条被染色的边.也就是说,是否存在拥有原图中n条边的子图,使得每个点的度为2?仔细想想,每个点的度为2,实 ...