JDBC 编程
DAO设计
没有使用DAO存在的问题:多个地方都要都同时做CRUD操作时,重复的代码就会很多。

DAO:Data Access Object(数据存取对象)。
位于业务逻辑和持久化数据之间,实现对持久化数据的访问。

ORM
对象关系映射:
将关系数据库中表中的记录映射成为对象,以对象的形式展现。因此ORM的目的是为了方便开发人员以面向对象的思想来实现对数据库的操作。
对应关系:

示意图:

domain
domain 就是一个符合JavaBean规范(一个类当中有字段和该字段的getter与Setter方法)的类。
作用:是用户与数据库交互的核心中转站。
示例:创建一个domain类
public class Student {
    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设计规范
编写DAO组件
- 定义DAO接口 
- 编写对应DAO实现类 
为什么要定义接口
- 接口就是只给出了函数声明,但是是没有函数体类。函数体在实现类中给出。
- 面向接口编程
- 根据客户提出的需求,定义接口,业务具体实现是通过实现类来完成。
- 当客户提出新的需求,只需要编写该业务逻辑新的实现类。
- 好处
- 业务逻辑更加清晰
- 增强代码的扩展性,可维护性
- 接口和实现相分离,适合团队协作开发
- 降低耦合度。便于以后升级扩展
 
 
包名的规范
整体规范:域名倒写.模块名称.组件名称。
DAO包规范:
- package com.jdbc.domain:存储所有的domain
- page com.jdbc.dao:存储所有的dao接口
- page com.jdbc.dao.impl:存储所有的Dao接口实现类
- page com.jdbc.dao.test:存储Dao组件的测试类
类名规范:
- domain类:存储在domain包中。用于描述一个对象,是一个javaBean,写时要见名知意。 
- dao接口:存储在dao包中,用于表示某一个对象的CRUD声明。 - 起名规范:IDomainDao ,即 :接口-domain-dao 
- dao实现类:存储到dao.impl包中,用于表示DAO接口的实现类,要实现DAO接口。 - 起名规范:DomainDAOImpl ,即:domain-dao-impl 
DAO代码优化
- 每一个DAO方法当中都会写驱动名称、url、用户名、密码 - 把公共的这些声明为成员变量,在一个类当中能够共享这些成员变量  
- 每个DAO当中都会相同的4行代码。 - 抽取到一个公共类JdbcUtil当中。  
- 每个dao方法每次操作只需要connection对象,至于是怎么样创建的不关心。 - 把创建Connection代码抽取到jdbcUtil当中,并提供一个getConn就能够获得连接对象。  
- 每次调用getConn就会创建一个Connection对象,但不需要每次都注册驱动。 - 把加载驱动放到静态代码块当中,只会在类被加载到JVM时,才会执行一次。  
- 每个dao方法都要关闭资源 - 在util当中提供一个方法专门关闭资源,在方法当中传入要关闭哪些资源。  
- DAO方法中,拼接SQL太麻烦。 - 要使用预编译语句对象。 
- DAO方法当中每次都创建一个connection对象,用完就关闭了,创建Connection成本很大。 - 通过数据库连接池来解决。 
- jdbcUtil当中的用户名,密码这些信息都写到了文件当中,不便于维护。 - 给写到一个单独的配置文件当中。 
DAO代码重构
在DAO当中执行的保存方法,更新方法,删除这些DML操作有太多重复代码。
重构代码原则
- 同一个类中:在一个类当中有多个方法当中有太多相同的代码,不同的地方通过参数传递进去,把它们抽到一个方法当中。
- 不同类中:不同类当中有共同的代码给抽取到一个新类当中。大家同时共享该类中的内容。
抽取DML方法
设计一个方法,要求传入两个参数,第一个参数为sql语句模板,第二个参数为可变参数,设置语句参数值。返回值为int,为受影响的行数。
DAO重构示意图

调用示意图

public static int executeUpdate(String sql, Object... params) {
    try (Connection c = DBUtil.getConnection(); PreparedStatement ps = c.prepareStatement(sql)) {
        // 遍历参数
        for (int i = 0; i < params.length; i++) {
            ps.setObject(i + 1, params[i]);
        }
        // 执行语句
        return ps.executeUpdate();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return 0;
}
抽取DQL方法
规定:
- 表中的列名必须和对象中的属性名相同
- 规定表中的类型必须和Java中的类型匹配
想要完成此项工作,就要使用内省机制。
步骤:
- 创建一个类实现结果集处理器,实现的时候也不知道是什么类型,所以也可以指定为一个泛型。
- 提供一个字段,表示要封装成对象的类型。
- 提供一个构造器,在创建时,就指定是什么类型。
- 在实现方法当中,通过内省机制获取所有属性名称,做为列名。
- 通过传入的类字节码创建对象。
- 通过内省获取字节码中所有的信息。
- 获取所有的属性描述器。
- 遍历属性描述器,获取对象的属性名称 ,规定的属性名和列名相同。
- 通过列名获取结果集中的值。
- 调用属性的set方法把属性的值设置进去。
public interface IResultSetHandler<T> {
    T handle(ResultSet rs) throws Exception;
}
public class BeanHandler<T> implements IResultSetHandler<T> {
    private Class<T> classType;
    public BeanHandler(Class<T> classType) {
        this.classType = classType;
    }
    @Override
    public T handle(ResultSet rs) throws Exception {
        if (rs.next()) {
            // 创建一个对象
            T obj = this.classType.newInstance();
            // 通过内省来拿属性 , Object.class
            BeanInfo bf = Introspector.getBeanInfo(this.classType, Object.class);
            // 获取所有属性描述器
            PropertyDescriptor[] pds = bf.getPropertyDescriptors();
            // 遍历每一个属性的描述 器
            for (PropertyDescriptor pd : pds) {
                if(pd.getName().equals("anonymousName"))
                    continue;
                Object val = rs.getObject(pd.getName());
                // 给对象设置属性值
                pd.getWriteMethod().invoke(obj, val);
            }
            return obj;
        }
        return null;
    }
}
public class BeanListHandler<T> implements IResultSetHandler<List<T>> {
    private Class<T> classType;
    public BeanListHandler(Class<T> classType) {
        this.classType = classType;
    }
    @Override
    public List<T> handle(ResultSet rs) throws Exception {
        List<T> list = new ArrayList<>();
        while (rs.next()) {
            // 创建一个对象
            T obj = this.classType.newInstance();
            // 通过内省来拿属性
            BeanInfo bf = Introspector.getBeanInfo(this.classType, Object.class);
            // 获取所有属性描述器
            PropertyDescriptor[] pds = bf.getPropertyDescriptors();
            // 遍历每一个属性的描述 器
            for (PropertyDescriptor pd : pds) {
                if(pd.getName().equals("anonymousName"))
                    continue;
                Object val = rs.getObject(pd.getName());
                // 给对象设置属性值
                pd.getWriteMethod().invoke(obj, val);
            }
            // 把对象存放 到集合当中
            list.add(obj);
        }
        return list;
    }
}
public class BeanCountHander implements IResultSetHandler<Integer> {
    @Override
    public Integer handle(ResultSet rs) throws Exception {
        if (rs.next()) {
            return rs.getInt("count");
        }
        return 0;
    }
}
public static <T> T executeQuery(String sql, IResultSetHandler<T> rh, Object... params) {
    ResultSet rs = null;
    try (Connection c = DBUtil.getConnection(); PreparedStatement ps = c.prepareStatement(sql)) {
        // 遍历参数
        for (int i = 0; i < params.length; i++) {
            ps.setObject(i + 1, params[i]);
        }
        // 执行语句
        rs = ps.executeQuery();
        return rh.handle(rs);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        DBUtil.close(null, null, rs);
    }
    return null;
}
开发步骤
- 创建表
- 建立domain包和domain类
- 建立dao包和dao接口
- 建立dao.impl包和dao实现类
- 根据dao接口创建dao测试类
- 编写实现类当中dao的声明的方法体
- 每编写一个dao方法,进行测试功能是否正确
JDBC 编程的更多相关文章
- 单独使用jdbc编程问题总结(一)
		在学习Mybatis之前,我们先来回顾JDBC编程的相关知识.在此基础上深入的学习Mybatis框架.如有错误,敬请指正. (一)首先我们既然要使用jdbc,当然是要操作数据库了.创建一个名为:myb ... 
- 浅谈JDBC编程
		一.概述 1.为什么要用JDBC 数据库是程序不可或缺的一部分,每一个网站和服务器的建设都需要数据库.对于大多数应用程序员(此处不包含数据库开发人员)来说,我们更多的不是在DBMS中对数据库进行操纵, ... 
- 02Mybatis_原生态jdbc编程中的问题总结——从而引生出为什么要用Mybatis
		我们先用jdbc去编写一个例子: 第一步:建表 /* SQLyog v10.2 MySQL - 5.1.72-community : Database - mybatis ************** ... 
- JDBC编程的方式
		JDBC编程的方式,我们以一个简单的查询为例,使用JDBC编程,如下: 从上面可以看出JDBC编程一般要如下步骤: 1. 加载数据库驱动 2. 创建并获取数据库连接 3. 创建jdbc stateme ... 
- JAVA基础知识之JDBC——编程步骤及执行SQL
		JDBC编程步骤 下面以mysql数据库为例, 1.加载驱动 首先需要下载数据库的驱动jar文件,并且在eclipse包中加入到class path中去, 例如mysql的驱动文件 mysql-con ... 
- JDBC编程 之 增删改查
		JDBC编程之数据增加,更改,查询,删除 package com.good.jdbc; import java.sql.Connection; import java.sql.DriverManage ... 
- JDBC编程步骤
		JDBC编程步骤 加载数据库驱动. 通常使用Class类的forName()静态方法来加载驱动. Class.forName(driverClass) dirverClass: mysql---Cla ... 
- 【Java】JDBC编程套路
		转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/5847020.html 学习Java开发,一个必须掌握的知识点,就是数据库操作.当程序需要用到的数据达到一定程度 ... 
- 用JDBC编程的执行时错误及其解决大全
		用JDBC编程的执行时错误及其解决 用JDBC编程的执行时错误及其解决 源码: .java.lang.ClassNotFoundException: com.microsoft.jdbc.sqlser ... 
- JDBC编程学习笔记之数据库连接池的实现
		在JDBC编程的时候,获取到一个数据库连接资源是很宝贵的,倘若数据库访问量超大,而数据库连接资源又没能得到及时的释放,就会导致系统的崩溃甚至宕机.造成的损失将会是巨大的.再看有了数据库连接池的JDBC ... 
随机推荐
- ImageView设置边框 以及内部图片居中显示 在AndroidStudio中添加shape.xml文件
			效果如图 边框设置:shape文件 <shape xmlns:android="http://schemas.android.com/apk/res/android"> ... 
- quartz的简介
			1. 介绍 Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源的任务调度框架,是完全由java开发的一个开源的任务日程管理系统,“任务进度管理器”就是一个在预 ... 
- 集合框架源码学习之LinkedList
			0-1. 简介 0-2. 内部结构分析 0-3. LinkedList源码分析 0-3-1. 构造方法 0-3-2. 添加add方法 0-3-3. 根据位置取数据的方法 0-3-4. 根据对象得到索引 ... 
- Laravel 5.2 三、中间件、视图与 Blade 模板引擎
			一.中间件 Laravel 的 HTTP 中间件提供了对路由的一层过滤和保护.下面模拟一下用中间件验证后台登录. 1. 创建中间件 cmd 窗口进入项目目录,使用 artisan 命令创建 php a ... 
- tcp窗口机制(写的最简单精炼的文章)
			tcp窗口机制(写的最简单精炼的文章) http://blog.csdn.net/occupy8/article/details/48468445 
- 4.FireDAC组件快照 二
			TFDUpdateSQL 生成添加,删除,修改SQL语句 TFDMetaInfoQuery 查询数据源信息 TFDEventAlerter 负责处理数据库事件通知 使用TFDEventAlerter类 ... 
- 3.FireDAC组件快照
			TFDManager 连接定义和Connect连接管理 TFDConnection 数据库连接组件,支持三种连接方式:1.持久定义(有一个唯一名称和一个配置文件,可以由FDManager管理) 例: ... 
- P4819 [中山市选]杀人游戏
			题目描述 一位冷血的杀手潜入Na-wiat,并假装成平民.警察希望能在NN个人里面,查出谁是杀手.警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人,谁是杀手,谁是平民.假如查 ... 
- 【python】日志系统
			来源: http://blog.csdn.net/wykgf/article/details/11576721 http://www.jb51.net/article/42626.htm http:/ ... 
- python math模块
			import math math. ceil:取大于等于x的最小的整数值,如果x是一个整数,则返回x copysign:把y的正负号加到x前面,可以使用0 cos:求x的余弦,x必须是弧度 degre ... 
