JDBC预处理对象prepareStatement[通俗易懂]

JDBC预处理对象prepareStatement[通俗易懂]JDBC预处理对象prepareStatement概述一、SQL注入问题SQL注入:用户输入的内容作为了SQL语句语法的一部分,改变了原有SQL真正的意义。假设有登录案例SQL语句如下:SELECT*FROM用户表WHERENAME=用户输入的用户名ANDPASSWORD=用户输的密码;此时,当用户输入正确的账号与密码后,查询到了信息则让用户登录。但是当用户输入的账…

大家好,又见面了,我是你们的朋友全栈君。

JDBC预处理对象prepareStatement概述

一、SQL注入问题

SQL注入:用户输入的内容作为了SQL语句语法的一部分,改变了原有SQL真正的意义。
假设有登录案例SQL语句如下:
SELECT * FROM 用户表 WHERE NAME = 用户输入的用户名 AND PASSWORD = 用户输的密码;
此时,当用户输入正确的账号与密码后,查询到了信息则让用户登录。但是当用户输入的账号为XXX 密码为:XXX’ OR ‘a’=’a时,则真正执行的代码变为:
SELECT * FROM 用户表 WHERE NAME = ‘XXX’ AND PASSWORD =’ XXX’ OR ’a’=’a’;
此时,上述查询语句时永远可以查询出结果的。那么用户就直接登录成功了,显然我们不希望看到这样的结果,这便是SQL注入问题。
为此,我们使用PreparedStatement来解决对应的问题。

二、代码演示SQL注入问题

(1)数据库准备

代码如下:

#创建sql_into数据库
CREATE DATABASE sql_into;
#使用sql_into数据库
USE sql_into;
#创建sql_into用户表
CREATE TABLE users(
 uid INT PRIMARY KEY AUTO_INCREMENT,
 username VARCHAR(200),
 PASSWORD VARCHAR(200) 
);
#加入用户信息
INSERT INTO users(username,PASSWORD) VALUES('xiaoming','123'),('xiaoliang','456');
#查询用户信息
SELECT *FROM users;

mysql代码演示
mysql代码演示

(2)创建用户登录界面

public class StatementMyCode {
    public static void main(String[] args) throws SQLException {
        Scanner sc=new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username =sc.nextLine();
        System.out.println("请输入密码:");
        String password=sc.nextLine();
//获取JDBCUtils连接
        Connection con=JDBCUtils1.getConnection();
        //Connection con= JDBCUtils1.getConnection();
//获取Statedment对象
        Statement stat=con.createStatement();
//执行SQL语句
        String sql = "select * from users where username='"+username+"' and password ='"+password+"'";
        System.out.println(sql);
        ResultSet rs=stat.executeQuery(sql);
        if(rs.next()){
            System.out.println("登录成功!");
        }else{
            System.out.println("登录失败!");
        }
        JDBCUtils1.close(rs,stat,con);
    }
}

SQL注入出现的登录BUG
SQL注入出现的登录BUG

(3)配置文件代码

配置文件代码文件名需要和JDBCUtils1里的工具类的配置文件保持一致,配置文件代码文件名为config.properties
className=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/sql_into
user=root
password=root

(4)JDBCUtils1文件代码

