java pgsql connection 是否可同时执行sql_Java-11-JDBC

什么是 JDBC

JDBC 是 Java Data Base Connectivity 的缩写,指的是 Java 提供了一些访问数据库的统一接口。如果我们在 Java 中想要访问数据库,就要使用 JDBC。

连接数据库

在连接数据库之前,我们要确保有 3 个信息:

  1. 数据库连接串
  2. 用户名
  3. 密码

有了这 3 个东西,我们就可以连接任意一个数据库,这里我们用 IDEA 中的 DataBase 功能,启动一个 H2 数据库。

当我们启动数据库后,我们使用 DriverManagergetConnection 方法来返回一个数据库连接(注意 Connection 是要关闭的,这里我们使用了 try...resource 自动关闭)

package com.github.hcsp.exception;

import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class Main {
    public static void main(String[] args) {
        File projectDir = new File(System.getProperty("basedir", System.getProperty("user.dir")));
        String jdbcUrl = "jdbc:h2:file:" + new File(projectDir, "learn").getAbsolutePath();
        try (Connection connection = DriverManager.getConnection(jdbcUrl, "", "")) {
            System.out.println(jdbcUrl);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
            throw new RuntimeException("数据库连接异常");
        }
    }
} 

当我们运行的时候,可能会遇到这种错误:

16cb2b75552e8b0c4a1c2a9633852c12.png

Java 连接数据库的时候,需要相应的数据库驱动,由于我们用的是 H2 数据库,所以就安装 h2 的驱动:

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.199</version>
            <scope>compile</scope>
        </dependency>

再试一下,发现没有报错,那就说明我们成功连接上数据库了。由于我们本地的数据库处于测试目的,没有账号和密码,如果有的话,只要在 getConnection 方法中传入就可以了。

执行 SQL 语句

那连接上数据库以后,我们就可以执行 SQL 语句了。

connection.createStatement 可以创建一个 SQL 语句,它也是需要 close 的,然后使用 executeQuery 来执行语句。

ResultSet 是一串数据,调用 next 方法取出来的是一行数据,我们可以使用相应的 get 方法,依次取出每一列的数据,它的列是从 1 开始的。

package com.github.hcsp.exception;

import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Main {
    public static void main(String[] args) {
        File projectDir = new File(System.getProperty("basedir", System.getProperty("user.dir")));
        String jdbcUrl = "jdbc:h2:file:" + new File(projectDir, "learn").getAbsolutePath();
        try (Connection connection = DriverManager.getConnection(jdbcUrl, "", "");
             Statement statement = connection.createStatement()) {
            final ResultSet resultSet = statement.executeQuery("select * from USERS_DATA");
            while (resultSet.next()) {
                System.out.println("用户ID 是 " + resultSet.getInt(1));
                System.out.println("用户名称 是 " + resultSet.getString(2));
            }
            System.out.println(jdbcUrl);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
            throw new RuntimeException("数据库连接异常");
        }
    }
}

到这里,我们就实现了用 Java 代码连接数据库,并且执行 SQL 语句的功能。

可以看到,由于 Java 的封装性,假如未来我们更换数据库的话,只要把连接串改一改就可以了,下面的所有方法,都是调用的接口类型的方法,所以是通用的。

SQL 注入

SQL 注入是指在输入的字符串之中注入SQL指令,在设计不良的程序当中忽略了字符检查,那么这些注入进去的恶意指令就会被数据库服务器误认为是正常的SQL指令而运行,因此遭到破坏或是入侵。(维基百科)

假设我们现在有个需求,是由客户端输入一个用户名,查询某个用户是否存在。我们可能会这样实现:

public class Main {
    public static void main(String[] args) {
        final boolean isUserExist = checkUserExist("zzh1");
        System.out.println(isUserExist);
    }

    public static boolean checkUserExist(String userName) {
        File projectDir = new File(System.getProperty("basedir", System.getProperty("user.dir")));
        String jdbcUrl = "jdbc:h2:file:" + new File(projectDir, "learn").getAbsolutePath();
        try (Connection connection = DriverManager.getConnection(jdbcUrl, "", "");
             Statement statement = connection.createStatement()) {
            final ResultSet resultSet = statement.executeQuery("select * from USERS_DATA where name = '" + userName + "'");
            return resultSet.next();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
            throw new RuntimeException("数据库连接异常");
        }
    }
}

看上去没什么问题,其实这个代码非常危险,因为我们已经假定了传入的字符串都是正常的用户名,但是对于由用户输入的所有数据,都要看作是不可信的。

假如现在传入的不是 zzh1 这种字符串,而是 zzh1;delete from USERS_DATA where ID = 2; 这种包含 SQL 语句的字符串,我们这样拼接上去的话,就导致执行了攻击者的 SQL 语句。

所以 SQL 注入的重点,实际上是我们不能完全信任由用户输入的数据,并且把这些数据拼接到 SQL 语句上。

PrepareStateMent

PrepareStateMent 可以解决这个问题,它在创建 SQL 语句的时候,使用 ? 作为占位符,采用参数传入的形式,即参数只会作为参数,而不会改变已经传入的 SQL 语句的结构。

public class Main {
    public static void main(String[] args) {
        final boolean isUserExist = checkUserExist("zzh");
        System.out.println(isUserExist);
    }

    public static boolean checkUserExist(String userName) {
        File projectDir = new File(System.getProperty("basedir", System.getProperty("user.dir")));
        String jdbcUrl = "jdbc:h2:file:" + new File(projectDir, "learn").getAbsolutePath();
        try (Connection connection = DriverManager.getConnection(jdbcUrl, "", "");
             PreparedStatement statement = connection.prepareStatement("select * from USERS_DATA where name = ?")) {
            statement.setString(1, userName);
            final ResultSet resultSet = statement.executeQuery();
            return resultSet.next();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
            throw new RuntimeException("数据库连接异常");
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值