JDBC
背景
我们的应用都是动态运行的,最早就是用于复杂计算领域,你给应用一些入参,应用通过一系列的复杂计算,最终得到结果,返回给使用者。现在的应用也一样,只不过支持的领域比较广,业务更复杂而已。我们都知道应用是需要加载到内存,才能运行。这样的话,当关闭进程,所有的数据都会丢失。所以为了保存数据,出现了数据库技术--主要用于存储数据。
数据库介绍
数据库是“按照数据结构来组织、存储和管理数据的仓库”。是一个长期存储在计算机内的、有组织的、可共享的、统一管理的大量数据的集合。
数据库技术的出现解决了应用数据的存储问题,但随着时间的推移,越来越多的数据库技术出现,例如Oracle、mysql、SqlServer等等,数据库种类变多是一种好的现象,可以让程序员有了跟多的选择,但存在一个问题,他们对外提供的接口各不相同,程序员要想使用不同的数据库,就需要了解对应操作数据库的API,这样就增加了程序员的学习成本,所以作为当时业界老大的SUN公司,就出了一套java语言操作数据库的标准(JDBC)。
这样的好处有哪些?
-
JAVA代码中不会再出现具体某种数据库相关的api,全部面向JDBC规范编程。
-
减轻程序员的学习成本,只需要学习JDBC相关的接口,无需关心底层的具体实现
-
更容易替换数据库
JDBC简介
Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。
JDBC标准相关的类在java.sql
包以及扩展包javax.sql
包下
核心类 | 作用 |
---|---|
DriverManager | 注册驱动,获取Connection |
Connection | 表示一个数据库连接,可以获取Statement对象 |
Statement | 向数据库发送SQL语句 |
ResultSet | 结果集,是一个二维表格 |
使用JDBC操作数据库
示例说明:我们使用典型的web架构的3层架构(表示层、业务逻辑层、数据持久层),这里主要关心的是数据持久层,所以只实现了后面两层。模拟从数据库student
表中查询年龄大于18岁的学生。
-
源码仓库
-
分支study/mybatis-3.5.6
-
具体请参考readme文档
DbPropertiesManager类
-
负责数据库相关属性(url、username、password)的管理
public class DbPropertiesManager{
private static DbProperties dbProperties;
public static DbProperties getDbProperties() throws IOException {
if (dbProperties == null) {
dbProperties = new DbProperties();
}
return dbProperties;
}
@Getter
public static class DbProperties {
private final String url;
private final String username;
private final String password;
public DbProperties() throws IOException {
InputStream is = ClassLoader.getSystemResourceAsStream("datasource.properties");
Properties properties = new Properties();
properties.load(is);
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
}
}
}
StudentService类
-
模拟业务逻辑,调用dao层
public class StudentService {
private final StudentDao studentDao;
public StudentService() throws IOException {
studentDao = new StudentDao();
}
public List<Student> getAgeGreaterThan(int minAge) {
List<Student> studentList = studentDao.getAgeGreaterThan(minAge);
return Optional.ofNullable(studentList).orElse(Collections.emptyList());
}
}
StudentDao类
-
操作数据库,给业务逻辑层反馈数据
public class StudentDao {
private final DbPropertiesManager.DbProperties dbProperties;
public StudentDao() throws IOException {
dbProperties = DbPropertiesManager.getDbProperties();
}
public List<Student> getAgeGreaterThan(int minAge) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
List<Student> studentList = new ArrayList<>();
try {
//获取连接
connection = DriverManager.getConnection(dbProperties.getUrl(), dbProperties.getUsername(), dbProperties.getPassword());
//构造sql语句
String sql = "SELECT * FROM student WHERE age > ?";
//获取Statement对象
statement = connection.prepareStatement(sql);
//设置参数
statement.setInt(1, minAge);
//执行
statement.execute();
//获取结果集
resultSet = statement.getResultSet();
//处理结果集
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
Student student = Student.builder()
.id(id)
.name(name)
.age(age)
.build();
studentList.add(student);
}
//关闭资源
}catch (SQLException e) {
e.printStackTrace();
}finally {
if (resultSet != null) {
try {
resultSet.close();
}catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return studentList;
}
}
StudentServiceTest类
-
测试类
class StudentServiceTest {
@Test
public void testGetAgeGreaterThan() throws IOException {
StudentService service = new StudentService();
List<Student> studentList = service.getAgeGreaterThan(18);
Assertions.assertNotNull(studentList);
}
}
运行结果
存在的问题
通过上面一个示例的演示,可以通过JDBC从数据库中获取到我们想要的结果,但是仅仅是一个查询操作我们就写了很长的代码。操作数据库我们大致需要一下流程:
-
获取数据库连接(要操作数据库就需要与数据库建立连接)
-
构造要执行的sql语句(告诉数据库做什么操作CRUD,此时sql的一些参数可能还没有填充)
-
获取Statement对象
-
设置参数(对sql中的占位符进行替换)
-
执行(调用DBMS执行sql)
-
获取结果集
-
解析结果集(将返回的结果解析成预期的对象)
-
关闭资源(由于Connection、Statement、ResultSet都是一种资源,所以需要关闭)
一般我们dao层的类有很多对数据库的操作,而每一次对数据库的操作,我们都要写上面类似固定的流程,这就导致代码大量冗余,而作为程序员,最基本的要求就是去除冗余保证代码的可维护性、可读性。那我们分析一下整个流程有哪些是始终不变的,哪些是每次变化的?
不变的内容: 获取连接、获取Statement、执行sql、获取结果、解析结果、关闭资源
变化的内容:构造的sql语句、sql语句中的入参
总结
JDBC的作用主要为java访问数据库提供统一接口标准,使得java代码与具体数据库解耦。但通过分析我们发现使用原始JDBC操作数据库会有代码冗余问题,使得DAO层代码臃肿不好维护,接下来我们就来学习Mybatis作为对JDBC的一种封装,它如何解决上面的问题的呢?