【JDBC】preparedstatement基本使用流程

一、引出问题

statement在执行SQL语句之前,需要我们自己完成SQL语句的拼接

String sql = "select * from employee where account = '" + account + "' and password = '" + password + "';";

1、只能拼接字符串类型,如果你数据库有一个字符串数组,它是拼接不了的。

2、如果字段很多,拼接也很麻烦。

3、可能发生注入攻击。动态值充当了SQL语句结构,影响了原有的查询结果!

例如:or '1' = '1' 是永远成立的,此时就产生注入攻击了。

image-20240725161918391

因此statement只适合执行静态的SQL语句,即没有任何动态条件值的SQL语句,如果有多个条件值,它会发生注入攻击。

而PreparedStatement叫做预编译,它会提前知道你的SQL结构,然后再给对应的结构动态赋值,不会让它充当SQL的部分,防止了注入攻击。


二、PreparedStatement和Statement步骤对比

PreparedStatement是Statement的一个子接口

image-20240725182133590
statement
     1.创建statement
     2.拼接SQL语句
     3.发送SQL语句,并且获取返回结果
  
preparedstatement
     1.编写SQL语句结果 不包含动态值部分的语句,动态值部分使用占位符 ? 替代
       PS:? 只能替代动态值
     2.创建preparedstatement,并且传入SQL语句
     3.动态值 占位符 赋值 ? 单独赋值即可
     4.发送SQL语句即可,并获取返回结果

PS:statement是在发送SQL语句的时候传入的sql,而preparedstatement是在创建预编译statement的时候就发送了sql语句!

正是因为提前告知了SQL语句的结构,如果当外人任然使用动态值充当了SQL语句结构,此时就会直接执行失败。


三、使用PreparedStatement解决

package com.atguigu.api.PreparedStatement;

import java.sql.*;
import java.util.Scanner;

/**
 * TODO:防止注入攻击  |   演示ps的使用流程
 */
public class PSUserLoginPart {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入id");
        int id = scanner.nextInt();

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

        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/itcast", "root", "123456");

        //3.编写SQL语句结果
        String sql = "select * from employee where id = ?;";

        //4.创建预编译statement并且设置SQL语句结果
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        //5.单独占位符进行赋值
        /**
         * 参数1:index,占位符的位置,从左向右数,从1开始
         * 参数2:object,占位符的值,可以设置任何类型的数据,避免了我们凭借和类型更加丰富
         */
        //其实是可以写getInt的,但建议统一写Object,因为这样就不需要考虑了
        preparedStatement.setObject(1, id);
        //如果有多个 ? 占位符的话,需要使用多个preparedStatement.setObject
        //6.发送SQL语句,并返回返回结果!
        // 此时就不需要传sql了,因为它已经知道语句动态值了!
        ResultSet resultSet = preparedStatement.executeQuery(); 

        //7.结果集解析
        while(resultSet.next()) {
            int id1 = resultSet.getInt("id");
            String salary = resultSet.getString("salary");
            System.out.println(id1 + "--" + salary);
        }

        //8.关闭资源
        connection.close();
        preparedStatement.close();
        resultSet.close();
    }
}

四、为啥PreparedStatement能解决注入攻击?

Statement

  1. SQL语句 + 动态值

    • 拼接完整SQL
    • 此位置可能发生注入攻击!statement也无法识别!
  2. Statement

    • 执行拼接好的SQL语句
    • 返回结果

PreparedStatement

  1. SQL语句(使用占位符) + 动态值

    • PreparedStatement
    • 占位符赋值
    • 此处动态值赋值,PreparedStatement已经知道语句结构!没法篡改!
  2. PreparedStatement

    • 执行完整的SQL语句
    • 返回结果
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值