JDBC应用程序接口

2020/07/04 程序

Java Database Connectivity(JDBC),是Java语言中用来规范客户端程序访问数据库的API,提供了查询、插入、更新数据库中数据的方法。下面将简单探讨JDBC的基础知识,以及关于JDBC driver的开源实现。

基本概念

JDBC是一种规范,提供完整的接口供应用程序访问底层数据库。简单的说JDBC是Java应用程序与不同数据库的连接桥梁,使用Java就能对数据库进行CURD操作。由于在现实中数据库是由不同的生产厂商决定的,例如MySQL、OceanBase、ODPS等等,数据库厂商根据JDBC规范实现了各自的应用驱动程序,用户可以根据实际情况调用对应的驱动来访问数据库。

在使用JDBC的过程中主要使用到4个接口

  • Driver接口: Driver接口一般是由数据库厂家提供,应用程序只需要调用相应的接口就可以了。例如下面分别连接MySQL与Oracle时装载的驱动程序:

      Class.forName("com.mysql.jdbc.Driver");
      Class.forName("oracle.jdbc.driver.OracleDriver");
    
  • Connection接口: 该接口主要负责与特定数据库创建链接,提交SQL语句并接收返回结果。例如创建MySQL数据库的链接过程:

      Connection conn = DriverManager.getConnection("jdbc:mysql://host:port/database", "user", "password");
    

    下面是一些常用的方法。

      // 创建Statement对象,该对象封装String类型的SQL语句。
      conn.createStatement();
    
      // 创建PrepareStatement对象,该对象封装了预编译的SQL语句。
      conn.prepareStatement();
    
      // 提交事务
      conn.commit();
    
      // 回滚事务
      conn.rollback();
    
  • Statement接口: 用于执行静态SQL语句并返回它所生成结果的对象。Statement接口有三类,分别是:

    • Statement: 提供执行语句和获取结果的基本方法,对数据库进行通用访问,支持批量更新、批量删除。一般用于执行静态SQL语句,不接受参数。

    • PreparedStatement: 继承自Statement,支持可变参数的SQL语句,添加了处理IN参数的方法,安全性比较好。

    • CallableStatement: 继承自PreparedStatement,支持调用存储过程。

    常见的Statement方法有:

      // 运行语句
      statement.execute(String SQL);
    
      // 运行Select语句,返回结果集
      statement.executeQuery(String SQL);
    
      // 运行Insert、Update、Delete语句,返回更新的行数
      statement.executeUpdate(String SQL);
    
      // 向数据库发送一批SQL语句
      statement.executeBatch();
    
  • ResultSet接口: 该接口提供对不同类型字段检索的方法。常用的有:

      resultSet.getString()
      resultSet.getFloat()
      resultSet.getDate()
      resultSet.getBoolean()
      resultSet.getObject()
    

JDBC的运行过程

应用JDBC的过程中一般经历这么几个阶段。

注册驱动程序

例如要对MySQL数据库进行访问,调用MySQL的JDBC驱动。

Class.forName("com.mysql.jdbc.Driver");

建立数据库连接Connection

String url = "jdbc:mysql://host:port/database";
Connection conn = DriverManager.getConnection(url, user, password);

创建执行SQL语句的Statement

String id = "1";
String sql = "DELETE FROM table WHERE id =" + id;
Statement st = conn.createStatement();
st.executeQuery(sql);

上述的方法中存在SQL注入的危险,因为sql语句是简单的拼接,如果传入的id变量的值为”1 or 1=1”,那么将会删除表中的所有记录。

String sql = "INSERT INTO user (name, pwd) VALUES (?,?)";
PreparedStatement ps = conn.preparedStatement(sql);
ps.setString(1, "col_value");
ps.setString(2, "123456");
ps.executeQuery();

上述的方法中能够防止SQL注入,因为sql语句在程序运行前已经完成了编译,在运行时动态把参数传入到PreparedStatement时,传入的内容被转义为字段的属性值而不是SQL语句。

获得执行结果ResultSet

ResultSet rs = ps.executeQuery();
while(rs.next()){
    rs.getString("col_name");
    rs.getInt(1);
}

释放资源

resultSet.close();
statement.close();
connection.close();

Apache Calcite进行JDBC多数据源关联

Apache Calcite是一个动态数据管理系统,提供标准的SQL语言、多种查询优化和连接各种数据源的能力,是在大数据领域中常见的查询引擎。Calcite的目标是“one size fits all”(一种方案适应所有需求场景),希望为不同计算平台和数据源提供统一的查询引擎。由于Calcite本身与数据存储和处理的逻辑无关,因此它成为了与多个数据存储位置(数据源)和多种数据处理引擎之间进行联调的解决方案。

假设有一个场景,我们需要从两个不同的数据库中读取数据并进行关联,这个过程可以使用Calcite的JDBC Adapter来实现。下面是一个简单的例子:

public void multiSourceTest() throws SQLException {
    Properties config = new Properties();
    config.put("model", TestUtil.resourcePath("multiSource.json"));
    config.put("lex", "MYSQL");
    String sql ="/*SQL*/";

    try (Connection con = DriverManager.getConnection("jdbc:calcite:", config)) {
        try (Statement stmt = con.createStatement()) {
            try (ResultSet rs = stmt.executeQuery(sql)) {
                printRs(rs);
            }
        }
    }
}

上述代码跟JDBC的调用过程类似,先建立Connection,然后创建Statement并执行SQL语句,然后获得返回结果ResultSet。Calcite架构中定义了Adapter概念,每个数据源的Adapter定义了model、schema、schema Factory。model定义了数据源的物理属性,也即是后端数据库的基本属性。上述代码中首先定义了model,获取不同数据源的属性。将lex设定为MYSQL可以在内部解析验证SQL过程中忽略大小写敏感。我的个人理解是Calcite的JDBC相比于其他JDBC驱动能够支持对不同数据源的操作。

Apache Calcite Avatica

Avatica是Calcite项目的一个子项目,这是一个构建数据库驱动程序的框架。上面看到的很多代码实例都是讲述客户端如何使用JDBC驱动来连接数据库进行操作,那么如何实现自己的JDBC驱动呢?这是我目前正在学习摸索中的问题,后面会再补充新的文章。

在Avatica中有三个核心的概念,通过AvaticaFactory来实现JDBC的4个重要接口(Driver,Connection,Statement,ResultSet),下面是官网的描述:

- Meta: Meta is a local API sufficient to implement any Avatica provider.
- AvaticaFactory: AvaticaFactory creates implementations of the JDBC classes on top of a Meta.
- Service: Service is an interface that implements the functions of Meta in terms of request and response command objects.

参考资料

  1. 使用Apache Calcite进行JDBC多数据源关联,https://zhuanlan.zhihu.com/p/143935885
  2. Apache顶级项目Calcite使用介绍,https://www.sohu.com/a/296117762_100123073
  3. 基于Calcite自定义JDBC Driver,https://blog.csdn.net/dafei1288/article/details/103485689
  4. Calcite Avatica,https://calcite.apache.org/avatica/docs/index.html

Search

    Table of Contents