Java 基础知识之 JDBC(上)

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 什么是 JDBCJDBC 全称 Java DataBase Connection,是 Java 定义的一套访问关系型数据库的规范,实现由各数据库厂商来完成,通过这套 API,Java 开发者可以轻松的访问各数据库。

什么是 JDBC


JDBC 全称 Java DataBase Connection,是 Java 定义的一套访问关系型数据库的规范,实现由各数据库厂商来完成,通过这套 API,Java 开发者可以轻松的访问各数据库。


如何通过 JDBC 访问数据库


通过 JDBC 访问数据库有一套固定的模板,查询数据库的示例代码如下。


    String url = "jdbc:mysql://127.0.0.1:3306/test";
        String username = "root";
        String password = "12345678";
        // 1. 获取连接
        Connection connection = DriverManager.getConnection(url, username, password);
        // 2. 获取查询语句
        PreparedStatement preparedStatement = connection.prepareStatement("select * from test");
        // 3. 执行查询,获取结果集
        ResultSet resultSet = preparedStatement.executeQuery();
        while (resultSet.next()){
          // 4. 从结果集取数据
            int id = resultSet.getInt("id");
            System.out.println(id);
        }
        // 5. 关闭连接
        resultSet.close();
        preparedStatement.close();
        connection.close();


上述代码中涉及到了一些 JDBC 相关的 API,下面加以介绍。


JDBC 提供了哪些 API 抽象?


驱动


为了操作数据库,我们需要先获取一个数据库的连接,驱动的作用正是获取某一个数据库的连接,JDBC 支持一个程序中同时存在多个驱动,驱动在 JDBC 中对应的接口是java.sql.Driver,驱动由驱动管理器java.sql.DriverManager进行管理,下面进行单独介绍。


java.sql.Driver


Driver 作为一个接口,由具体的数据库厂商进行实现,在加载驱动时,驱动将创建自己的实例并向驱动管理器进行注册,因此我们经常看到一些类似Class.forName("com.mysql.cj.jdbc.Driver")的代码。以 MySQL 为例,实现为com.mysql.cj.jdbc.Driver,代码如下。


public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }
    public Driver() throws SQLException {
    }
}


MySQL 的驱动在静态代码块中添加了向驱动管理器注册自身的逻辑,因此调用Class.forName("com.mysql.cj.jdbc.Driver")方法后驱动管理器就对 MySQL 的驱动进行管理。


下面为 Driver 接口中的一些相对来说比较重要的方法,分别加以介绍。


image.png


Driver 获取 Connection 的示例代码如下。


        String url = "jdbc:mysql://127.0.0.1:3306/test";
        String username = "root";
        String password = "12345678";
        Driver driver = new com.mysql.cj.jdbc.Driver();
        Properties properties = new Properties();
        properties.put("user", username);
        properties.put("password", password);
        Connection connection = driver.connect(url, properties);
        connection.close();


java.sql.DriverManager


DriverManager 是 Driver 的管理器,提供了注册驱动、取消注册驱动、获取连接等方法,有了 DriverManager 之后,我们每次获取连接时就不用再关心使用哪个具体的 Driver。先看 DriverManager 提供的主要方法。


image.png


从上面的方法中可以看到,DriverManager 的作用就是管理 Driver,进一步抽象 Connection 的获取,DriverManager 会从已注册的驱动中尝试获取 Connection。如果只是提供 Driver 的注册和取消注册方法,那么使用 DriverManager 获取 Connection 前,使用方仍然要关心 Driver 的具体实现,为了解决这个问题,DriverManager 初始化时会尝试初始化 Driver,具体有两种方式,感兴趣的小伙伴可自行阅读源码。


初始化 jdbc.dirvers 系统属性指定的 Driver,多个 Driver 使用:分割。

JDBC 4 开始利用 SPI 机制初始化 Driver。关于 SPI 机制,可参考我前面的文章 《Java 基础知识之 SPI》

有了 SPI 机制之后,我们只需要引入具体数据库的驱动即可,而不用再调用Class.forName("com.mysql.cj.jdbc.Driver")方法。MySQL 的驱动目前已支持 SPI 。



image.png

最后,再上一段 DriverManager 获取 Connection 的示例代码。


    // Class.forName("com.mysql.cj.jdbc.Driver") 不再需要调用该方法初始化驱动
    String url = "jdbc:mysql://127.0.0.1:3306/test";
        String username = "root";
        String password = "12345678";
        Connection connection = DriverManager.getConnection(url, username,password);
        connection.close();


