JDBC的简单使用

JDBC的简单使用

微信搜索 zze_coding 或扫描 👉 二维码关注我的微信公众号获取更多资源推送:

介绍

JDBC(Java Data Base Connectivity,Java 数据库连接)是一种用于执行 SQL 语句的 Java API,可以为多种关系数据库提供统一访问,它由一组用 Java 语言编写的类和接口组成。JDBC 提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序,同时,JDBC 也是个商标名。

有了 JDBC,向各种关系数据发送 SQL 语句就是一件很容易的事。换言之,有了J DBC API,就不必为访问 Sybase 数据库专门写一个程序,为访问 Oracle数据库又专门写一个程序,或为访问 Informix 数据库又编写另一个程序等等,程序员只需用 JDBC API 写一个程序就够了,它可向相应数据库发送 SQL 调用,将 Java 语言和 JDBC 结合起来使程序员只须写一遍程序就可以让它在任何平台上运行。

Java 数据库连接体系结构是用于 Java 应用程序连接数据库的标准方法。JDBC 对 Java 程序员而言是 API,对实现与数据库连接的服务提供商而言是接口模型。作为 API,JDBC 为程序开发提供标准的接口,并为数据库厂商及第三方中间件厂商实现与数据库的连接提供了标准方法。JDBC 使用已有的 SQL 标准并支持与其它数据库连接标准,如 ODBC 之间的桥接。JDBC 实现了所有这些面向标准的目标并且具有简单、严格类型定义且高性能实现的接口。

使用

Statement

在 JDBC 提供的 API 中,我们可以通过 DB 连接对象来获取一个 Statement 对象,通过这个对象我们可以使用 Java 代码来连接数据库、执行 SQL 语句。

Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
    // 注册驱动
    Class.forName("com.mysql.jdbc.Driver");
    // 建立连接:url:协议+访问的数据库 user:用户名 password:密码
    connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/1221?serverTimezone=GMT&characterEncoding=utf8", "root", "root");
    // 创建statement
    statement = connection.createStatement();
    // 执行查询
    String sql = "select * from user";
    resultSet = statement.executeQuery(sql);
    while (resultSet.next()) {
    int id = resultSet.getInt("id");
    String name = resultSet.getString("name");
    System.out.println(String.format("%s:%s", id, name));
    }
} catch (Exception ex) {
    ex.printStackTrace();
} finally {
    try {
        resultSet.close();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        resultSet = null;
    }
    try {
        statement.close();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        statement = null;
    }
    try {
        connection.close();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        connection = null;
    }
}

PreparedStatement

相比较之前的 StatementPreparedStatement 会预先处理给定的 sql 语句,对其执行语法检查。 在 sql 语句里面使用 ‘?’ 占位符来替代后续要传递进来的变量。 后面进来的变量值,将会被看成是字符串,不会产生任何的关键字。

Connection connection = null;
PreparedStatement statement = null;
try {
    Class.forName("com.mysql.jdbc.Driver");
    connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb?serverTimezone=GMT&characterEncoding=utf8", "root", "root");
    String sql = "insert into user (name) values (?)";
    statement = connection.prepareStatement(sql);
    statement.setString(1, "王五");
    int flag = statement.executeUpdate();
    System.out.println(flag);
    if (flag > 0) {
        System.out.println("添加成功");
    } else {
        System.out.println("添加失败");
    }
} catch (Exception ex) {
    ex.printStackTrace();
} finally {
    try {
        statement.close();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        statement = null;
    }
    try {
        connection.close();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        connection = null;
    }
}

使用 PreparedStatement 的几个理由

在 JDBC 应用中,如果你已经是稍有水平的开发者,你就应该始终以 PreparedStatement 代替 Statement。也就是说,在任何时候都不要使用 Statement。基于以下的原因:

1、代码的可读性和可维护性。虽然用 PreparedStatement 来代替 Statement 会使代码多出几行,但这样的代码无论从可读性还是可维护性上来说,都比直接用 Statement 的代码高很多档次。看如下例子:

