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 ...
随机推荐
- bzoj 1036: [ZJOI2008]树的统计Count——树链剖分
Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. Q ...
- HDU 1728 逃离迷宫 (广搜)
题目链接 Problem Description 给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可 ...
- HDU 2899 三分
我们对这个函数求二阶导数,发现他的二阶导数是恒大于0的,那么他的导数是单调的,且在某时刻为0,那么这时的x值就是极值处的x值,其实题目说了,有最小值,那么我们三分水过去就好了. 反思:精度不够,因为是 ...
- CSS3禁止网页中文本被选中代码
通常大家会有js来实现,另一个方案就是,将-webkit-user-select 和-moz-user-select 的值设为none,这针对于移动用户,可能会很有用.请谨慎使用这个属性:因为大部分用 ...
- Coursera在线学习---第八节.K-means聚类算法与主成分分析(PCA)
一.K-means聚类中心初始化问题. 1)随机初始化各个簇类的中心,进行迭代,直到收敛,并计算代价函数J. 如果k=2~10,可以进行上述步骤100次,并分别计算代价函数J,选取J值最小的一种聚类情 ...
- Linux内核中链表的实现与应用【转】
转自:http://blog.chinaunix.net/uid-27037833-id-3237153.html 链表(循环双向链表)是Linux内核中最简单.最常用的一种数据结构. ...
- iOS 适配/ autoLayout基本知识
历史 iPhone3GS.iPhone4\4s:没有屏幕适配最早开发里面的程序全部都是写死的 iPad 旋转出来之后 Autoresizing问世iPhone5\5c\5s兼容各种不同的情况 系统适配 ...
- 3.4Code
#include<algorithm> #include<iostream> #include<cstdio> #define inf 0x3f3f3f3f #de ...
- java常用设计模式学习心得
学习自:http://shenzhenchufa.blog.51cto.com/730213/161581 代码来自:http://shenzhenchufa.blog.51cto.com/73021 ...
- hihocoder 1178 : 计数
#1178 : 计数 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Rowdark是一个邪恶的魔法师.在他阅读大巫术师Lich的传记时,他发现一类黑魔法来召唤远古生物, ...