JDBC中的DAO设计模式------Data Access Object(数据访问对象)

1.DAO简介

  • 什么是DAO?

DAO即Data Access Object, 是用来访问数据信息的类. 包含了对数据的 CRUD(即create,read,update,delete) 操作. 而不包含任何业务相关的信息.

DAO其实就是对一些常用的 JDBC 方法的封装(就像之前写的JDBC工具类, 也有不同的地方).

  • DAO的意义?

为了实现代码功能的模块化, 更有利于代码的维护与升级.

  • DAO要实现哪些数据相关操作的方法?

若是要处理一些事务的操作, 下列方法还应该在最前面添加一个数据库连接Connection参数

  1. void update(String sql, Object … args);
    执行对数据库的 Insert Update Delete 操作
  2. <T> T get(Class<T> clazz, String sql, Object … args);
    查询一条记录, 返回对应的JavaBean对象
  3. <T> List<T> getForList(Class<T> clazz, String sql, Object … args);
    查询多条记录, 返回对应对象的集合
  4. <E> E getForValue(String sql, Object … args);
    返回某一条记录的某一个字段的值 或 一个统计的值(即聚集函数的结果)

2.beanutils工具类

beanutils工具类是Apache的产品之一, 是一个用来操作JavaBean对象的开源jar. 回想之前, 我们是用的 Java 原始的反射机制来操作的JavaBean对象.

JavaBean: 是一个特殊的 Java 类, 类必须是具体的和公共的, 并且具有无参数的构造器, 通过提供的公共方法(即setter和getter方法)来操作成员变量.

Java 类的属性:

① 在 JavaEE 开发中, Java类的属性通过类的 getter(或setter) 方法来定义, 即去除方法 get(或set), 将之后字母的首字母小写, 即为 Java 类的属性.例: public String getIdCard(); 所代表的属性是 idCard.

② 而之前我们常说的属性(即类的成员变量), 这里称之为字段.

③ 注意, 我们写的时候, 字段一般都与属性一一对应; 当然, 也会有不对应的情况.

和之前用 JDBC 驱动时一样, 要将 commons-beanutils-1.9.3.jar和commons-logging-1.2.jar 两个 jar包添加到当前项目的 “构建路径”.

JDBC_13

步骤: ①没有 lib 目录的在当前项目下新建目录 lib,将要添加的 jar 包放在里面.

②在想要添加的 jar 上右键单击, 之后单击 “构建路径”(即 “Build Path”)

③之后再单击 “添加至构建路径” 即 “Add to Build Path”

经常用到的两个方法: setProperty() 为JavaBean对象指定属性赋值.

getProperty() 获取 JavaBean 对象的指定属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class TestBeanUtils {
@Test
public void testBeanUtils() throws Exception{
//Student类还是之前写的类
Object obj = new Student();
System.out.println(obj);
BeanUtils.setProperty(obj, "name", "Bob");
System.out.println(obj);
/*输出:
Student [id=0, name=null, email=null, date=null]
Student [id=0, name=Bob, email=null, date=null]
*/
}
}

3.DAO

要学会使用编辑器, 可快速重构代码.

学会将代码模块化, 可将功能性的代码片段抽取成一个方法, 方便维护和管理.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172

import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;