数据源


不管是 Driver 还是 DriverManager,最终都要获取连接,JDBC 2.0 开始,提出一个数据源的概念,也是用于获取连接,其接口为javax.sql.DataSource,其上只定义两个获取连接的方法,具体如下。


public interface DataSource  extends CommonDataSource, Wrapper {
  Connection getConnection() throws SQLException;
  Connection getConnection(String username, String password) throws SQLException;
}


目前有两个使用较多的数据源,分别是 HiKariCP 和 Druid 。感兴趣的小伙伴可自行研究。


连接


连接在 JDBC API 的抽象是java.sql.Connection,表示客户端和某一种具体数据库之间的会话,连接提供的 API 大概可分为如下几类。


1. 获取 Statement 的 API


Statement 用于执行 SQL,后面会进行介绍,这里先看有哪些获取 Statement 的方法。


    /**
     * 创建一个可以生成给定类型、并发性、保持性的 ResultSet 的 Statement
     * 默认的结果集类型是 ResultSet.TYPE_FORWARD_ONLY,
     * 默认的并发性是 ResultSet.CONCUR_READ_ONLY,
     * 默认的保持性可以调用 #getHoldability 方法获取
     *
     * @param resultSetType     结果集类型,可取值为 ResultSet.TYPE_FORWARD_ONLY、ResultSet.TYPE_SCROLL_INSENSITIVE、ResultSet.TYPE_SCROLL_SENSITIVE
     * @param resultSetConcurrency  结果集的并发性,可取值为 ResultSet.CONCUR_READ_ONLY,ResultSet.CONCUR_UPDATABLE
     * @param resultSetHoldability  结果集的保持性,可取的值为 ResultSet.HOLD_CURSORS_OVER_COMMIT、ResultSet.CLOSE_CURSORS_AT_COMMIT
     */
    Statement createStatement() throws SQLException;
    Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException;
    Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException;
    /**
     * 创建 PreparedStatement
     * 默认的结果集类型是 ResultSet.TYPE_FORWARD_ONLY,
     * 默认的并发性是 ResultSet.CONCUR_READ_ONLY,
     * 默认的保持性可以调用 #getHoldability 方法获取
     *
     * @param sql           要发送到数据库的 SQL ,可以包含多个 ? 作为参数
     * @param resultSetType     结果集类型,可取值为 ResultSet.TYPE_FORWARD_ONLY、ResultSet.TYPE_SCROLL_INSENSITIVE、ResultSet.TYPE_SCROLL_SENSITIVE
     * @param resultSetConcurrency  结果集的并发性,可取值为 ResultSet.CONCUR_READ_ONLY,ResultSet.CONCUR_UPDATABLE
     * @param resultSetHoldability  结果集的保持性,可取的值为 ResultSet.HOLD_CURSORS_OVER_COMMIT、ResultSet.CLOSE_CURSORS_AT_COMMIT
     * @param autoGeneratedKeys   返回的 PreparedStatement 是否可以获取自动生成的键,可取值为 Statement.RETURN_GENERATED_KEYS、Statement.NO_GENERATED_KEYS
     * @param columnIndexes     目标表中列的索引,指示返回的 PreparedStatement 可以获取到自动生成的哪些键
     * @param columnNames       目标表中的列名,指示返回的 PreparedStatement 可以获取到自动生成的哪些键
     */
    PreparedStatement prepareStatement(String sql)throws SQLException;
    PreparedStatement prepareStatement(String sql, int resultSetType,  int resultSetConcurrency) throws SQLException;
    PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException;
    PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException;
    PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException;
    PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException;
    /**
     * 创建一个可以生成给定类型、并发性、保持性的 ResultSet 的 CallableStatement
     * 默认的结果集类型是 ResultSet.TYPE_FORWARD_ONLY,
     * 默认的并发性是 ResultSet.CONCUR_READ_ONLY,
     * 默认的保持性可以调用 #getHoldability 方法获取
     *
     * @param sql           要发送到数据库的 SQL ,可以包含多个 ? 作为参数
     * @param resultSetType     结果集类型,可取值为 ResultSet.TYPE_FORWARD_ONLY、ResultSet.TYPE_SCROLL_INSENSITIVE、ResultSet.TYPE_SCROLL_SENSITIVE
     * @param resultSetConcurrency  结果集的并发性,可取值为 ResultSet.CONCUR_READ_ONLY,ResultSet.CONCUR_UPDATABLE
     * @param resultSetHoldability  结果集的保持性,可取的值为 ResultSet.HOLD_CURSORS_OVER_COMMIT、ResultSet.CLOSE_CURSORS_AT_COMMIT
     */ 
  CallableStatement prepareCall(String sql) throws SQLException;
  CallableStatement prepareCall(String sql, int resultSetType,  int resultSetConcurrency) throws SQLException;
  CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException;


