自定义数据库框架

我们以前写过的DAO,其中有多少冗余代码!分析一下,找出冗余代码,把共同的部分写成方法,把不同的地方写为方法参数。做成一个工具类,就叫QueryRunner

QueryRunner.java

获取DataSource


private   DataSource ds;

public  QueryRunner(DataSource ds)

{

this.ds=ds;

}

 

增删改:只有SQL语句,以及参数不同,其它都相同;


public void update (String sql,Object []objs)

{

Connection   con=null;

PreparedStatement   st=null;

try {

con=ds.getConnection();

st=con.prepareStatement(sql);

//得到参数的元数据

ParameterMetaData   pmd=st.getParameterMetaData();

//参数的个数

int count=pmd.getParameterCount();

if(count>0)

{

if(objs==null   || objs.length==0){

throw new   RuntimeException("参数不能为空");

}

else if(count!=objs.length){

throw new   RuntimeException("参数个数不匹配");

}

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

st.setObject(i+1,   objs[i]);

}

}

st.executeQuery();

}   catch (SQLException e) {

e.printStackTrace();

}

}

查询:SQL语句不同,参数不同,还有对ResultSet的处理不同!有反把ResultSet映射成Student,还有映射成List<Student>。当然,如果写UserDao,那么还要把ResultSet映射成User或List<User>。


public Object query(String sql,ResultSetHandler   resultHandler,Object []objs)

{

Connection con=null;

PreparedStatement st=null;

ResultSet rs=null;

Object obj=null;

try {

con=ds.getConnection();

st=con.prepareStatement(sql);

ParameterMetaData   pmd=st.getParameterMetaData();

int count=pmd.getParameterCount();

if(count>0){

if(objs==null||objs.length==0)

{

System.out.println("参数不能为空");

}else if(objs.length!=count)

{

System.out.println("参数不匹配");

}

for(int   i=0;i<count;i++)

{

st.setObject(i+1,   objs[i]);

}

}

rs=st.executeQuery();

obj =   resultHandler.handler(rs);

} catch (SQLException e) {

e.printStackTrace();

}

return obj;

}

查询结果集处理

查操作还有一个问题,查操作不只是SQL语句和参数不同,还有把ResultSet映射成什么样子的对象也不同!把结果集映射成什么对象,这应该由用来完成!

因为把结果集映射成一个对象,不是数据,而是动作,那么这种问题就不能通过传递一个普通的参数来处理了,而是传递一个动作给我们的查方法!传递动作就是传递方法,这时你应该写一个接口。

策略模式:把算法提取出来!


public interface ResultSetHandler {

Object   handler(ResultSet rs);

}

 

如果结果集是一条记录

注意:可以把结果集转换成Bean对象!要求列名称与Bean属性名称必须一致!


public class BeanHandler implements ResultSetHandler {

private Class clz;

public BeanHandler (Class<Account>   clz)

{

this.clz=clz;

}

public Object handler(ResultSet rs) {

Object   obj=null;

try {

if(rs.next())

{

obj=clz.newInstance();

//获取结果集的元数据

ResultSetMetaData   rsmd = rs.getMetaData();

int count = rsmd.getColumnCount();//得到列数

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

//列的名字

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

//每一列的值

Object   columnValue=rs.getObject(i+1);

Field   f=clz.getDeclaredField(columnName);

f.setAccessible(true);

f.set(obj,   columnValue);

}

}

}   catch (Exception e) {

e.printStackTrace();

}

return obj;

}

}

结果集是多条记录


public class BeanListHandler implements ResultSetHandler {

private Class clz;

public BeanListHandler (Class<Account>   clz)

{

this.clz=clz;

}

public List   handler(ResultSet rs) {

List   list=new ArrayList();

Object   obj=null;

try {

while(rs.next())

{

obj=clz.newInstance();

//获取结果集的元数据

ResultSetMetaData   rsmd = rs.getMetaData();

int count = rsmd.getColumnCount();//得到列数

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

//列的名字

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

//每一列的值

Object   columnValue=rs.getObject(i+1);

Field   f=clz.getDeclaredField(columnName);

f.setAccessible(true);

f.set(obj,   columnValue);

list.add(obj);

}

}

}   catch (Exception e) {

e.printStackTrace();

}

return   list;

}

}

测试类


public class defineFrame {

public static   void main(String[] args) {

QueryRunner   qr = new QueryRunner(c3p0Util.getDataSource());

qr.update("insert into account   values(?,?,?)",new Object []{6,"aj",1000});

List<Account>   account = (List<Account>)qr.query("select   * from account", new   BeanListHandler(Account.class),null);

System.out.println(account);

qr.update("delete from account where   id=?",new Object []{6});

}

}

ORM简介

