Java 基础知识之 JDBC(上)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 什么是 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;



相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
3月前
|
Java 关系型数据库 数据库连接
JDBC:Java与数据库的“黄金搭档”,为何它如此重要?
JDBC:Java与数据库的“黄金搭档”,为何它如此重要?
48 8
|
3月前
|
Java 数据库连接 API
JDBC:Java数据库连接的“黑科技”大揭秘
JDBC:Java数据库连接的“黑科技”大揭秘
38 7
|
3月前
|
SQL Java 数据库连接
为何JDBC是Java开发者的“心头好”?原因竟然这么简单!
为何JDBC是Java开发者的“心头好”?原因竟然这么简单!
40 3
|
1月前
|
SQL Java 数据库连接
如何在 Java 脚本中有效地使用 JDBC
如何在 Java 脚本中有效地使用 JDBC
17 0
|
3月前
|
SQL Java 关系型数据库
【前端学java】JDBC快速入门
【8月更文挑战第12天】JDBC快速入门
32 2
【前端学java】JDBC快速入门
|
3月前
|
SQL Java 数据库连接
JDBC之旅:从陌生到熟悉的Java数据库连接之路
JDBC之旅:从陌生到熟悉的Java数据库连接之路
30 9
|
3月前
|
SQL Java 关系型数据库
探索Java数据库连接的奥秘:JDBC技术全攻略
探索Java数据库连接的奥秘:JDBC技术全攻略
58 8
|
3月前
|
SQL Java 数据库连接
Java开发者必知:JDBC连接数据库的“三大法宝”
Java开发者必知:JDBC连接数据库的“三大法宝”
35 7
|
3月前
|
SQL 安全 Java
JDBC:Java与数据库的“月老红线”,你真的了解它吗?
JDBC:Java与数据库的“月老红线”,你真的了解它吗?
22 1
|
3月前
|
SQL Java 数据库连接
深入剖析JDBC:Java与数据库沟通的“桥梁”与“秘密”
深入剖析JDBC:Java与数据库沟通的“桥梁”与“秘密”
24 0