2. 事务相关的 API

// 事务隔离级别:不支持事务隔离级别
int TRANSACTION_NONE             = 0;
// 事务隔离级别:读未提交
int TRANSACTION_READ_UNCOMMITTED = 1;
// 事务隔离级别:读已提交
int TRANSACTION_READ_COMMITTED   = 2;
// 事务隔离级别:可重复度
int TRANSACTION_REPEATABLE_READ  = 4;
// 事务隔离级别:序列号
int TRANSACTION_SERIALIZABLE     = 8;
// 设置事务隔离级别
void setTransactionIsolation(int level) throws SQLException;
// 获取事务隔离级别
int getTransactionIsolation() throws SQLException;
// 设置是否自动提交事务,默认情况执行完一条 SQL 后自动提交事务
void setAutoCommit(boolean autoCommit) throws SQLException;
// 获取是否自动提交事务
boolean getAutoCommit() throws SQLException;
// 提交事务
void commit() throws SQLException;
// 回滚事务
void rollback() throws SQLException;
// 设置事务的保存点,在事务内创建 rollback 将返回到该保存点,事务外创建新的事务将从该保存点开始
Savepoint setSavepoint() throws SQLException;
Savepoint setSavepoint(String name) throws SQLException;


3. 创建 JDBC 数据类型实例的 API


JDBC 中的数据类型并非每个关系型数据库都支持,数据类型后面加以介绍,Connection 可以创建的数据类型如下。


Clob createClob() throws SQLException;
Blob createBlob() throws SQLException;
NClob createNClob() throws SQLException;
SQLXML createSQLXML() throws SQLException;
Array createArrayOf(String typeName, Object[] elements) throws SQLException;
Struct createStruct(String typeName, Object[] attributes) throws SQLException;


4. 其他 API


// 获取数据库的元数据
DatabaseMetaData getMetaData() throws SQLException;
// 设置/获取客户端的信息
void setClientInfo(Properties properties) throws SQLClientInfoException;
Properties getClientInfo() throws SQLException;
// 终止/关闭打开的连接
void abort(Executor executor) throws SQLException;
void close() throws SQLException;
// 连接是否已经关闭
boolean isClosed() throws SQLException;
// 清除/获取数据库访问的警告信息
void clearWarnings() throws SQLException;
SQLWarning getWarnings() throws SQLException;
// 连接是否仍有效,即未关闭
boolean isValid(int timeout) throws SQLException;
// 设置/获取驱动等待数据库请求完成的毫秒数
void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException;
int getNetworkTimeout() throws SQLException;
// 设置/获取连接是否用于只读
void setReadOnly(boolean readOnly) throws SQLException;
boolean isReadOnly() throws SQLException;
// 设置/获取当前连接到的数据库
void setSchema(String schema) throws SQLException;
String getSchema() throws SQLException;
// 设置/获取当前连接创建的 Statement 可以获取到的 ResultSet 的保持性
void setHoldability(int holdability) throws SQLException;
int getHoldability() throws SQLException;



