目录
JDBC 很重要。它是一套标准规范,通过它可以访问不同的关系型数据库。它无处不在,存在于各种各样的 Java Web 项目中,用来连接数据库。它隐藏在持久层框架中,Mybatis 等持久层框架就是封装了 JDBC 操作数据库的过程。
但是初学者在使用 JDBC 的过程中很容易出错,会遇到各种各样的问题。所以我觉得有必要专门写一篇文章介绍它的原理,并带着诸位一起操作数据库。如果这篇文章能够帮助你解决你遇到的问题和疑惑,那我觉得它的存在是有价值和意义的。如果你没使用 JDBC 成功的连接过数据库,我建议你跟着本教程一步一步的操作。只要你耐心学习,就能使用 JDBC 操作数据库,享受成功的喜悦。
本文先会介绍 JDBC 的一些概念,再用一个常见的场景带着诸位使用 JDBC 连接 Mysql 数据库,进行增删改查。最后会总结一下 JDBC 的不足之处,以及如何弥补 JDBC 的不足之处。
JDBC 是一种规范,它在 Java 中定义了操作数据库的接口,这些接口包括连接数据库、操作数据库的增删改查、操作数据库的事务等等。至于,用什么通信协议连接数据库?怎样连接数据库?怎样操作数据库的增删改查?怎样操作数据库的事务?这些都由 Mysql 、Oracle 、SqlServer 等各大数据库厂商去实现,具体的实现细节肯定是不同的。
所以这套规范保证了用一套 Java 代码就可以操作不同的数据库,为开发者屏蔽了一些细节问题.各大数据库厂商使用 Java 语言实现 JDBC 定义的接口后,会以 Jar 包供给开发者使用,这些 Jar 包就是数据库驱动,又叫数据库连接器。
最常见的数据库连接器有 Mysql 连接器,经常看见的英文名是 mysql-connector-java。如果你不太了解它,推荐你看我之前写的一篇文章《mysql-connector-java详解》,或许你会有一定的收获。
Java 语言中定义了这一套 JDBC 的规范,使开发者使用 Java 语言操作数据库更加简单、方便。我总结了一下,有如下两点好处。
通过 JDBC 访问数据库的流程图如下:
接下来进入了实操的环节,我将使用 JDBC 操作 Mysql 数据库。相信我,只要你跟着我一步一步的操作,你也可以成功的使用 JDBC 操作数据库的。假设你开发了一个网站,用户可以在网站上进行注册(增)、登录(查)、修改用户名(改)、注销(删)等操作。这个场景模拟用户的一些操作,有些细节的地方简化了,可以不用去深究。
我先说一下 JDBC 的编写步骤,如下 8 点所示:
下面介绍一下我编写和运行程序的环境和数据库的表结构。
我在 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='用户表';
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>
先配置好数据库的 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);
- }
-
- }
程序运行的结果如下图所示,我用红框标识出了数据库连接。你测试一下,看一下你是否能打印出数据库连接。
通过 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);
- }
- }
程序运行的结果如下图所示,打印出了注册成功,同时数据库中也有了一条记录。
登录用户就是用手机号码和密码做为条件,查询数据库中的用户表。如果查到了数据,就登录成功。如果没查到数据,就登录失败。
- /**
- * 用户登录
- */
- @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);
- }
- }
结果如下图所示,登录成功。
修改用户就是用登录查出的用户的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);
- }
- }
结果如下图所示,修改成功,并且数据库中的数据也改变了。
注销用户就是删除用户。
- /**
- * 注销用户
- */
- @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 有哪些不足?如下所示,总共有 4 点不足。
1、在创建连接,关闭连接,异常处理的时侯有很多冗余、重复的代码,导致一个很长的方法中业务代码只占一小部分
2、Sql 语句在代码中硬编码,不易维护
3、Sql 输入参数需要自己映射,要手动处理sql中的占位符,将输入参数和占位符对应起来
4、获取数据库返回的数据时,需要手动创建对象,再遍历结果集,将数据放到对象中
既然知道了 JDBC 的不足之处,那就要弥补这些不足。所以一些持久层的框架就应运而生,这些持久层框架封装了 JDBC 操作数据库的过程,使开发者只需要关心 Sql 本身,而不需要花费精力去处理例如注册驱动、创建 connection、创建 statement、手动设置参数、检索结果集等繁琐的过程。
常见的持久层框架有 Mybatis 、 JdbcTemplate 、Hibernate 等。现在,大部分项目都会使用 Mybatis ,我也推荐使用你 Mybatis。JdbcTemplate 也可以使用,Hibernate 已经过时了,只有在一些老项目中才能看到它的身影。
以上就是 JDBC 原理介绍以及数据库操作,诸位可以跟着步骤操作一下,不用担心连不上数据库了。我之前写过 Mysql 数据库驱动的文章,也写过持久层技术对比的文章。这一篇 JDBC 详解的文章是和那两篇文章相互呼应的,是同一个系列的文章。
最后,做一个简单的调查,你有没有成功的使用 JDBC 操作过数据库?如果有,那恭喜你学会了使用 JDBC 编程。如果没有,那你可能遇到了问题,你可以将问题抛出来。基于这两种假设,你可以在评论区留言,大家一起讨论一下。