📜 本系列教程适用于JavaWeb初学者、爱好者,小白白。我们的天赋并不高,可贵在努力,坚持不放弃。坚信量最终引发质变,厚积薄发。
🚀 文中白话居多,尽量以小白视角呈现,帮助大家快速入门。
🎅 我是 蜗牛老师,之前网名是 Ongoing蜗牛,人如其名,干啥都慢,所以更新也慢。希望大家多多支持,让我动力十足!
本篇文章我们将初步了解实际的项目开发,了解应用分层,把握项目代码结构。介绍的应用分层也是目前广泛使用的一个结构,本次学习会实现其中的实体层和数据访问层(DAO 层),了解 O/R 映射概念。那么在之后的实际项目中这两层也是必备的基础结构。同时也可以对 JDBC 编程进一步巩固复习。
应用分层其实是一种软件设计模式,它会将一个应用分解为多个层次结构,每个层次结构都自己特定的职责。分层设计模式主要是为了提高代码的可重用性、可维护性和可测试性。
比如一个小型公司和一个中型公司。小公司很多时候都是一个人身兼数职,即负责前台接待,也负责招聘、培训等事项,这就导致业务不专精、效率低下,好处就是节约了成本。那么一个中型公司呢?通常会将不同的职责划分给不同的部门或职位,比如销售部负责销售业务,人力资源部负责招聘、培训等人力资源管理工作。这样可以使得各个部门或职位各司其职,提高工作效率。
生活中很多行为都类似于应用分层,即将一个整体分开,使得各个部分能够各司其职,提高效率和便利性。
对于应用程序来说,也并非一定要分层,但是经过了无数前辈踩坑,总结得出的经验来看,分层的优势更多。接下来就来介绍目前比较流行的分层规范:
以下是各层的简单结构图:

一般是上层依赖于下层,如:请求处理层依赖或调用业务逻辑层,业务逻辑层依赖或调用数据访问层。
通过将应用程序划分为多个层次,每个层次可以独立进行修改和扩展,而不影响其他层次的代码。这种分层设计也有助于提高应用程序的模块化程度,便于团队协同开发和测试。
实体层是定义应用程序中的数据模型,表示应用程序中的各种对象和数据结构。其实我们的应用程序从另一个角度来说就是数据的流转,比如用户输入用户名密码,经过我们的程序最终流转到数据库保存起来,或是我们查看网站的某一页面,也是将数据从数据库取出来,最终流转到页面进行展示。这些数据在程序中就是各种对象和数据结构。
这就不得不提 O/R 映射了。
O/R 映射(Object/Relational Mapping)是一种技术,用于将对象模型与关系模型进行映射,从而将对象持久化到关系数据库中。简单来说,O/R 映射就是将Java程序中的对象自动持久化到关系数据库中。
O/R 映射的目的是解决面向对象与关系数据库存在的互不匹配的现象。它通过描述对象和数据库之间映射的元数据,将对象模型转换为关系模型,以及将关系模型转换为对象模型。
对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。

数据库中的数据要在程序中流转使用,就需要想办法在程序中去表示数据库中的数据。怎么表示呢?O/R 映射。
O/R 映射也就是对象-关系映射,具体操作是将数据库的表映射成程序中的类,表中列映射为类的属性。
具体如何操作呢?这是数据库中的teacher 表。

现在将其映射到程序中的类。

从图上看出 O/R 映射不难,很简单,就是表名变为类名(类名为大驼峰命名法),列变为属性,列名为属性名(小驼峰命名法),同时也要注意数据库数据类型转为对应的程序中数据类型。那我们接来实现该类吧。
首先准备好开发环境,添加了 MySQL 驱动 jar 包,新建了 com.entity 包,entity 是实体的意思,该包就代表实体层,存放我们的实体类,也就是 O/R 映射类。

