MySQL数据库学习笔记(十一)----DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介:

【正文】

一、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,最终的工程文件结构如下:

ffbb2b6e-8d0d-4d4b-9b46-0283ee06a254

  • 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的工具类。以后如果要用的话,可以直接在主方法里调用这个类就行了。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3月前
|
存储 SQL 关系型数据库
Mysql学习笔记(二):数据库命令行代码总结
这篇文章是关于MySQL数据库命令行操作的总结,包括登录、退出、查看时间与版本、数据库和数据表的基本操作(如创建、删除、查看)、数据的增删改查等。它还涉及了如何通过SQL语句进行条件查询、模糊查询、范围查询和限制查询,以及如何进行表结构的修改。这些内容对于初学者来说非常实用,是学习MySQL数据库管理的基础。
166 6
|
22天前
|
SQL Java 数据库连接
JDBC编程安装———通过代码操控数据库
本文,教你从0开始学习JBCD,包括驱动包的下载安装调试设置,以及java是如何通过JBDC实现对数据库的操作,以及代码的分析,超级详细
|
3月前
|
SQL 关系型数据库 MySQL
Mysql学习笔记(三):fetchone(), fetchmany(), fetchall()详细总结
MySQL中用于数据检索的`fetchone()`, `fetchmany()`, `fetchall()`函数的功能、SQL语句示例和应用场景。
109 3
Mysql学习笔记(三):fetchone(), fetchmany(), fetchall()详细总结
|
3月前
|
SQL Ubuntu 关系型数据库
Mysql学习笔记(一):数据库详细介绍以及Navicat简单使用
本文为MySQL学习笔记,介绍了数据库的基本概念,包括行、列、主键等,并解释了C/S和B/S架构以及SQL语言的分类。接着,指导如何在Windows和Ubuntu系统上安装MySQL,并提供了启动、停止和重启服务的命令。文章还涵盖了Navicat的使用,包括安装、登录和新建表格等步骤。最后,介绍了MySQL中的数据类型和字段约束,如主键、外键、非空和唯一等。
87 3
Mysql学习笔记(一):数据库详细介绍以及Navicat简单使用
|
3月前
|
Java 关系型数据库 MySQL
mysql5.7 jdbc驱动
遵循上述步骤,即可在Java项目中高效地集成MySQL 5.7 JDBC驱动,实现数据库的访问与管理。
680 1
|
3月前
|
关系型数据库 MySQL 数据库
Mysql学习笔记(四):Python与Mysql交互--实现增删改查
如何使用Python与MySQL数据库进行交互,实现增删改查等基本操作的教程。
80 1
|
3月前
|
SQL druid Java
JDBC和数据库连接池-两个工具类-JDBCUtilsByDruid和BasicDAO
JDBC和数据库连接池-两个工具类-JDBCUtilsByDruid和BasicDAO
154 0
|
25天前
|
存储 Oracle 关系型数据库
数据库传奇:MySQL创世之父的两千金My、Maria
《数据库传奇:MySQL创世之父的两千金My、Maria》介绍了MySQL的发展历程及其分支MariaDB。MySQL由Michael Widenius等人于1994年创建,现归Oracle所有,广泛应用于阿里巴巴、腾讯等企业。2009年,Widenius因担心Oracle收购影响MySQL的开源性,创建了MariaDB,提供额外功能和改进。维基百科、Google等已逐步替换为MariaDB,以确保更好的性能和社区支持。掌握MariaDB作为备用方案,对未来发展至关重要。
55 3
|
25天前
|
安全 关系型数据库 MySQL
MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!
《MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!》介绍了MySQL中的三种关键日志:二进制日志(Binary Log)、重做日志(Redo Log)和撤销日志(Undo Log)。这些日志确保了数据库的ACID特性,即原子性、一致性、隔离性和持久性。Redo Log记录数据页的物理修改,保证事务持久性;Undo Log记录事务的逆操作,支持回滚和多版本并发控制(MVCC)。文章还详细对比了InnoDB和MyISAM存储引擎在事务支持、锁定机制、并发性等方面的差异,强调了InnoDB在高并发和事务处理中的优势。通过这些机制,MySQL能够在事务执行、崩溃和恢复过程中保持
61 3
|
25天前
|
SQL 关系型数据库 MySQL
数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog
《数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog》介绍了如何利用MySQL的二进制日志(Binlog)恢复误删除的数据。主要内容包括: 1. **启用二进制日志**:在`my.cnf`中配置`log-bin`并重启MySQL服务。 2. **查看二进制日志文件**:使用`SHOW VARIABLES LIKE &#39;log_%&#39;;`和`SHOW MASTER STATUS;`命令获取当前日志文件及位置。 3. **创建数据备份**:确保在恢复前已有备份,以防意外。 4. **导出二进制日志为SQL语句**:使用`mysqlbinlog`
81 2