public class DAO {
/**
* 通用的更新方法,包括: Insert Delete Update
* @param sql
* @param args
*/
public void update(String sql, Object ... args) {
Connection conn = null;
PreparedStatement psmt = null;
try {
//1. 获取数据库连接
conn = JDBCTools.getConnection();
psmt = conn.prepareStatement(sql);
for(int i = 0;i < args.length;i ++) {
psmt.setObject(i+1, args[i]);
}
//2. 执行 SQL语句
psmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCTools.release(null, psmt, conn);
}
}
/**
* 通用的查询方法,SQL为select类型.
* 查询结果最多是一行记录.
* @param clazz
* @param sql
* @param args
* @return
*/
public <T> T get(Class<T> clazz, String sql, Object ... args) {
List<T> list = getForList(clazz, sql, args);
if(list.size()>0) {
return list.get(0);
}
return null;
}
/**
* 通用的查询方法,SQL为select类型.
* 查询结果可以为多行记录(0~n).
* @param clazz
* @param sql
* @param args
* @return
*/
public <T> List<T> getForList(Class<T> clazz, String sql, Object ... args){
List<T> list = new ArrayList<>();
Connection conn = null;
PreparedStatement psmt = null;
ResultSet rs = null;
try {
conn = JDBCTools.getConnection();
psmt = conn.prepareStatement(sql);
for(int i = 0;i < args.length;i ++) {
psmt.setObject(i+1, args[i]);
}
//1. 获取连接再获取结果集
rs = psmt.executeQuery();
//2. 将结果集转换为Map的List
List<Map<String, Object>> values = handleResultSetToMapList(rs);
//3. 将 Map 的List 转换为 JavaBean 对应的List
list = transferMapListToBeanList(clazz, values);
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
/**
* 查询方法,结果为一行中的一列
* @param sql
* @param args
* @return
*/
@SuppressWarnings("unchecked")
public <E> E getForValue(String sql, Object ... args) {
Connection conn = null;
PreparedStatement psmt = null;
ResultSet rs = null;
try {
conn = JDBCTools.getConnection();
psmt = conn.prepareStatement(sql);
for(int i = 0;i < args.length;i ++) {
psmt.setObject(i+1, args[i]);
}
rs = psmt.executeQuery();
if(rs.next()) {
return (E)rs.getObject(1);
}
} catch(Exception ex) {
ex.printStackTrace();
}finally {
JDBCTools.release(rs, psmt, conn);
}
return null;
}
/**
* 获取结果集的 ColumnLabel 对应的 List
* @param rs
* @return
* @throws Exception
*/
private List<String> getColumnLabels(ResultSet rs) throws SQLException{
List<String> labels = new ArrayList<>();
ResultSetMetaData rsmd = rs.getMetaData();
for(int i = 0;i < rsmd.getColumnCount();i++) {
labels.add(rsmd.getColumnLabel(i+1));
}
return labels;
}
/**
* 处理结果集得到一个 Map 的List, 其中一个 Map 代表一个记录.
* @param rs
* @return
* @throws Exception
*/
private List<Map<String, Object>> handleResultSetToMapList(ResultSet rs) throws SQLException{
List<String> labels = this.getColumnLabels(rs);
List<Map<String,Object>> values = new ArrayList<>();
Map<String,Object> map = null;
while(rs.next()){
map = new HashMap<>();
for(String key :labels) {
Object value = rs.getObject(key);
map.put(key, value);
}
values.add(map);
}
return values;
}
/**
* 将 Map 的 List 转换为 JavaBean对象的 List
* @param clazz
* @param values
* @return
* @throws InstantiationException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
private <T> List<T> transferMapListToBeanList(Class<T> clazz, List<Map<String, Object>> values)
throws InstantiationException, IllegalAccessException, InvocationTargetException {
List<T> list = new ArrayList<>();
T bean = null;
if(values.size()>0) {
for(Map<String,Object> m:values) {
bean = clazz.newInstance();
for(Map.Entry<String, Object> entry:m.entrySet()) {
String propertyName = entry.getKey();
Object propertyValue = entry.getValue();
BeanUtils.setProperty(bean, propertyName, propertyValue);
}
list.add(bean);
}
}
return list;
}
}

4.TestDAO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

import java.sql.Date;
import java.util.List;
import java.util.Scanner;

import org.junit.Test;

public class DAOTest {
DAO dao = new DAO();
@Test
public void testUpdate() {
Student stu = getStudentFromConsole();
addStudent(stu);
}
private Student getStudentFromConsole() {
Student stu = new Student();
Scanner scanner = new Scanner(System.in);
System.out.print("请输入学生ID:");
stu.setId(scanner.nextInt());
System.out.print("请输入学生Name:");
stu.setName(scanner.next());
System.out.print("请输入学生Email:");
stu.setEmail(scanner.next());
System.out.print("请输入学生Birth:");
stu.setDate(Date.valueOf(scanner.next()));
scanner.close();
return stu;
}
public void addStudent(Student stu) {
String sql = "INSERT INTO Student VALUES(?,?,?,?)";
dao.update(sql,stu.getId(),stu.getName(),stu.getEmail(),stu.getDate());
}
@Test
public void testGet() {
String sql = "SELECT id, name, email, birth date FROM Student "
+ "WHERE id = ?";
Student stu = dao.get(Student.class, sql,3);
System.out.println(stu);
}
@Test
public void testGetForList() {
String sql = "SELECT id, name, email, birth date FROM Student";
List<Student> list = dao.getForList(Student.class, sql);
for(Student stu:list) {
System.out.println(stu);
}
}
@Test
public void testGetForValue() {
String sql = "SELECT COUNT(*) FROM Student";
int result = dao.getForValue(sql);
System.out.println(result);
}
}

评论