相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
21天前
|
Java 程序员 调度
Java中的多线程编程:基础知识与实践
【4月更文挑战第5天】 在现代软件开发中,多线程编程是一个不可或缺的技术要素。它允许程序员编写能够并行处理多个任务的程序,从而充分利用多核处理器的计算能力,提高应用程序的性能。Java作为一种广泛使用的编程语言,提供了丰富的多线程编程支持。本文将介绍Java多线程编程的基础知识,并通过实例演示如何创建和管理线程,以及如何解决多线程环境中的常见问题。
|
2天前
|
SQL Java 数据库连接
Java从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
ava从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
|
2天前
|
IDE Java 开发工具
Java从入门到精通:1.3.1实践编程巩固基础知识
Java从入门到精通:1.3.1实践编程巩固基础知识
|
2天前
|
Java
Java基础知识整理,驼峰规则、流程控制、自增自减
在这一篇文章中我们总结了包括注释、关键字、运算符的Java基础知识点,今天继续来聊一聊命名规则(驼峰)、流程控制、自增自减。
34 3
|
2天前
|
Java 开发者
Java基础知识整理,注释、关键字、运算符
在日常的工作中,总会遇到很多大段的代码,逻辑复杂,看得人云山雾绕,这时候若能言简意赅的加上注释,会让阅读者豁然开朗,这就是注释的魅力!
37 11
|
27天前
|
关系型数据库 Java 开发工具
Java入门高频考查基础知识9(15问万字参考答案)
本文探讨了Spring Cloud的工作原理,包括注册中心的心跳机制、服务发现机制,以及Eureka默认的负载均衡策略。同时,概述了Spring Boot中常用的注解及其实现方式,并深入讨论了Spring事务的注解、回滚条件、传播性和隔离级别。文章还介绍了MySQL的存储引擎及其区别,特别关注了InnoDB如何实现MySQL的事务处理。此外,本文还详细探讨了MySQL索引,包括B+树的原理和设计索引的方法。最后,比较了Git和SVN的区别,并介绍了Git命令的底层原理及流程。
32 0
Java入门高频考查基础知识9(15问万字参考答案)
|
27天前
|
存储 缓存 算法
Java入门高频考查基础知识4(字节跳动面试题18题2.5万字参考答案)
最重要的是保持自信和冷静。提前准备,并对自己的知识和经验有自信,这样您就能在面试中展现出最佳的表现。祝您面试顺利!Java 是一种广泛使用的面向对象编程语言,在软件开发领域有着重要的地位。Java 提供了丰富的库和强大的特性,适用于多种应用场景,包括企业应用、移动应用、嵌入式系统等。下是几个面试技巧:复习核心概念、熟悉常见问题、编码实践、项目经验准备、注意优缺点、积极参与互动、准备好问题问对方和知其所以然等,多准备最好轻松能举一反三。
56 0
Java入门高频考查基础知识4(字节跳动面试题18题2.5万字参考答案)
|
27天前
|
存储 算法 JavaScript
Java入门高频考查算法逻辑基础知识3-编程篇(超详细18题1.8万字参考编程实现)
解决这类问题时,建议采取下面的步骤: 理解数学原理:确保你懂得基本的数学公式和法则,这对于制定解决方案至关重要。 优化算法:了解时间复杂度和空间复杂度,并寻找优化的机会。特别注意避免不必要的重复计算。 代码实践:多编写实践代码,并确保你的代码是高效、清晰且稳健的。 错误检查和测试:要为你的代码编写测试案例,测试标准的、边缘情况以及异常输入。 进行复杂问题简化:面对复杂的问题时,先尝试简化问题,然后逐步分析和解决。 沟通和解释:在编写代码的时候清晰地沟通你的思路,不仅要写出正确的代码,还要能向面试官解释你的
33 0
|
27天前
|
存储 Java 编译器
Java入门高频考查基础知识2(超详细28题2.5万字答案)
多态是面向对象编程中的一个重要概念,它允许不同类的对象对同一消息作出不同的响应。在具体实现上,多态允许一个父类的引用指向其子类的对象,并根据实际指向的对象的类型来调用相应的方法。在 Java 中,多态可以通过以下几种方式实现:在同一个类中,方法名相同,但形参列表不同,实现了多态。子类可以重写(覆盖)其父类的方法,实现多态。在父类引用中调用该方法时,根据实际指向的子类对象的类型来调用相应的方法实现。
40 0
|
1月前
|
Java 数据库连接 API
Java 学习路线:基础知识、数据类型、条件语句、函数、循环、异常处理、数据结构、面向对象编程、包、文件和 API
Java 是一种广泛使用的、面向对象的编程语言,始于1995年,以其跨平台性、安全性和可靠性著称,应用于从移动设备到数据中心的各种场景。基础概念包括变量(如局部、实例和静态变量)、数据类型(原始和非原始)、条件语句(if、else、switch等)、函数、循环、异常处理、数据结构(如数组、链表)和面向对象编程(类、接口、继承等)。深入学习还包括包、内存管理、集合框架、序列化、网络套接字、泛型、流、JVM、垃圾回收和线程。构建工具如Gradle、Maven和Ant简化了开发流程,Web框架如Spring和Spring Boot支持Web应用开发。ORM工具如JPA、Hibernate处理对象与数
94 3