1 ORM是什么?

  ORM(Object/Relation Mapping)就是对象-关系的映射,对象就是Java这种面向对象语言,关系就是关系型数据库,其实就是把一个对象映射成表的一行记录,再把表的一行记录映射成Java中的一个对象。这就是ORM的用途!

2 常用ORM工具(JDBC框架)

l  Apache commons DBUtils:很简单的JDBC框架,很多公司在使用它,就是因为它内容很简单,也很方便;

l  Hibernate(全自动):SSH中的H就是它了,它的HQL号称是面向对象的查询语言;

l  Ibatis(半自动):简单、方便!很多人用“全自动”形容Hibernate,那么对Ibatis就是“半自动”了。Hibernate把面向关系的东西都封装起来了,甚至你可能对SQL不是很了解都可以通过Hibernate来操作数据库!但是,有是我们还是需要自己来通过面向关系(打开封装)来完成一些特殊的操作,那么“半自动”的Ibatis就派上用场了;

l  Spring-JDBC(基本与DBUtils是一个级别的,很简单的封装):Spring中的JDBC框架与dbUtils很相似!但是Spring的IoC给Spring-JDBC做了强大的后盾,并且Spring通过AOP对声明式事务的处理可以说是为人能比,所以,Spring的JDBC框架还是很有用途的;

l  EJB(Entity Bean)(老了):Java EE中的实体Bean,因为是重量级组件,现在已经很少使用了。

DBUtils

1 DBUtils简介

DBUtils是Apache Commons组件中的一员,开源免费!

DBUtils是对JDBC的简单封装,但是它还是被很多公司使用!

DBUtils的Jar包:dbutils.jar

2 DBUtils主要类

l  DbUtils:都是静态方法,一系列的close()方法;

l  QueryRunner:提供update()、query()、batch()方法;

其实我们自定义的框架中,JdbcRunner就是按照QueryRunner来写的,所以大家对update()和query()方法的使用应该没有问题了。

QueryRunner的query()方法也需要ResultSetHandler来映射结果集,接口名称也与我们写的一样,所以大家应该比较熟悉了。

3 QueryRunner之更新

在DBUtlis中最主要的类就是QueryRunner了,创建它有如下两种方式:


QueryRunner qr1 = new QueryRunner();

DataSource ds = …

QueryRunner qr2 = new QueryRunner(ds);

一种方法是给QueryRunner指定DataSource,另一种是不指定DataSource。本来在DBUtils1.0版本就存在的setDataSource()方法,在1.4已经消失了!不能向下兼容的东西,真是垃圾!

QueryRunner的update()和query()方法有两种重要的重载方式:需要Connection参数的,和不需要Connection参数的,需要Connectoin参数的很好理解!不需要Connection参数时,QueryRunner使用DataSource来获取Connection。如果你没有给QueryRunner指定DataSource,那么你就不能使用不需要Connection的update()和query()方法了。

l  query(Connection on, String sql, ResultSetHandler rsh, Object… params):需要Connection,不会关闭Connection,这说明调用者自己需要关闭Connection;

l  query(String sql, ResultSetHandler rsh, Object… params):不需要Connection,会使用DataSource来获取Connection。如果没有给QueryRunner指定DataSource就会出现异常!会关闭Connection!

l  update(Connection on, String sql, Object… params):需要Connection参数,执行完成后,不会关闭Connection,这说明调用者需要自己来关闭Connection;

l  update(String sql, Object… params):不需要Connection,会使用DataSource来获取Connection,如果没有为QueryRunner指定DataSource,那么调用本方法就会抛出异常。执行结束后会关闭Connection。


QueryRunner qr = new QueryRunner();

String sql = "insert into tab_student values(?,?,?,?)";

Connection con = ...

Object[] params = {...};

qr.update(con, sql, params);

con.close();


DataSource ds = ...

QueryRunner qr = new QueryRunner(ds);

String sql = "insert into tab_student values(?,?,?,?)";

Object[] params = {...};

qr.update(sql, params);

4 QueryRunner之查询

DBUtils为我们提供了一些处理器,即ResultSetHandler的实现类!当然,如果你觉得DBUtils提供的处理器还不够的话,你可以自己再写一些处理器。

l  ArrayHandler:单行处理器!把结果集转换成Object[];

l  ArrayListHandler:多行处理器!把结果集转换成List<Object[]>;

l  MapHandler:单行处理器!把结果集转换成Map<String,Object>,其中列名为键!

l  MapListHandler:多行处理器!把结果集转换成List<Map<String,Object>>;

l  BeanHandler:单行处理器!把结果集转换成Bean,该处理器需要Class参数,即Bean的类型;

l  BeanListHandler:多行处理器!把结果集转换成List<Bean>;

l  ColumnListHandler:多行单列处理器!把结果集转换成List<Object>,使用ColumnListHandler时需要指定某一列的名称或编号,例如:new ColumListHandler(“name”)表示把name列的数据放到List中。

