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 ...
随机推荐
- Bzoj4481 [Jsoi2015]非诚勿扰
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 147 Solved: 75 Description [故事背景] JYY赶上了互联网创业的大潮,为非 ...
- 深入理解微服务架构spring的各个知识点(面试必问知识点)
什么是spring spring是一个开源框架,spring为简化企业级开发而生,使用spring可以使简单的java bean 实现以前只有EJG才能实现的功能. Spring是一个轻量级的控制反转 ...
- Reachability from the Capital(Codeforces Round #490 (Div. 3)+tarjan有向图缩点)
题目链接:http://codeforces.com/contest/999/problem/E 题目: 题意:给你n个城市,m条单向边,问你需要加多少条边才能使得从首都s出发能到达任意一个城市. 思 ...
- Vue 定义组件模板的七种方式(一般用单文件组件更好)
在 Vue 中定义一个组件模板,至少有七种不同的方式(或许还有其它我不知道的方式): 字符串 模板字面量 x-template 内联模板 render 函数 JSF 单文件组件 在这篇文章中,我将通过 ...
- js_一个简单的30分钟循环倒计时
吐槽段: 需求的变更是千变万化的,至少在你说服和你打交道的那位谁谁谁之前. 创业公司就是这样,产品经理一个想法,就是改改改,管你改起来复杂不复杂,在他们眼里都是非常简单的. 今天的一个小改动需求,把活 ...
- php中使用static方法
<?php class Char{ public static $number = 0; public static $name; function __construct($what){ se ...
- deepin安装metasploit
[1]安装metasploit 1.curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/tem ...
- python基础===创建大量对象是节省内存方法
问题: 你的程序要创建大量(可能上百万) 的对象,导致占用很大的内存. 解决方案: 对于主要是用来当成简单的数据结构的类而言,你可以通过给类添加__slots__属性来极大的减少实例所占的内存.比如: ...
- Redis 分片实现 Redis Shard [www]
Redis 分片实现 Redis Shard https://www.oschina.net/p/redis-s ...
- php常见术语
什么是PHP? php是Hypertext Preprocessor的缩写,php是一种内嵌 HTML的脚本语言.PHP的独特语法混合了c,java和perl及PHP式的新语法.这门语言的的目标是让网 ...