【Java Web编程 十三】深入理解JDBC规范

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
简介: 【Java Web编程 十三】深入理解JDBC规范

之前学习了JSP和Servlet以及JavaBean,本篇Blog补上通往MVC架构的最后一篇,数据的持久化,也就是JDBC的相关知识,了解JDBC的基本概念和用处,如何操作数据库。

JDBC基本概念

什么是JDBC?JDBC 指 Java 数据库连接,是一种标准Java应用编程接口( JAVA API),用来连接 Java 编程语言和广泛的数据库。JDBC API 库包含下面提到的每个任务,都是与数据库相关的常用用法。

  1. 创建或断开与数据库的连接
  2. 创建 SQL 或 MySQL 语句,执行 SQL 或 MySQL 查询或修改数据库中的数据,查看和修改所产生的记录
  3. 抛出SQL语句执行的错误

从根本上来说,JDBC 是一种规范,它提供了一套完整的接口,允许便携式访问到底层数据库,因此可以用 Java 编写不同类型的可执行文件。为什么要有JDBC,没有JDBC,我们写代码要自己考虑如何连接数据库,要自己考虑如何连接各式各样的数据库,编写它们的驱动程序,而且要自己管理这些连接,现在有了JDBC,它为我们处理好了一切,我们只需要调用API接口就可以轻松操作数据库了,何乐而不为。

JDBC架构

JDBC 的 API 支持两层和三层处理模式进行数据库访问,但一般的 JDBC 架构由两层处理模式组成:

  1. JDBC API: 提供了应用程序对 JDBC数据库驱动程序管理器的连接。
  2. JDBC Driver API: 提供了 JDBC 数据库驱动程序管理器对数据库驱动程序的连接。

JDBC API 使用驱动程序管理器和数据库特定的驱动程序来提供异构数据库的透明连接。JDBC 数据库驱动程序管理器可确保正确的数据库驱动程序来访问每个数据源。该驱动程序管理器能够支持连接到多个异构数据库的多个并发的驱动程序。

JDBC常用接口

JDBC 的 API 提供了以下接口和类用来帮助我们连接数据库并进行相关操作,可以按照用途进行这样的划分:

与数据库连接操作相关的对象

  • Connection : 此接口具有连接数据库的所有方法。该连接对象表示通信上下文,即,所有与数据库的通信仅通过这个连接对象进行
  • DriverManager :这个类管理一系列数据库驱动程序。匹配连接使用通信子协议从 JAVA 应用程序中请求合适的数据库驱动程序。识别 JDBC 下某个子协议的第一驱动程序将被用于建立数据库连接。
  • Driver : 这个接口处理与数据库服务器的通信。一般我们用不到这个类,我们直接使用 DriverManager类,它管理Driver对象,也抽象了与Driver对象工作相关的详细信息。

与数据库执行SQL语句相关的对象

  • Statement : 使用创建于这个接口的对象将 SQL 语句提交到数据库。也就是通过此接口构建和执行SQL语句。
  • ResultSet : 在使用语句对象执行 SQL 查询后,这些对象保存从数据获得的数据,也就是结果集,结果集可滚动。

数据库执行SQL语句产生的异常对象

  • SQLException : 这个类处理发生在数据库应用程序的任何错误。

总而言之,JDBC的常用操作就是围绕我们通常在数据库中的一系列操作展开的。

JDBC数据类型

JDBC 驱动程序在将 Java 数据类型发送到数据库之前,会将其转换为相应的 JDBC 类型。对于大多数数据类型都采用了默认的映射关系。例如,一个 Java int 数据类型转换为 SQL INTEGER。通过默认的映射关系来提供驱动程序之间的一致性,当调用 PreparedStatement 中的 setXXX()方法时,Java 数据类型会转换为默认的 JDBC 数据类型:

JDBC事务

可以通过事务在任意时间来控制以及更改应用到数据库。它把单个 SQL 语句或一组 SQL 语句作为一个逻辑单元,如果其中任一语句失败,则整个事务失败,我们一般是默认事务自动提交的,如果想手动提交事务,也可以操作,示例如下:

try{
   //关闭数据库事务自动提交
   conn.setAutoCommit(false);
   Statement stmt = conn.createStatement();
   //设置一个还原点
   Savepoint savepoint1 = conn.setSavepoint("Savepoint1");
   String SQL = "INSERT INTO Employees " +
                "VALUES (106, 20, 'Rita', 'Tez')";
   stmt.executeUpdate(SQL);  
   String SQL = "INSERTED IN Employees " +
                "VALUES (107, 22, 'Sita', 'Tez')";
   stmt.executeUpdate(SQL);
   // 提交事务
   conn.commit();
}catch(SQLException se){
   // 如果捕获到了异常,回滚事务到还原点
   conn.rollback(savepoint1);
}

JDBC批处理

批处理是指将关联的 SQL 语句组合成一个批处理,并将他们当成一个调用提交给数据库。当一次发送多个 SQL 语句到数据库时,可以减少通信的资源消耗,从而提高了性能。我们可以批处理Statement对象的数据,也可以批处理PrepareStatement 对象数据:

批处理Statement对象的数据示例

// Create statement object
Statement stmt = conn.createStatement();
// Set auto-commit to false
conn.setAutoCommit(false);
// Create SQL statement
String SQL = "INSERT INTO Employees (id, first, last, age) " +
             "VALUES(200,'Zia', 'Ali', 30)";
// Add above SQL statement in the batch.
stmt.addBatch(SQL);
// Create one more SQL statement
String SQL = "INSERT INTO Employees (id, first, last, age) " +
             "VALUES(201,'Raj', 'Kumar', 35)";
// Add above SQL statement in the batch.
stmt.addBatch(SQL);
// Create one more SQL statement
String SQL = "UPDATE Employees SET age = 35 " +
             "WHERE id = 100";
// Add above SQL statement in the batch.
stmt.addBatch(SQL);
// Create an int[] to hold returned values
int[] count = stmt.executeBatch();
//Explicitly commit statements to apply changes
conn.commit();

批处理PrepareStatement 对象的数据示例

// Create SQL statement
String SQL = "INSERT INTO Employees (id, first, last, age) " +
             "VALUES(?, ?, ?, ?)";
// Create PrepareStatement object
PreparedStatemen pstmt = conn.prepareStatement(SQL);
//Set auto-commit to false
conn.setAutoCommit(false);
// Set the variables
pstmt.setInt( 1, 400 );
pstmt.setString( 2, "Pappu" );
pstmt.setString( 3, "Singh" );
pstmt.setInt( 4, 33 );
// Add it to the batch
pstmt.addBatch();
// Set the variables
pstmt.setInt( 1, 401 );
pstmt.setString( 2, "Pawan" );
pstmt.setString( 3, "Singh" );
pstmt.setInt( 4, 31 );
// Add it to the batch
pstmt.addBatch();
int[] count = pstmt.executeBatch();
//Explicitly commit statements to apply changes
conn.commit();

JDBC操作实践

由于后续要学习MyBatis,这里就不详细细说JDBC的各种各样的操作了,因为我们知道MyBatis做的更好,是一个持久层框架,我们这里只是简单使用下JDBC,大致了解下在框架出现之前代码是如何通过JDBC操作数据库的。我们先预置一个数据表user,包含四个字段:

安装JDBC的Mysql驱动

我们通过Maven构建项目可以直接加载数据库驱动,通过pom.xml文件安装驱动程序:

<dependency>
      <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
      <version>8.0.18</version>
  /dependency>

建立JDBC数据库连接

可以编写代码加载安装驱动,也就是建立与数据库的连接:

package com.example.GoldenManage.utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JdbcUtil {
    public static  Connection getConnection() {
        Connection connection;
        //JDBC驱动
        String driver = "com.mysql.cj.jdbc.Driver";
        //数据库url
        String url = "jdbc:mysql://localhost:3306/test?&useSSL=false&serverTimezone=UTC";
        String user = "root";
        String password = "root";
        try {
            //注册JDBC驱动程序
            Class.forName(driver);
            //建立连接
            connection = DriverManager.getConnection(url, user, password);
            if (!connection.isClosed()) {
                System.out.println("数据库连接成功");
            }
            return connection;
        } catch (ClassNotFoundException e) {
            System.out.println("数据库驱动没有安装");
        } catch (SQLException e) {
            e.printStackTrace();
            System.out.println("数据库连接失败");
        }
       return null;
    }
}