在 com.entity 包下新建 Teacher 类。
public class Teacher {
/**
* 唯一标识
*/
private Integer id;
/**
* 姓名
*/
private String name;
/**
* 性别
*/
private String sex;
/**
* 年龄
*/
private Integer age;
/**
* 无参构造器
*/
public Teacher() {
}
/**
* 提供setter和getter方法
*/
在 Teacher 类中编写 teacher 表中列的对应属性,一般设置为私有,同时要添加无参构造函数和 setter、getter 方法。(IDEA 中使用 Alt+insert 快捷键快捷生成构造函数和 setter、getter 方法)
这样 O/R 映射类就完成了。之后数据库中的一条数据就可以对应 Java 中的一个对象。
DAO 层是 Data Access Object(数据访问对象)的缩写,DAO 层通常位于业务逻辑层与数据库层之间,主要用于处理与数据库相关的操作,封装对数据库的访问细节,提供简单、统一的接口供上层业务逻辑调用。它主要作用是实现数据访问逻辑与业务逻辑的分离,提高代码的可重用性、可维护性和可测试性。在典型的三层架构中,DAO 层位于持久化层(Persistence Layer)中,负责与数据库进行交互。它通常包含一些数据访问接口(接口定义了访问数据库的方法)和其对应的实现类。通过 DAO 层,应用程序可以通过调用相应的方法来执行数据库操作,如插入数据、更新数据、删除数据、查询数据等。
DAO 层很简单,就是与 MySQL、Oracle、Hbase、OB 等数据库进行交互,目前我们使用 Java 中的 JDBC 去操作数据库,那么就在 DAO 层封装数据库的增删改查操作,同时为了简化 DAO,不使用接口和接口实现的组合,直接一个类搞定。

新建 com.dao 包,包下新建 TeacherDao 类,该类名很好理解吧,表明该类服务于 Teacher。知道了这样的规律后,那么 student 表呢?实体类为 Student,DAO 层为 StudentDao 类。
TeacherDao 类下会封装对 teacher 表的数据库操作,这里编写新增操作和单条记录查询操作。同时为了便于学习入门,不会过渡封装,以免造成代码不易理解和阅读。
直接上代码:
public class TeacherDao {
/**
* 数据库URL
*/
private static final String DB_URL = "jdbc:mysql://127.0.0.1:3306/test_jdbc?serverTimezone=Asia/Shanghai";
/**
* 数据库用户名
*/
private static final String USER = "root";
/**
* 数据库密码
*/
private static final String PASSWORD = "root";
/**
* 获取数据库连接
*
* @return
* @throws ClassNotFoundException
* @throws SQLException
*/
public static Connection getConnection() throws ClassNotFoundException, SQLException {
// 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 获取数据库连接
Connection connection = DriverManager.getConnection(DB_URL, USER, PASSWORD);
return connection;
}
/**
* 关闭结果集、声明、连接等资源
*
* @param rs
* @param pstmt
* @param conn
*/
public static void close(ResultSet rs, PreparedStatement pstmt, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 新增教师信息
*
* @param teacher
* @return
*/
public int executeInsert(Teacher teacher) throws SQLException, ClassNotFoundException {
// 获取数据库连接
Connection connection = getConnection();
// 新增SQL
String sql = "insert into teacher (name, sex, age) value (?, ?, ?)";
// 预编译SQL
PreparedStatement preparedStatement = connection.prepareStatement(sql);
// 设置参数
preparedStatement.setString(1, teacher.getName());
preparedStatement.setString(2, teacher.getSex());
preparedStatement.setInt(3, teacher.getAge());
// 执行SQL
int num = preparedStatement.executeUpdate();
// 关闭资源
close(null, preparedStatement, connection);
return num;
}
/**
* 根据id查询教师信息
*
* @param id
* @return
* @throws SQLException
* @throws ClassNotFoundException
*/
public Teacher executeSelect(int id) throws SQLException, ClassNotFoundException {
// Teacher类实例化,一个Teacher对象来存储一条数据库教师记录
Teacher teacher = new Teacher();
// 获取数据库连接
Connection connection = getConnection();
// 根据ID查询SQL
String sql = "select * from teacher where id = ?";
// 预编译SQL
PreparedStatement preparedStatement = connection.prepareStatement(sql);
// 设置参数
preparedStatement.setInt(1, id);
// 执行SQL
ResultSet resultSet = preparedStatement.executeQuery();
// 处理结果集
while (resultSet.next()){
teacher.setId(resultSet.getInt("id"));
teacher.setName(resultSet.getString("name"));
teacher.setSex(resultSet.getString("sex"));
teacher.setAge(resultSet.getInt("age"));
}
// 关闭资源
close(resultSet, preparedStatement, connection);
return teacher;
}
}
这是一个简单的 Java 类,名为 TeacherDao,它用于与 MySQL 数据库进行交互。
DB_URL、USER、PASSWORD:这三个静态常量分别存储了数据库的URL、用户名和密码。getConnection():这个方法用于获取数据库的连接。它首先加载 MySQL 的 JDBC 驱动程序,然后使用驱动管理器获取数据库连接。close(ResultSet rs, PreparedStatement pstmt, Connection conn):这个方法用于关闭结果集、声明和连接。如果这些对象不为 null,则尝试关闭它们。这是一个良好的编程习惯,可以避免资源泄漏,当然最好放在 finally 块中。executeInsert(Teacher teacher):这个方法接收一个 Teacher 对象,并将其信息插入到数据库中的 teacher 表中。它首先获取数据库连接,然后创建一个预编译的 SQL 语句,该语句使用问号作为占位符来代替实际的值。然后,它使用 PreparedStatement 对象设置实际的值,并执行 SQL 语句。最后,它关闭结果集、声明和连接,并返回执行更新操作的数量。executeSelect(int id):从数据库的 teacher 表中查询并返回具有特定 ID 的 Teacher 对象。首先创建一个新的 Teacher 对象,该对象将用于存储从数据库中检索的教师记录。获取数据库连接。创建一个 SQL 查询字符串,该字符串包含一个占位符(?)。然后使用连接创建一个预编译的 SQL 语句,使用setId()、setName()、setSex() 和 setAge() 方法设置查询结果,并将结果存储在 Teacher 对象中。通过调用 ResultSet 对象的 next() 方法遍历查询结果。每次迭代时,都会从结果集中获取下一个记录,并将其存储在 Teacher 对象中。最后,它关闭结果集、声明和连接,并将含有教师记录的 Teacher 对象进行返回。我们编写测试类:
public class Test {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
TeacherDao teacherDao = new TeacherDao();
// 构造新增的教师信息
Teacher teacher = new Teacher();
teacher.setName("张八一");
teacher.setSex("男");
teacher.setAge(36);
// 将教师信息新增到数据库表中
int num = teacherDao.executeInsert(teacher);
System.out.println("执行影响的记录数:" + num);
// 查询教师的id
int id = 2;
// 根据id查询教师信息
Teacher teacher1 = teacherDao.executeSelect(id);
// 打印教师信息
System.out.println("查询出的数据为:" + teacher1.getName() + "," + teacher1.getSex() + "," + teacher1.getAge());
}
}
执行结果如下:
执行影响的记录数:1
查询出的数据为:李四,男,27
大家可以自行尝试,多多练习,多多测试!
应用分层: 实体层、数据访问层、业务逻辑层、请求处理层
O/R映射: 是指将数据库的表映射成程序中的类,表中列映射为类的属性。
DAO层: 封装对数据库访问的一些操作。