// 使用 Statement
stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");
// 使用 PreparedStatement
perstmt = con.prepareStatement("insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)");
perstmt.setString(1,var1);
perstmt.setString(2,var2);
perstmt.setString(3,var3);
perstmt.setString(4,var4);
perstmt.executeUpdate();

不用我多说,对于第一种方法。别说其他人去读你的代码,就是你自己过一段时间再去读,都会觉得伤心。

2、PreparedStatement 尽最大可能提高性能。每一种数据库都会尽最大努力对预编译语句提供最大的性能优化,因为预编译语句有可能被重复调用,所以语句在被 DB 的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中(相当于一个函数)就会得到执行。这并不是说只有一个 Connection 中多次执行的预编译语句被缓存,而是对于整个 DB 中,只要预编译的语句语法和缓存中匹配,那么在任何时候就可以不需要再次编译而可以直接执行。而 Statement 的语句中,即使是相同的操作,而由于每次操作的数据不同所以使整个语句相匹配的机会极小,几乎不太可能匹配。如:

insert into tb_name (col1,col2) values ('11','22');
insert into tb_name (col1,col2) values ('11','23');

即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义。事实是没有数据库会对普通语句编译后的执行代码缓存,所以每执行一次都要对传入的语句编译一次。

当然并不是所以预编译语句都一定会被缓存,数据库本身会用一种策略,比如使用频度等因素来决定什么时候不再缓存已有的预编译结果,从而保留有更多的空间存储新的预编译语句。

3、最重要的一点是极大地提高了安全性。即使到目前为止,仍有一些人连基本的恶义 SQL 语法都不知道。

String sql = "select * from tb_name where name= '"+varname+"' and passwd='"+varpasswd+"'";

如果我们把 ' or '1' = '1 作为 varpasswd 传入进来,用户名随意,看看会有什么效果。

select * from tb_name = '随意' and passwd = '' or '1' = '1';

因为 '1'='1' 肯定成立,所以可以任何通过验证。更有甚者,把 ';drop table tb_name; 作为 varpasswd 传入进来,结果则是:

select * from tb_name = '随意' and passwd = '';drop table tb_name;

有些数据库是不会让你成功的,但也有很多数据库就可以使这些语句得到执行。而如果你使用预编译语句,你传入的任何内容就不会和原来的语句发生任何匹配的关系(前提是数据库本身支持预编译,但目前可能没有什么服务端数据库不支持编译了,只有少数的桌面数据库,就是直接文件访问的那些)只要全使用预编译语句,你就用不着对传入的数据做任何过滤。而如果使用普通的 Statement, 有可能要对 drop 等关键字做费尽心机的判断和过滤。

上面的几个原因,还不足让你在任何时候都使用 PreparedStatement 吗?

小结

选择 PreparedStatement 还是 Statement 取决于你要怎么使用它们。对于只执行一次的 SQL 语句选择 Statement 是最好的。相反, 如果 SQL 语句被多次执行的话选用 PreparedStatement 是最好的。

PreparedStatement 的第一次执行消耗是很高的,它的性能体现在后面的重复执行。例如,假设我使用 PreparedStatement 的方式来执行一个没有参数的查询。JDBC 驱动会发送一个网络请求到数据解析和优化这个查询,而实际执行时会产生另一个网络请求。在 JDBC 驱动中,减少网络通讯是最终的目的。所以如果我们的程序在运行期间只需要一次请求, 那么就使用 Statement 。对于 Statement, 同一个查询只会产生一次网络到数据库的通讯。

  • PreparedStatement 是预编译的,对于批量处理可以大大提高效率,而且可以防止 SQL 注入。
  • 在对数据库只执行一次性存取的时侯,建议用 Statement 对象进行处理。因为 PreparedStatement 对象的开销比 Statement 大,对于一次性操作并不会带来额外的好处。
  • Statement 每次执行 SQL 语句,相关数据库都要执行 SQL 语句的编译,而 PreparedStatement 是预编译的,且支持批处理。

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://www.zze.xyz/archives/java-jdbc.html

Buy me a cup of coffee ☕.