目录
一、引言
JDBC 很重要。它是一套标准规范,通过它可以访问不同的关系型数据库。它无处不在,存在于各种各样的 Java Web 项目中,用来连接数据库。它隐藏在持久层框架中,Mybatis 等持久层框架就是封装了 JDBC 操作数据库的过程。
但是初学者在使用 JDBC 的过程中很容易出错,会遇到各种各样的问题。所以我觉得有必要专门写一篇文章介绍它的原理,并带着诸位一起操作数据库。如果这篇文章能够帮助你解决你遇到的问题和疑惑,那我觉得它的存在是有价值和意义的。如果你没使用 JDBC 成功的连接过数据库,我建议你跟着本教程一步一步的操作。只要你耐心学习,就能使用 JDBC 操作数据库,享受成功的喜悦。
本文先会介绍 JDBC 的一些概念,再用一个常见的场景带着诸位使用 JDBC 连接 Mysql 数据库,进行增删改查。最后会总结一下 JDBC 的不足之处,以及如何弥补 JDBC 的不足之处。
二、JDBC 是什么
1、我对 JDBC 的理解
JDBC 是一种规范,它在 Java 中定义了操作数据库的接口,这些接口包括连接数据库、操作数据库的增删改查、操作数据库的事务等等。至于,用什么通信协议连接数据库?怎样连接数据库?怎样操作数据库的增删改查?怎样操作数据库的事务?这些都由 Mysql 、Oracle 、SqlServer 等各大数据库厂商去实现,具体的实现细节肯定是不同的。
所以这套规范保证了用一套 Java 代码就可以操作不同的数据库,为开发者屏蔽了一些细节问题.各大数据库厂商使用 Java 语言实现 JDBC 定义的接口后,会以 Jar 包供给开发者使用,这些 Jar 包就是数据库驱动,又叫数据库连接器。
最常见的数据库连接器有 Mysql 连接器,经常看见的英文名是 mysql-connector-java。如果你不太了解它,推荐你看我之前写的一篇文章《mysql-connector-java详解》,或许你会有一定的收获。
2、使用 JDBC 的好处
Java 语言中定义了这一套 JDBC 的规范,使开发者使用 Java 语言操作数据库更加简单、方便。我总结了一下,有如下两点好处。
- 定义了操作数据库的标准类库,可以用同一种方式操作不同的数据库。
- 屏蔽了数据库驱动的底层实现,从而使开发者可以更简单的操作数据库。
通过 JDBC 访问数据库的流程图如下:
3、JDBC 几个重要的类和接口介绍
- DriverManager :这个类管理一系列数据库驱动程序。匹配连接使用通信子协议从 JAVA 应用程序中请求合适的数据库驱动程序。识别 JDBC 下某个子协议的第一驱动程序将被用于建立数据库连接。
- Driver :该接口提供给数据库厂商使用的,不同数据库厂商提供不同的实现。
- Connection :代表数据库的连接对象,此接口具有与数据库交互的所有方法,所有与数据库的通信仅通过这个连接对象进行。
- Statement :通过调用 Connection 子类对象的 createStatement() 方法创建该接口的子类对象。将 Sql 语句提交到数据库执行,获取数据库执行的结果集。但是 Statement 有不足之处,比如:存在拼串操作,繁琐;存在 Sql 注入问题。
- PrepatedStatement:该接口继承 Statement 接口,表示一条预编译过的 Sql 语句,可以使用该对象多次高效地执行 Sql 语句。它可以弥补 Statement 的不足之处,能预编译提高性能优化,能防止 Sql 注入。
- CallableStatement:用于执行 SQL 存储过程
三、JDBC 操作数据库示例
接下来进入了实操的环节,我将使用 JDBC 操作 Mysql 数据库。相信我,只要你跟着我一步一步的操作,你也可以成功的使用 JDBC 操作数据库的。假设你开发了一个网站,用户可以在网站上进行注册(增)、登录(查)、修改用户名(改)、注销(删)等操作。这个场景模拟用户的一些操作,有些细节的地方简化了,可以不用去深究。
1、JDBC 编写步骤
我先说一下 JDBC 的编写步骤,如下 8 点所示:
- 加载数据库驱动
- 创建并获取数据库链接
- 创建 jdbc statement 对象
- 设置 sql 语句
- 设置 sql 语句中的参数(使用 preparedStatement )
- 通过 statemen t执行 sql 并获取结果
- 对 sql 执行结果进行解析处理
- 释放资源(resultSet、preparedstatement、connection)
2、环境介绍
下面介绍一下我编写和运行程序的环境和数据库的表结构。
- JDK 版本:1.8及以上
- Mysql 版本:8.0.25
- Mysql 驱动版本:8.0.28
我在 Mysql 中创建了一张用户表,用来演示数据库的增删改查,表结构如下所示:
CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户id',
`phone` char(11) NOT NULL COMMENT '手机号',
`name` varchar(50) NOT NULL COMMENT '用户名',
`pwd` varchar(50) NOT NULL COMMENT '密码',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='用户表';
3、下载驱动
Mysql 驱动是 mysql-connector-java,下载驱动两种有方式。一种方式是到官网直接下载jar包,再将下载的 Jar 包放到项目的 lib 目录下,然后 build path。另一种方式是通过 Maven 下载,在 pom 文件中配置依赖。如果不知道怎么下载 Mysql 驱动,不太熟悉操作步骤,可以参考我之前写的文章《不同版本mysql-connector-java的jar包下载地址》。
我使用的是 Maven 依赖的方式,pom 文件的配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>jdbcTest</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
4、连接数据库
先配置好数据库的 url 、用户名和密码,然后获取数据库连接,最后打印连接。我使用 Junit 测试,如果你不习惯用 Junit ,也可以使用 main 方法测试。
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.util.Properties;
public class ConnectionTest {
@Test
public void testConnection() throws SQLException {
// 获取Driver实现类对象
Driver driver = new com.mysql.jdbc.Driver();
// url:jdbc:mysql://localhost:3306/test
// jdbc:mysql:协议
// localhost:ip地址
// 3306:默认mysql的端口号
// test:test数据库
String url = "jdbc:mysql://localhost:3306/test";
// 将用户名和密码封装在Properties中
Properties info = new Properties();
info.setProperty("user", "root");
info.setProperty("password", "root");
Connection conn = driver.connect(url, info);
System.out.println(conn);
}
}
程序运行的结果如下图所示,我用红框标识出了数据库连接。你测试一下,看一下你是否能打印出数据库连接。
5、注册用户
通过 JDBC 成功的连接数据库,我们开始注册用户了,注册用户就是往数据库中插入一下用户数据。因为获取数据库连接和关闭数据库连接比较繁琐,我将这两个过程封装工具类 JDBCUtils 。
package utils;
import java.sql.*;
/**
* @Description 操作数据库的工具类
*/
public class JDBCUtils {
/**
*
* @Description 获取数据库的连接
* @return
* @throws Exception
*/
public static Connection getConnection() throws Exception {
// 1.配置基本信息
String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "xxx";
String driverClass = "com.mysql.cj.jdbc.Driver";
// 2.加载驱动
Class.forName(driverClass);
// 3.获取连接
Connection conn = DriverManager.getConnection(url, user, password);
return conn;
}
/**
*
* @Description 关闭连接和Statement的操作
* @param conn
* @param ps
*/
public static void closeResource(Connection conn,Statement ps){
try {
if(ps != null)
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
*
* @Description 关闭资源操作
* @param conn
* @param ps
* @param rs
*/
public static void closeResource(Connection conn,Statement ps,ResultSet rs){
try {
if(ps != null)
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(rs != null)
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
有了该工具类,接下来注册用户就简单了,代码如下所示:
/**
* 用户注册
*/
@Test
public void testAdd() {
Connection conn = null;
PreparedStatement ps = null;
try {
String sql = "INSERT INTO `test`.`user`( `phone`, `name`, `pwd`) VALUES ( ?, ?, ?)";
conn = JDBCUtils.getConnection();
ps = conn.prepareStatement(sql);
//3.填充占位符
ps.setInt(1, 1326666666);
ps.setString(2, "zhangsan");
ps.setString(3, "123456");
int count = ps.executeUpdate();
if (count > 0) {
System.out.println("注册成功");
} else {
System.out.println("注册失败");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, ps);
}
}
程序运行的结果如下图所示,打印出了注册成功,同时数据库中也有了一条记录。
6、登录用户
登录用户就是用手机号码和密码做为条件,查询数据库中的用户表。如果查到了数据,就登录成功。如果没查到数据,就登录失败。
/**
* 用户登录
*/
@Test
public void testLogin() {
Connection conn = null;
PreparedStatement ps = null;
ResultSet resultSet = null;
try {
conn = JDBCUtils.getConnection();
String sql = "select * from user where phone = ? and pwd = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, "1326666666");
ps.setString(2, "123456");
resultSet = ps.executeQuery();
if (resultSet.next()) {
System.out.println(resultSet.getString("name") + "登录成功");
} else {
System.out.println("用户名不存在或密码错误");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, ps, resultSet);
}
}
结果如下图所示,登录成功。
7、修改用户
修改用户就是用登录查出的用户的id做为条件,更新用户名。在这里我将用户名【zhangsan】改为【zhangsan1】。
/**
* 修改用户名
*/
@Test
public void testUpdate() {
Connection conn = null;
PreparedStatement ps = null;
try {
String sql = "UPDATE `user` SET `name` = ? WHERE `id` = ?";
conn = JDBCUtils.getConnection();
ps = conn.prepareStatement(sql);
//3.填充占位符
ps.setString(1, "zhangsan1");
ps.setInt(2, 1);
int count = ps.executeUpdate();
if (count > 0) {
System.out.println("修改成功");
} else {
System.out.println("修改失败");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, ps);
}
}
结果如下图所示,修改成功,并且数据库中的数据也改变了。
8、注销用户
注销用户就是删除用户。
/**
* 注销用户
*/
@Test
public void testDelete() {
Connection conn = null;
PreparedStatement ps = null;
try {
String sql = "DELETE FROM `user` WHERE `id` = ?";
conn = JDBCUtils.getConnection();
ps = conn.prepareStatement(sql);
//3.填充占位符
ps.setInt(1, 1);
int count = ps.executeUpdate();
if (count > 0) {
System.out.println("注销成功");
} else {
System.out.println("注销失败");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn, ps);
}
}
结果如下图所示,删除成功,并且数据库中的数据也删除了。
四、总结 JDBC 的不足之处
现在,我们已经用 JDBC 将数据库的增删改查演示完了。通过上面的代码,我们也可以感受到 JDBC 的不足之处。那么,JDBC 有哪些不足?如下所示,总共有 4 点不足。
1、在创建连接,关闭连接,异常处理的时侯有很多冗余、重复的代码,导致一个很长的方法中业务代码只占一小部分
2、Sql 语句在代码中硬编码,不易维护
3、Sql 输入参数需要自己映射,要手动处理sql中的占位符,将输入参数和占位符对应起来
4、获取数据库返回的数据时,需要手动创建对象,再遍历结果集,将数据放到对象中
五、如何弥补 JDBC 的不足之处
既然知道了 JDBC 的不足之处,那就要弥补这些不足。所以一些持久层的框架就应运而生,这些持久层框架封装了 JDBC 操作数据库的过程,使开发者只需要关心 Sql 本身,而不需要花费精力去处理例如注册驱动、创建 connection、创建 statement、手动设置参数、检索结果集等繁琐的过程。
常见的持久层框架有 Mybatis 、 JdbcTemplate 、Hibernate 等。现在,大部分项目都会使用 Mybatis ,我也推荐使用你 Mybatis。JdbcTemplate 也可以使用,Hibernate 已经过时了,只有在一些老项目中才能看到它的身影。
六、结语
以上就是 JDBC 原理介绍以及数据库操作,诸位可以跟着步骤操作一下,不用担心连不上数据库了。我之前写过 Mysql 数据库驱动的文章,也写过持久层技术对比的文章。这一篇 JDBC 详解的文章是和那两篇文章相互呼应的,是同一个系列的文章。
最后,做一个简单的调查,你有没有成功的使用 JDBC 操作过数据库?如果有,那恭喜你学会了使用 JDBC 编程。如果没有,那你可能遇到了问题,你可以将问题抛出来。基于这两种假设,你可以在评论区留言,大家一起讨论一下。