执行SQL语句并获取结果集

建立连接后就可以操作数据库执行相关的SQL语句了,执行SQL语句有两种常用对象,用来构建查询语句:

我们一般不在JDBC中执行存储过程

package com.example.GoldenManage.dao;
import com.example.GoldenManage.model.UserModel;
import com.example.GoldenManage.utils.JdbcUtil;
import javax.xml.crypto.Data;
import java.sql.*;
import java.time.LocalDate;
public class UserDao {
    /**
     * 通过用户名到数据库中获取凭证密码
     * @param userName
     * @return
     */
    public static String getPasswordByUserName(String userName) {
        //SQL语句
        String sql = "select password from user where username = " +"'" + userName+"'";
        Connection connection = JdbcUtil.getConnection();
        Statement statement=null;
        ResultSet resultSet = null;
        String password=null;
        try {
            statement = connection.createStatement();
            //执行语句,得到结果集
            resultSet = statement.executeQuery(sql);
            while (resultSet.next()) {
                //这里只查询的密码
                password = resultSet.getString(1);
            }
            resultSet.close();
            connection.close();//关闭连接
        } catch (SQLException e1) {
            e1.printStackTrace();
        }
        return password;
    }
    /**
     * 插入數據
     * @return
     */
    public static int regiserUser(UserModel userModel) {
        int flag=0;
        //SQL语句
        String sql = "insert into user values (?,?,?,?)";
        Connection connection = JdbcUtil.getConnection();
        PreparedStatement statement=null;
        try {
            statement = connection.prepareStatement(sql);
            statement.setString(1, userModel.getUsername());
            statement.setString(2, userModel.getPhone());
            statement.setString(3, userModel.getPassword());
            statement.setString(4, userModel.getEmail());
            //执行语句,得到结果集
            flag = statement.executeUpdate();
            connection.close();//关闭连接
        } catch (SQLException e1) {
            e1.printStackTrace();
        }
        return flag;
    }
}

同样我们也可以对结果集做多种操作,例如获取第一条数据或者或者最后一条数据等操作,结果集其实就是返回一个数据表,数据表的光标是可滚动的,有些常用的操作方法:

SQL语句执行异常

当SQL语句执行异常时会有SQLException报出来:

JDBC事务操作实践

我们编写一段事务验证的代码,确认JDBC确实可以操作事务回滚:

public static void main(String[] args) throws SQLException {
        Connection connection = JdbcUtil.getConnection();
        Savepoint savepoint = null;
        try{
            //关闭数据库事务自动提交
            connection.setAutoCommit(false);
            Statement stmt = connection.createStatement();
            //设置一个还原点
            savepoint = connection.setSavepoint("Savepoint1");
            String sql = "insert into user values ('tml','13345678907','666666','123@qq.com')";
            stmt.executeUpdate(sql);
            //错误的sql语句
            String errorSql = "inserted into user values ('tml','13345678907','666666','123@qq.com')";
            stmt.executeUpdate(errorSql);
            // 提交事务
            connection.commit();
        }catch(SQLException se){
            // 如果捕获到了异常,回滚事务到还原点
            connection.rollback(savepoint);
            System.out.println("sql语句执行异常,事务已回滚");
        }

当执行时就会报错,可以发现数据也并没有落库:

当我们修正错误的sql语句后,可以发现数据正常落库:

JDBC批处理操作实践

我们还是往user表里插数据,只不过这次是批量插入数据:

public static void main(String[] args) throws SQLException {
        Connection connection = JdbcUtil.getConnection();
        try{
            String sql = "insert into user values (?,?,?,?)";
            PreparedStatement stmt = connection.prepareStatement(sql);
            stmt.setString(1, "AA");
            stmt.setString(2, "AA");
            stmt.setString(3, "AA");
            stmt.setString(4, "AA");
            stmt.addBatch();
            stmt.setString(1, "BB");
            stmt.setString(2, "BB");
            stmt.setString(3, "BB");
            stmt.setString(4, "BB");
            stmt.addBatch();
            stmt.setString(1, "CC");
            stmt.setString(2, "CC");
            stmt.setString(3, "CC");
            stmt.setString(4, "CC");
            stmt.addBatch();
            stmt.executeBatch();
        }catch(SQLException se){
            System.out.println("批处理异常"+se);
        }
    }

查看结果可以看到批量插了进来:

总结一下

JDBC其实就是提供了一套我们通过代码去访问数据库的平台无光的规范,帮助我们连接数据库,执行SQL语句,执行数据库事务,批处理数据库数据或SQL语句,操作返回的结果集,并且给我们提供数据类型的映射,打印执行SQL失败的报错。其实还提供一些数据库的流数据处理等高级操作,这里就不一一说明了。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
4月前
|
Java
如何在Java中进行多线程编程
Java多线程编程常用方式包括:继承Thread类、实现Runnable接口、Callable接口(可返回结果)及使用线程池。推荐线程池以提升性能,避免频繁创建线程。结合同步与通信机制,可有效管理并发任务。
215 6
|
4月前
|
IDE Java 编译器
java编程最基础学习
Java入门需掌握:环境搭建、基础语法、面向对象、数组集合与异常处理。通过实践编写简单程序,逐步深入学习,打牢编程基础。
277 1
|
5月前
|
SQL Java 数据库
2025 年 Java 从零基础小白到编程高手的详细学习路线攻略
2025年Java学习路线涵盖基础语法、面向对象、数据库、JavaWeb、Spring全家桶、分布式、云原生与高并发技术,结合实战项目与源码分析,助力零基础学员系统掌握Java开发技能,从入门到精通,全面提升竞争力,顺利进阶编程高手。
983 1
|
5月前
|
安全 Java API
Java Web 在线商城项目最新技术实操指南帮助开发者高效完成商城项目开发
本项目基于Spring Boot 3.2与Vue 3构建现代化在线商城,涵盖技术选型、核心功能实现、安全控制与容器化部署,助开发者掌握最新Java Web全栈开发实践。
546 1
|
4月前
|
安全 前端开发 Java
从反射到方法句柄:深入探索Java动态编程的终极解决方案
从反射到方法句柄,Java 动态编程不断演进。方法句柄以强类型、低开销、易优化的特性,解决反射性能差、类型弱、安全性低等问题,结合 `invokedynamic` 成为支撑 Lambda 与动态语言的终极方案。
206 0
|
5月前
|
存储 前端开发 Java
【JAVA】Java 项目实战之 Java Web 在线商城项目开发实战指南
本文介绍基于Java Web的在线商城技术方案与实现,涵盖三层架构设计、MySQL数据库建模及核心功能开发。通过Spring MVC + MyBatis + Thymeleaf实现商品展示、购物车等模块,提供完整代码示例,助力掌握Java Web项目实战技能。(238字)
576 0
|
5月前
|
Java 开发者
Java并发编程:CountDownLatch实战解析
Java并发编程:CountDownLatch实战解析
507 100
|
5月前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
411 16
|
5月前
|
NoSQL Java 关系型数据库
超全 Java 学习路线,帮你系统掌握编程的超详细 Java 学习路线
本文为超全Java学习路线,涵盖基础语法、面向对象编程、数据结构与算法、多线程、JVM原理、主流框架(如Spring Boot)、数据库(MySQL、Redis)及项目实战等内容,助力从零基础到企业级开发高手的进阶之路。
418 1
|
4月前
|
算法 Java Go
【GoGin】(1)上手Go Gin 基于Go语言开发的Web框架,本文介绍了各种路由的配置信息;包含各场景下请求参数的基本传入接收
gin 框架中采用的路优酷是基于httprouter做的是一个高性能的 HTTP 请求路由器,适用于 Go 语言。它的设计目标是提供高效的路由匹配和低内存占用,特别适合需要高性能和简单路由的应用场景。
390 4