public class JDBCUtils1 {
    private static String url;
    private static String user;
    private static String password;
    private static String className;
    private JDBCUtils1(){}
   static {
        try{
            Properties p=new Properties();
            InputStream in = JDBCUtils1.class.getClassLoader().getResourceAsStream("config.properties");
            p.load(in);
            in.close();
            url=p.getProperty("url");
            user=p.getProperty("user");
            password=p.getProperty("password");
            className=p.getProperty("className");
            //注册驱动
            Class.forName(className);
        }catch (Exception e){
            e.printStackTrace();
        }
}
    public static Connection getConnection(){
        //获取连接
        Connection con=null;
        try {
        con= DriverManager.getConnection(url,user,password);
            return con;
        } catch (SQLException e) {

            throw new RuntimeException("连接失败");
        }
    }
    public static void close(ResultSet rs, Statement stat,Connection con){
        try {
            if(rs!=null)
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if(stat!=null)
            stat.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (con!=null)
            con.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

三、防止SQL注入 使用预处理对象

(1)原理介绍

preparedStatement:预编译对象,是Statement对象的子类。
特点:

  • 性能高
  • 会把sql语句先编译
  • 能过滤掉用户输入的关键字。
    PreparedStatement预处理对象,处理的每条sql语句中所有的实际参数,都必须使用占位符?替换。
    String sql = "select * from user where username = ? and password = ?";

PreparedStatement使用,需要通过以下3步骤完成:

  1. PreparedStatement预处理对象代码:
    // 获得预处理对象,需要提供已经使用占位符处理后的SQL语句
    PreparedStatement psmt = conn.prepareStatement(sql)
  2. 设置实际参数
    void setXxx(int index, Xxx xx) 将指定参数设置指定类型的值
    参数1:index 实际参数序列号,从1开始。
    参数2:xxx 实际参数值,xxx表示具体的类型。
    例如:
    setString(2, “1234”) 把SQL语句中第2个位置的占位符?替换成实际参数 “1234”
  3. 执行SQL语句:
    int executeUpdate(); –执行insert update delete语句.
    ResultSet executeQuery(); –执行select语句.
    boolean execute(); –执行select返回true 执行其他的语句返回false.

(2)使用preparedStatement

用户登录界面代码演示

public class prepareStatementMyCode {
    public static void main(String[] args) throws SQLException {
        Scanner sc=new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username =sc.nextLine();
        System.out.println("请输入密码:");
        String password=sc.nextLine();
//获取JDBCUtils连接
        Connection con=JDBCUtils1.getConnection();
        //Connection con= JDBCUtils.getConnection();
//获取Statedment对象
        Statement stat=con.createStatement();
//执行SQL语句
        String sql = "select * from users where username=? and password =?";
        PreparedStatement ps = con.prepareStatement(sql);
        ps.setObject(1,username);
        ps.setObject(2,password);
        System.out.println(sql);
        ResultSet rs=ps.executeQuery();
        if(rs.next()){
            System.out.println("登录成功!");
        }else{
            System.out.println("登录失败!");
        }
        JDBCUtils1.close(rs,stat,con);
    }
}

正确执行代码演示结果
正确执行代码演示
SQL注入代码演示
SQL注入代码演示

四、使用prepareStatement完成查询数据

代码如下:

public class prepareStatementCSDNSelect {
    public static void main(String[] args) {
        //获取连接对象
        Connection con=null;
        PreparedStatement ps= null;
        ResultSet rs = null;
        try {
            con= JDBCUtils1.getConnection();
            String sql="select * from users";
            ps = con.prepareStatement(sql);
            rs = ps.executeQuery();
            while(rs.next()){
                int uid=rs.getInt("uid");
                String username=rs.getString("username");
                String password=rs.getString("password");
                System.out.println(uid+"  "+username+"  "+password);
            }
        } catch (SQLException e) {
           throw  new RuntimeException(e);
        }finally {
            JDBCUtils1.close(rs,ps,con);
        }
    }
}

使用prepareStatement完成查询
使用prepareStatement完成查询

五、使用prepareStatement和javabean类完成查询

(1)创建user1类

代码如下:

/*一个类具备私有成员变量 空参构造方法  get/set 方法   实现序列化接口 那么称这个类为javabean类*/
public class User1 {
    private int uid;
    private String username;
    private   String password;
    public User1() {
    }

    public User1(int uid, String username, String password) {
        this.uid = uid;
        this.username = username;
        this.password = password;
    }

    public int getUid() {
        return uid;
    }

    public void setUid(int uid) {
        this.uid = uid;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User1{" +
                "uid=" + uid +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

(2)使用把每条记录封装到user1对象中 将多个user1对象放到list集合当中

/*查询所有记录 把每条记录封装到user1对象中 将多个user1对象放到list集合当中*/
public class prepareStatementCSDNSelectBean {
    public static void main(String[] args) {
        //获取连接对象
        Connection con=null;
        PreparedStatement ps= null;
        ResultSet rs = null;
        try {
            con= JDBCUtils1.getConnection();
            String sql="select * from users";
            ps = con.prepareStatement(sql);
            rs = ps.executeQuery();
            //定义一个集合用来存储user对象
            List<User1>  list=new ArrayList<>();
            while(rs.next()){
                int uid=rs.getInt("uid");
                String username=rs.getString("username");
                String password=rs.getString("password");
                User1 u=new User1(uid,username,password);
                list.add(u);

               // System.out.println(uid+"  "+username+"  "+password);
            }
            System.out.println(list);
        } catch (SQLException e) {
           throw  new RuntimeException(e);
        }finally {
            JDBCUtils1.close(rs,ps,con);
        }
    }
}

查询结果演示
查询结果演示

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/137857.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • tcp为什么是三次握手不是两次握手_tcp四次挥手

    tcp为什么是三次握手不是两次握手_tcp四次挥手一、为什么握手是三次,而不是两次或者四次?答:两次不安全,四次没必要。tcp通信需要确保双方都具有数据收发的能力,因此双方都要发送SYN确保对方具有通信的能力二、为什么挥手是四次而不是三次?答:发送FIN包只能表示对方不再发送数据了,不代表对方不再接收数据,因此被动关闭方进行ACK回复之后有可能还会继续发送数据,等到不再发送数据了才会发送下一个FIN包,因此FIN包和ACK包是分开的…

    2022年10月3日
    4
  • opencv lsd算法_opencv目标识别

    opencv lsd算法_opencv目标识别最小二乘法的概念最小二乘法要关心的是对应的costfunction是线性还是非线性函数,不同的方法计算效率如何,要不要求逆,矩阵的维数一般都是过约束,方程式的数目多于未知的参数数目。最小二乘法的目标:求误差的最小平方和,根据costfunction的对应有两种:线性和非线性(取决于对应的残差(residual)是线性的还是非线性的)。线性最小二乘的解是closed-formsolution …

    2022年10月1日
    2
  • 怎么新建pytest的ini文件_qt读写配置文件

    怎么新建pytest的ini文件_qt读写配置文件前言pytest配置文件可以改变pytest的运行方式,它是一个固定的文件pytest.ini文件,读取配置信息,按指定的方式去运行查看pytest.ini的配置选项pytest-h找到以下

    2022年7月29日
    9
  • 粒子群算法详解

    粒子群算法详解一.产生背景  ❃粒子群算法(particleswarmoptimization,PSO)由Kennedy和Eberhart在1995年提出,该算法对于Hepper的模拟鸟群(鱼群)的模型进行修正,以使粒子能够飞向解空间,并在最好解处降落,从而得到了粒子群优化算法。❃同遗传算法类似,也是一种基于群体叠代的,但并没有遗传算法用的交叉以及变异,而是粒子在解空间追随最优的粒子进行搜索。

    2022年6月10日
    33
  • 放在u盘根目录就可运行的efi shell_U盘PE启动安装Win7系统教程(微PE版)

    放在u盘根目录就可运行的efi shell_U盘PE启动安装Win7系统教程(微PE版)本教程讲述如何通过微PE制作U盘PE启动盘来安装纯净无捆绑的Win7GHO镜像,U盘装系统的优点在于灵活性更强兼容性更好,支持BIOS+MBR和EFI+GPT下安装,即使原系统启动不了也能装。下面以安装专注于win7最新月版作品为示例,也适用于其它GHO镜像重装。操作步骤1、首先制作一个U盘PE启动盘,本教程以纯净好用的微PE为示例,PE及工具不唯一,大家可根据自己需要选择纯净无捆绑的…

    2022年7月24日
    11
  • java的四种输入方法,你会几种?

    java的四种输入方法,你会几种?java的输入方法最常见的就是Scanner的方法,我经过查阅一些资料发现了输入方法原来还有那么多种,可以玩出不少花样,下面是我总结出的四种输入方式,有需要的可以拿去1.Scanner相关的功能Scanner的输入方法是最常见的一种,也是小编在此最推荐的一种,固定格式如下:importjava.util.Scanner;publicclassTestDemo1007_4{publicstaticvoidmain(String[]args){Scanner

    2022年7月9日
    107

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号