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 ...
随机推荐
- HTML JS文字闪烁实现(项目top.htm分析)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <!-- saved from ur ...
- linux下删除已经不用的配置文件
使用命令 dpkg -l | grep -v ^ii 查看当前未安装或者不用了的配置文件 例如我的显示如下
- •搭建LAMP环境及快速部署双网站并实现基于域名的虚拟主机
本节所讲内容: 实战:搭建LAMP环境及快速部署双网站并实现基于域名的虚拟主机 LAMP架构:??? Linux+Apache+Mysql+PHP Linux+Apache+Mysql/MariaDB ...
- skb管理函数之skb_clone、pskb_copy、skb_copy
skb_clone--只复制skb描述符本身,如果只修改skb描述符则使用该函数克隆: pskb_copy--复制skb描述符+线性数据区域(包括skb_shared_info),如果需要修改描述符以 ...
- 安全测试===黑客攻击常用cmd命令大全
黑客常用命令大全net user heibai lovechina /add 加一个heibai的用户密码为lovechina net localgroup Administrators heibai ...
- 64_m2
mimetic-devel-0.9.8-7.fc26.i686.rpm 12-Feb-2017 05:40 288474 mimetic-devel-0.9.8-7.fc26.x86_64.rpm 1 ...
- 64_j2
jetty-websocket-server-9.4.3-3.v20170317.fc26.n..> 14-Apr-2017 12:03 62034 jetty-websocket-servle ...
- tcp 在调用connect失败后要不要重新socket
tcp 在调用connect失败后要不要重新socket http://blog.csdn.net/occupy8/article/details/48253251
- 2017多校第7场 HDU 6127 Hard challenge 极角排序,双指针
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6127 题意:平面直角坐标系上有n个整点,第i个点有一个点权val,坐标为(xi,yi),其中不存在任 ...
- HEER-Easing Embedding Learning by Comprehensive Transcription of Heterogeneous Information Networks
来源:KDD 2018 原文:HEER code:https://github.com/GentleZhu/HEER 注: 若有错误,欢迎指正 这篇KDD’18的文章,没有按照常规的方法将所有的n ...