一、DAO模式简介
DAO即Data Access Object,数据访问接口。数据访问:故名思义就是与数据库打交道。夹在业务逻辑与数据库资源中间。
DAO模式实际上是两个模式的组合,即Data Accessor (数据访问者)模式和 Active Domain Object(领域对象)模式。Data Accessor 模式实现了数据访问和业务逻辑的分离;Active Domain Object 模式实现了业务数据的对象化封装。
需要注意的是,DAO设计模式是Java EE中的设计模式,而非Java SE中的23种设计模式。
二、实现DAO模式
一个典型的DAO实现有下列几个组件:
- 一个DAO接口;
- 一个实现DAO接口的具体类;
- 数据传递对象(DTO):有些时候叫做值对象(VO)或领域模型(domain)
这种实现模式就是一个套路,记熟就好了。不过在这之前,如果有不明白的地方,还是要回顾一下之前几篇博文中的知识:PreparedStatement接口重构增删改查、封装JDBC工具类。好了,下面直接上代码。
三、代码实现
我们一下面的这张数据表为例:
新建Java工程文件DaoTest01,最终的工程文件结构如下:
- DBUtils:初步封装的JDBC工具类;
- db-config.properties:属性文件,方便修改配置信息;
- Person类就是领域模型,表示是对它(数据库表)进行增删改查。
- PersonDao接口:专门对Person类进行操作(例如增删改查)的接口。注:这里不直接写操作类,是因为接口利于维护,可以在这里写上公共的代码。一个领域模型对应一个Dao接口。
- PeronDaoImpl类:实现上面的PeronDao接口
步骤如下:
注:第(1)、(2)步操作和上一篇博文是一模一样的,这里只是为了保证本篇文章的完整性,所以重新写一下。
(1)先新建一个DBUtils工具类:(package com.util.db)
1 package com.util.db;
2
3 import java.sql.Connection;
4 import java.sql.DriverManager;
5 import java.sql.ResultSet;
6 import java.sql.SQLException;
7 import java.sql.Statement;
8 import java.util.ResourceBundle;
9
10 /**
11 * 数据库操作工具类
12 * @author lamp
13 *
14 */
15 public class DBUtils {
16
17 //数据库连接地址
18 public static String URL;
19 //用户名
20 public static String USERNAME;
21 //密码
22 public static String PASSWORD;
23 //mysql的驱动类
24 public static String DRIVER;
25
26 private static ResourceBundle rb = ResourceBundle.getBundle("com.util.db.db-config");
27
28 private DBUtils(){}
29
30 //使用静态块加载驱动程序
31 static{
32 URL = rb.getString("jdbc.url");
33 USERNAME = rb.getString("jdbc.username");
34 PASSWORD = rb.getString("jdbc.password");
35 DRIVER = rb.getString("jdbc.driver");
36 try {
37 Class.forName(DRIVER);
38 } catch (ClassNotFoundException e) {
39 e.printStackTrace();
40 }
41 }
42 //定义一个获取数据库连接的方法
43 public static Connection getConnection(){
44 Connection conn = null;
45 try {
46 conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
47 } catch (SQLException e) {
48 e.printStackTrace();
49 System.out.println("获取连接失败");
50 }
51 return conn;
52 }
53
54 /**
55 * 关闭数据库连接
56 * @param rs
57 * @param stat
58 * @param conn
59 */
60 public static void close(ResultSet rs,Statement stat,Connection conn){
61 try {
62 if(rs!=null)rs.close();
63 if(stat!=null)stat.close();
64 if(conn!=null)conn.close();
65 } catch (SQLException e) {
66 e.printStackTrace();
67 }
68 }
69
70 }
注意:26行中,注意获取属性文件的包名是否正确。稍后会定义这个属性文件。
28行:既然是工具类,一般不要实例化,此时可以采用单例设计模式,或者将构造方法私有化。
26行:很明显可以看到,我们是将连接数据库的URL、用户名,密码等信息编写在一个属性文件(jdbc.properties)中,稍后再来定义这个属性文件。
31行:为避免重复代码,使用静态代码块:只会在类加载的时候执行一次。
42行:定义一个获取数据库连接的方法
60行:关闭数据库连接
(2)接下来新建一个属性文件,new-->file,命名为:db-config.properties,代码如下:
jdbc.url=jdbc:mysql://localhost:3306/jdbcdb
jdbc.username=root
jdbc.password=smyh
jdbc.driver=com.mysql.jdbc.Driver
以后如果需要修改配置信息,只需要在这里改就行了。注意在上面的DBUtils类中是怎么来调用这个配置信息的。
紧接着新建文件,定义好Person类:(package com.vae.domain)
1 package com.vae.domain;
2
3 public class Person {
4 private int id;
5 private String name;
6 private int age;
7 private String description;
8 public int getId() {
9 return id;
10 }
11 public void setId(int id) {
12 this.id = id;
13 }
14 public String getName() {
15 return name;
16 }
17 public void setName(String name) {
18 this.name = name;
19 }
20 public int getAge() {
21 return age;
22 }
23 public void setAge(int age) {
24 this.age = age;
25 }
26 public String getDescription() {
27 return description;
28 }
29 public void setDescription(String description) {
30 this.description = description;
31 }
32 public Person(int id, String name, int age, String description) {
33 super();
34 this.id = id;
35 this.name = name;
36 this.age = age;
37 this.description = description;
38 }
39 public Person(String name, int age, String description) {
40 super();
41 this.name = name;
42 this.age = age;
43 this.description = description;
44 }
45 public Person() {
46 super();
47 // TODO Auto-generated constructor stub
48 }
49 @Override
50 public String toString() {
51 return "Person [id=" + id + ", name=" + name + ", age=" + age
52 + ", description=" + description + "]";
53 }
54
55
56 }
这个Person类就是领域模型,表示是对它进行增删改查。
(3)定义PersonDao接口:专门对Person类进行操作(例如增删改查)的接口(package com.vae.dao)
package com.vae.dao;
import java.sql.SQLException;
import java.util.List;
import com.vae.domain.Person;
public interface PersonDao {
//添加方法
public void add(Person p)throws SQLException;
//更新方法
public void update(Person p)throws SQLException;
//删除方法
public void delete(int id)throws SQLException;
//查找方法
public Person findById(int id)throws SQLException;
//查找所有
public List<Person> findAll()throws SQLException;
}
(4)定义PeronDaoImpl实现类 ,实现上面的PeronDao接口(package com.vae.dao.impl)
1 package com.vae.dao.impl;
2
3 import java.sql.Connection;
4 import java.sql.PreparedStatement;
5 import java.sql.ResultSet;
6 import java.sql.SQLException;
7 import java.util.ArrayList;
8 import java.util.List;
9
10 import com.util.db.DBUtils;
11 import com.vae.dao.PersonDao;
12 import com.vae.domain.Person;
13
14 /**
15 * PersonDao的具体实现类
16 * @author lamp
17 *
18 */
19 public class PersonDaoImpl implements PersonDao{
20
21 /**
22 * 实现添加方法
23 */
24 @Override
25 public void add(Person p) throws SQLException {
26 Connection conn = null;
27 PreparedStatement ps = null;
28 String sql = "insert into person(name,age,description)values(?,?,?)";
29 try{
30 conn = DBUtils.getConnection();
31 ps = conn.prepareStatement(sql);
32 ps.setString(1, p.getName());
33 ps.setInt(2, p.getAge());
34 ps.setString(3, p.getDescription());
35 ps.executeUpdate();
36 }catch(SQLException e){
37 e.printStackTrace();
38 throw new SQLException("添加数据失败");
39 }finally{
40 DBUtils.close(null, ps, conn);
41 }
42 }
43
44 /**
45 * 更新方法
46 */
47 @Override
48 public void update(Person p) throws SQLException {
49 Connection conn = null;
50 PreparedStatement ps = null;
51 String sql = "update person set name=?,age=?,description=? where id=?";
52 try{
53 conn = DBUtils.getConnection();
54 ps = conn.prepareStatement(sql);
55 ps.setString(1, p.getName());
56 ps.setInt(2, p.getAge());
57 ps.setString(3, p.getDescription());
58 ps.setInt(4, p.getId());
59 ps.executeUpdate();
60 }catch(SQLException e){
61 e.printStackTrace();
62 throw new SQLException("更新数据失败");
63 }finally{
64 DBUtils.close(null, ps, conn);
65 }
66 }
67
68 /**
69 * 删除方法
70 */
71 @Override
72 public void delete(int id) throws SQLException {
73 Connection conn = null;
74 PreparedStatement ps = null;
75 String sql = "delete from person where id=?";
76 try{
77 conn = DBUtils.getConnection();
78 ps = conn.prepareStatement(sql);
79 ps.setInt(1,id);
80 ps.executeUpdate();
81 }catch(SQLException e){
82 e.printStackTrace();
83 throw new SQLException(" 删除数据失败");
84 }finally{
85 DBUtils.close(null, ps, conn);
86 }
87 }
88
89 /**
90 * 根据ID查询一个对象
91 */
92 @Override
93 public Person findById(int id) throws SQLException {
94 Connection conn = null;
95 PreparedStatement ps = null;
96 ResultSet rs = null;
97 Person p = null;
98 String sql = "select name,age,description from person where id=?";
99 try{
100 conn = DBUtils.getConnection();
101 ps = conn.prepareStatement(sql);
102 ps.setInt(1, id);
103 rs = ps.executeQuery();
104 if(rs.next()){
105 p = new Person();
106 p.setId(id);
107 p.setName(rs.getString(1));
108 p.setAge(rs.getInt(2));
109 p.setDescription(rs.getString(3));
110 }
111 }catch(SQLException e){
112 e.printStackTrace();
113 throw new SQLException("根据ID查询数据失败");
114 }finally{
115 DBUtils.close(rs, ps, conn);
116 }
117 return p;
118 }
119
120 /**
121 * 查询所有数据
122 */
123 @Override
124 public List<Person> findAll() throws SQLException {
125 Connection conn = null;
126 PreparedStatement ps = null;
127 ResultSet rs = null;
128 Person p = null;
129 List<Person> persons = new ArrayList<Person>();
130 String sql = "select id,name,age,description from person";
131 try{
132 conn = DBUtils.getConnection();
133 ps = conn.prepareStatement(sql);
134 rs = ps.executeQuery();
135 while(rs.next()){
136 p = new Person();
137 p.setId(rs.getInt(1));
138 p.setName(rs.getString(2));
139 p.setAge(rs.getInt(3));
140 p.setDescription(rs.getString(4));
141 persons.add(p);
142 }
143 }catch(SQLException e){
144 e.printStackTrace();
145 throw new SQLException("查询所有数据失败");
146 }finally{
147 DBUtils.close(rs, ps, conn);
148 }
149 return persons;
150 }
151
152 }
我们在各自的增删改查里都抛出了异常,如果出现异常,就会抛出相应的错误信息。
总结:这样的话,我们就封装好了JDBC的工具类。以后如果要用的话,可以直接在主方法里调用这个类就行了。
【工程文件】
链接:http://pan.baidu.com/s/1qW6tew8
密码:t98s