l  KeyedHandler:多行处理器!把结果集转换成Map<Object,Map<String,Object>>。使用KeyedHandler时需要指定主键列名称或编码,例如:new KeyedHandler(“number”)!生成的Map中以主键列的值为键,值还是一个Map,Map表示当前行记录。

l  ScalarHandler:单行单列处理器!把结果集转换成Object。一般用于聚集查询,例如select count(*) from tab_student。


@Test

public void fun1() throws   SQLException {

DataSource ds = JdbcUtils.getDBCPDataSource();

QueryRunner qr = new QueryRunner(ds);

String sql = "select * from tab_student where number=?";

Object[] objs = qr.query(sql, new ArrayHandler(), "S_2000");

System.out.println(Arrays.toString(objs));

}

@Test

public void fun2() throws   SQLException {

DataSource ds = JdbcUtils.getDBCPDataSource();

QueryRunner qr = new QueryRunner(ds);

String sql = "select * from tab_student";

List<Object[]> list =   qr.query(sql, new ArrayListHandler());

for(Object[] objs : list) {

System.out.println(Arrays.toString(objs));

}

}

@Test

public void fun3() throws   SQLException {

DataSource ds = JdbcUtils.getDBCPDataSource();

QueryRunner qr = new QueryRunner(ds);

String sql = "select * from tab_student where number=?";

Map<String,Object> map =   qr.query(sql, new MapHandler(), "S_2000");

System.out.println(map);

}

@Test

public void fun4() throws   SQLException {

DataSource ds = JdbcUtils.getDBCPDataSource();

QueryRunner qr = new QueryRunner(ds);

String sql = "select * from tab_student";

List<Map<String,Object>>   list = qr.query(sql, new MapListHandler());

for(Map<String,Object> map : list) {

System.out.println(map);

}

}

@Test

public void fun5() throws   SQLException {

DataSource ds = JdbcUtils.getDBCPDataSource();

QueryRunner qr = new QueryRunner(ds);

String sql = "select * from tab_student where number=?";

Student stu = qr.query(sql, new   BeanHandler<Student>(Student.class), "S_2000");

System.out.println(stu);

}

@Test

public void fun6() throws   SQLException {

DataSource ds = JdbcUtils.getDBCPDataSource();

QueryRunner qr = new QueryRunner(ds);

String sql = "select * from tab_student";

List<Student> list =   qr.query(sql, new BeanListHandler<Student>(Student.class));

for(Student stu : list) {

System.out.println(stu);

}

}

@Test

public void fun7() throws   SQLException {

DataSource ds = JdbcUtils.getDBCPDataSource();

QueryRunner qr = new QueryRunner(ds);

String sql = "select * from tab_student";

List<Object> list = qr.query(sql,   new ColumnListHandler("name"));

for(Object s : list) {

System.out.println(s);

}

}

@Test

public void fun8() throws   SQLException {

DataSource ds = JdbcUtils.getDBCPDataSource();

QueryRunner qr = new QueryRunner(ds);

String sql = "select * from tab_student";

Map<Object,Map<String,Object>>   map = qr.query(sql, new KeyedHandler("number"));

/*与MapListHandler相似,MapListHandler返回的是List<Map>,而KeyedHandler返回的是Map<Object,Map>,其中键为主键列的值,所以在使用KeyedHandler时需要指定主键列名称

*/

for(Map.Entry<Object,Map<String,Object>>   entry : map.entrySet()) {

System.out.println(entry);

}

}

@Test

public void fun9() throws   SQLException {

DataSource ds = JdbcUtils.getDBCPDataSource();

QueryRunner qr = new QueryRunner(ds);

String   sql = "select count(*) from   tab_student";

Number number = (Number)qr.query(sql, new ScalarHandler());

/*

单行单列处理器,一般用于聚合查询,在使用ScalarHandler时可以指定列名,如果不指定,默认为第1列。

*/

int cnt = number.intValue();

/*

对聚合函数的查询结果,有的驱动返回的是Long,有的返回的是BigInteger,所以这里我们把它转换成Number,Number是Long和BigInteger的父类!然后我们再调用Number的intValue()或longValue()方法就OK了。

*/

System.out.println(cnt);

}

5 QueryRunner之批处理

QueryRunner还提供了批处理方法:batch()。

我们更新一行记录时需要指定一个Object[]为参数,如果是批处理,那么就要指定Object[][]为参数了。即多个Object[]就是Object[][]了,其中每个Object[]对应一行记录:


@Test

public void fun10() throws SQLException {

DataSource ds = JdbcUtils.getDBCPDataSource();

QueryRunner qr = new QueryRunner(ds);

String sql = "insert into tab_student values(?,?,?,?)";

Object[][] params = new Object[10][];//表示 要插入10行记录

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

params[i] = new Object[]{"S_300" + i, "name" + i, 30 + i, i%2==0?"男":"女"};

}

