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

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
简介: 【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失败的报错。其实还提供一些数据库的流数据处理等高级操作,这里就不一一说明了。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
6月前
|
安全 Java API
Java Web 在线商城项目最新技术实操指南帮助开发者高效完成商城项目开发
本项目基于Spring Boot 3.2与Vue 3构建现代化在线商城,涵盖技术选型、核心功能实现、安全控制与容器化部署,助开发者掌握最新Java Web全栈开发实践。
630 1
|
6月前
|
存储 前端开发 Java
【JAVA】Java 项目实战之 Java Web 在线商城项目开发实战指南
本文介绍基于Java Web的在线商城技术方案与实现,涵盖三层架构设计、MySQL数据库建模及核心功能开发。通过Spring MVC + MyBatis + Thymeleaf实现商品展示、购物车等模块,提供完整代码示例,助力掌握Java Web项目实战技能。(238字)
728 0
|
7月前
|
JavaScript Java 微服务
现代化 Java Web 在线商城项目技术方案与实战开发流程及核心功能实现详解
本项目基于Spring Boot 3与Vue 3构建现代化在线商城系统,采用微服务架构,整合Spring Cloud、Redis、MySQL等技术,涵盖用户认证、商品管理、购物车功能,并支持Docker容器化部署与Kubernetes编排。提供完整CI/CD流程,助力高效开发与扩展。
793 64
|
7月前
|
前端开发 Java 数据库
Java 项目实战从入门到精通 :Java Web 在线商城项目开发指南
本文介绍了一个基于Java Web的在线商城项目,涵盖技术方案与应用实例。项目采用Spring、Spring MVC和MyBatis框架,结合MySQL数据库,实现商品展示、购物车、用户注册登录等核心功能。通过Spring Boot快速搭建项目结构,使用JPA进行数据持久化,并通过Thymeleaf模板展示页面。项目结构清晰,适合Java Web初学者学习与拓展。
496 1
|
8月前
|
缓存 NoSQL Java
Java Web 从入门到精通之苍穹外卖项目实战技巧
本项目为JavaWeb综合实战案例——苍穹外卖系统,涵盖Spring Boot 3、Spring Cloud Alibaba、Vue 3等主流技术栈,涉及用户认证、订单处理、Redis缓存、分布式事务、系统监控及Docker部署等核心功能,助你掌握企业级项目开发全流程。
848 0
|
8月前
|
安全 JavaScript Java
java Web 项目完整案例实操指南包含从搭建到部署的详细步骤及热门长尾关键词解析的实操指南
本项目为一个完整的JavaWeb应用案例,采用Spring Boot 3、Vue 3、MySQL、Redis等最新技术栈,涵盖前后端分离架构设计、RESTful API开发、JWT安全认证、Docker容器化部署等内容,适合掌握企业级Web项目全流程开发与部署。
665 0
|
Java 关系型数据库 MySQL
mysql5.7 jdbc驱动
遵循上述步骤,即可在Java项目中高效地集成MySQL 5.7 JDBC驱动,实现数据库的访问与管理。
2903 1
|
SQL druid Java
Java数据库部分(MySQL+JDBC)(二、JDBC超详细学习笔记)(下)
Java数据库部分(MySQL+JDBC)(二、JDBC超详细学习笔记)
245 3
Java数据库部分(MySQL+JDBC)(二、JDBC超详细学习笔记)(下)
|
SQL Java 关系型数据库
Java数据库部分(MySQL+JDBC)(二、JDBC超详细学习笔记)(上)
Java数据库部分(MySQL+JDBC)(二、JDBC超详细学习笔记)
657 3
Java数据库部分(MySQL+JDBC)(二、JDBC超详细学习笔记)(上)
|
SQL 关系型数据库 MySQL
Java数据库部分(MySQL+JDBC)(一、MySQL超详细学习笔记)(下)
Java数据库部分(MySQL+JDBC)(一、MySQL超详细学习笔记)
150 6