qr.batch(sql, params);

//执行批处理

}

时间: 2024-10-30 07:48:16

自定义数据库框架的相关文章

Java Web自定义MVC框架详解 (转)

转自:http://blog.csdn.net/jackfrued/article/details/42774459 最近给学生讲Java Web,希望他们能够在学完这部分内容后自己实现一个MVC框架.但是突然发现百度上能搜索到的靠谱的资料并不是很多,有些只是原理没有代码实现,有些有 代码实现但是对于初学者来说理解起来还是比较困难,于是决定把自己讲自定义MVC框架的内容放在这里分享给大家,不仅仅是代码,也有原理和探讨.内容会比 较长,因为我打算用递增的方式讲解如何写一个自定义MVC框架,重点是前

python -- 自定义web框架

在学习自定义web框架之前我们对什么是web框架需要有个清晰的认识,本质上说,web框架就是一个socket Server. 目前常见的动态网站WEB框架前面有WSGI(eg:Django.Flask...)或者是自己写的SOCKET(Tornado),然后交给URL路由系统处理,然后交给某个函数或某个类,然后在模板(常用jinja2)里拿到模板然后把模板和从数据库取出的数据进行混合组成一个字符串然后返回给用户(python3在发送时要byte编码). 这里对WSGI举例说明一下: WSGI是用

自定义MVC框架之工具类-模型类

截止目前已经改造了5个类: ubuntu:通过封装验证码类库一步步安装php的gd扩展 自定义MVC框架之工具类-分页类的封装 自定义MVC框架之工具类-文件上传类 自定义MVC框架之工具类-图像处理类 这个模型类支持以下功能: >连贯操作,js叫链式操作,连贯操作的函数可以打乱顺序,最后一个函数必须是执行语句的那个函数,如select, delete, update, add等 如 $db->table( 'user' )->where( 'id=1' )->select() 等

Django【二】自定义web框架

自定义web框架 1.准备登录的html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="icon" href="favicon.ico"> </head> <body> <

自定义web框架(django)

Django基础了解知识 HTTP协议(超文本传输协议) HTTP协议 四大特性: 基于TCP/IP之上作用于应用层 基于请求响应 无状态 引申出cookie session token-- 无连接 长连接 websocket (HTTP协议的大补丁) 数据格式: 请求格式 请求首行(请求方式,协议版本等等) 请求头(一大堆K:V键值对) \r\n 或者是\n 总之就是加一个空行 请求体(真正的数据 发post请求的时候才有 如果是get请求不会有) 响应格式 响应首行 响应头 \r\n 或者是

如何自定义MyBatis框架

MyBatis入门到自定义MyBatis框架 第一个 MyBatis 程序(XML配置) 在上一篇中,简单总结了一下原生 JDBC 的一些局限性,同时引出了 MyBatis 这个框架,算较为详细的整理如何搭建 MyBatis 的工作环境 这一篇,我们在开篇,现在搭建好工作环境的基础上,开始我们的第一个例程,但是,简单的让程序跑起来以后,我们却要讲解如何自定义 MyBatis 框架,它的意义是什么呢? 虽然第一个例程虽然比较简单,但是其中有很多点却是容易引起疑惑的,例如为什么用工厂模式后还有构建者

Python自定义web框架、Jinja2

WSGI(Web Server Gateway Interface)是一种规范,它定义了使用python编写的web app与web server之间接口格式,实现web app与web server间的解耦. python标准库提供的独立WSGI服务器称为wsgiref. 标准Web框架 #!/usr/bin/env python #coding:utf-8 from wsgiref.simple_server import make_server def RunServer(environ,

EF之MSSQL分布式部署一:EFContext自定义数据库链接

不废话,上代码: 来源:http://bbs.csdn.net/topics/390823046 原文地址:EF之MSSQL分布式部署一:EFContext自定义数据库链接 /// <summary> /// 得到Entity的连接字符串 /// </summary> /// <param name="edmxFullName">Edmx的包括命名空间的全名称</param> /// <param name="server

浅谈数据库框架,见笑,请多指正

浅谈数据库框架,见笑,请多指正 http://weibo.com/p/1001603724746155003486 一友说"插件式存储又割裂了SQL引擎的完整逻辑...总体而言在现有框架下MySQL的优化器没有多大改进的价值". 我们且做个技术分析: 1 插件式框架,可以静态/动态加载组件,方便在同类不同属家的模块间切换,这种设计是良好的. 很多软件的设计都采用了"微内核+插件"这样的方式构筑了强大的应用.如Ecplise生态圈. 2 数据库范围内, MySQL的属