java中连接Mysql以及PreparedStatement如何防止sql注入

news2024/10/24 19:26:09

目录

JDBC

使用JDBC连接到MySQL

使用 Statement

使用 PreparedStatement

Statement 和 PreparedStatement 区别


在 java 中如何连接到 MySQL 数据库,执行 SQL 查询,并处理查询结果?

JDBC

java 程序连接到 mysql,首先需要下载 JDBC 驱动程序。JDBC是一个允许 Java 程序连接到数据库并与之交互的库。

JDBC 驱动程序通常是一个 JAR 文件:MySQL :: Download Connector/J

下载后将该 jar 文件放在项目任意文件夹中,在 idea 中选中该 JAR 文件右键,选择添加到库即可。这样,当Java程序尝试加载JDBC驱动程序时,JVM(Java虚拟机)能够在类路径中找到并加载它。

使用JDBC连接到MySQL

在使用 Java 的 JDBC 连接到 MySQL 数据库时,有两种主要的方法来执行 SQL 语句:Statement 和 PreparedStatement。这两种方法各有优缺点,适用于不同的场景。

使用 Statement

在 Java 的数据库编程中,Statement 对象是一个非常重要的接口。

  • 定义Statement 是用于执行静态 SQL 语句并返回它所生成结果的接口。
  • 特点
    • 每次执行 SQL 语句时,数据库都需要重新解析和编译 SQL 语句,这会影响性能。
    • 容易受到 SQL 注入攻击,因为 SQL 语句和参数是动态拼接的。
    • 适用于执行一次性的、不带参数的 SQL 语句。

如下以拼接的方式执行sql语句,易受到sql注入的攻击

package demo;

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

public class MySQLConnectionExample {

    // 数据库连接信息
    private static final String DB_URL = "jdbc:mysql://localhost:3306/security";
    private static final String USER = "root";
    private static final String PASS = "root";

    public static void main(String[] args) {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try {
            // 打开连接
            System.out.println("Connecting to database...");
            connection = DriverManager.getConnection(DB_URL, USER, PASS); //连接到数据库,如果连接成功,connection 变量将引用一个有效的数据库连接。

            // 如果连接成功,打印一条消息
            if (connection != null) {
                System.out.println("Successfully connected to the database!");

                // 通过调用 connection.createStatement() 方法创建一个 Statement 对象,用于执行 SQL 查询。
                statement = connection.createStatement();
                //以拼接的方式执行sql语句,易受到sql注入的攻击
                String n = "2";
                // 执行 SQL 查询
                String sql = "SELECT * FROM security.users WHERE id=" + n + " LIMIT 0,1";
                resultSet = statement.executeQuery(sql);

                // 处理查询结果
                while (resultSet.next()) {
                    System.out.println("sql查询成功:" + sql);
                    String id = resultSet.getString("id");
                    String username = resultSet.getString("username");
                    String password = resultSet.getString("password");
                    // 打印结果或进行其他处理
                    System.out.println("id: " + id);
                    System.out.println("Username: " + username);
                    System.out.println("password: " + password);
                    // 可以根据需要添加更多列的处理
                }
            }

        } catch (SQLException e) {
            // 处理 JDBC 错误
            e.printStackTrace();
        } finally {
            // 关闭 ResultSet
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            // 关闭 Statement
            try {
                if (statement != null) {
                    statement.close();
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            // 关闭 Connection
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
    }
}

使用 PreparedStatement

  • 定义PreparedStatementStatement 的子接口,用于执行带参数的预编译 SQL 语句。
  • 特点
    • 预编译 SQL 语句,提高性能。编译后的 SQL 语句可以多次执行而不需要重新解析。
    • 防止 SQL 注入攻击,因为参数是通过占位符(通常是问号 ?)进行绑定的,数据和查询逻辑是分开的。
    • 适用于需要多次执行相同 SQL 语句但使用不同参数的情况。

执行后 sql 语句显示如下,貌似能被注入

SELECT * FROM security.users WHERE id='1' and 1=2 --+' LIMIT 1

但其实 PreparedStatement 会将参数值作为单独的参数传递给数据库,而不是直接拼接到 SQL 语句中。所以 1' and 1=2 --+ 只是作为一个参数值赋值给 id。实际执行的是如下 sql 语句

SELECT * FROM security.users WHERE id='1\' and 1=2 --+' LIMIT 1

而这条语句实际执行效果等于如下语句。因为 mysql 会尝试将 1\' and 1=2 --+ 转换为整数 1,具体可以看MySQL 的隐式类型转换,从而防止了 sql 注入。

SELECT * FROM security.users WHERE id='1' LIMIT 1

package demo;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class MySQLConnectionExample {

    // 数据库连接信息
    private static final String DB_URL = "jdbc:mysql://localhost:3306/security";
    private static final String USER = "root";
    private static final String PASS = "root";

    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        try {
            // 打开连接
            System.out.println("Connecting to database...");
            connection = DriverManager.getConnection(DB_URL, USER, PASS);

            // 如果连接成功,打印一条消息
            if (connection != null) {
                System.out.println("Successfully connected to the database!");

                // 准备 SQL 语句,使用占位符 ?
                String sql = "SELECT * FROM security.users WHERE id=? LIMIT 1";
                preparedStatement = connection.prepareStatement(sql);

                // 设置占位符的值, 其中 1 是占位符的位置(从 1 开始计数),userId 是要设置的值。
                String userId = "1' and 1=2 --+"; // 假设要查询的用户 ID 为 1
                preparedStatement.setString(1, userId);

                // 执行 SQL 查询
                resultSet = preparedStatement.executeQuery();

                // 处理查询结果
                while (resultSet.next()) {
                    System.out.println("SQL 查询成功");
                    String id = resultSet.getString("id");
                    String username = resultSet.getString("username");
                    String password = resultSet.getString("password");
                    // 打印结果或进行其他处理
                    System.out.println("id: " + id);
                    System.out.println("Username: " + username);
                    System.out.println("password: " + password);
                    // 可以根据需要添加更多列的处理
                }
            }

        } catch (SQLException e) {
            // 处理 JDBC 错误
            e.printStackTrace();
        } finally
        {
            // 关闭 ResultSet
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            // 关闭 PreparedStatement
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            // 关闭 Connection
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
    }
}

Statement 和 PreparedStatement 区别

  • 性能PreparedStatement 通常比 Statement 性能更高,因为它允许数据库预编译 SQL 语句。
  • 安全性PreparedStatement 能够防止 SQL 注入攻击,而 Statement 则容易受到这种攻击。
  • 适用场景Statement 适用于执行一次性的、不带参数的 SQL 语句;而 PreparedStatement 则适用于需要多次执行相同 SQL 语句但使用不同参数的情况。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2211064.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Dev-C++萌新福利2

朝鲜球作品原创 1 符号认识: 1.1简单例题1 1.2简单例题22奇奇怪怪的符号 2.1简单例题3 2.2符号表 2.2.1符号表中特殊符号 2.3符号使用代码样例(部分) 萌新福利 作品成本6999元&#xff0…

OSError: [Errno 22] Invalid argument:无效的参数完美解决方法

🚨 OSError: [Errno 22] Invalid argument:无效的参数完美解决方法 💡 🚨 OSError: [Errno 22] Invalid argument:无效的参数完美解决方法 💡摘要引言正文1. 什么是 OSError: [Errno 22] Invalid argument&…

牛客.数字游戏​编辑牛客.体操队形(暴力搜索)​​​​​​​牛客.二叉树最大路径和​编辑牛客.排序子序列

目录 牛客.数字游戏​编辑 牛客.体操队形(暴力搜索) 牛客.二叉树最大路径和​编辑 牛客.排序子序列 牛客.数字游戏 难度不大,但是要注意,他这个快速输入与输出 import java.util.*; import java.io.*; import java.util.StringTokenizer; // 注意类名…

架构设计笔记-15-面向服务架构设计理论与实践

目录 知识要点 案例分析 1.微服务架构 2.微服务 3.微服务架构 4.SOA与微服务 5.基于微服务架构的系统/传统单体式系统 论文 1.论微服务架构及其应用 知识要点 服务组件体系结构(Service Component Architecture,SCA)是面向服务体系…

IT基础监控运维:监控易的深度解析与应用

在数字化转型加速的今天,IT系统的稳定性和高效运维成为了企业业务连续性的关键保障。IT基础监控作为运维工作的基石,其重要性不言而喻。本文将以监控易产品为核心,深入探讨IT基础监控的功能、特点及范围,为运维团队提供实用的参考…

销售管理之线索管理

一、线索获取:销售增长与市场洞察的双引擎 销售增长的基石 线索:销售旅程的起点:在销售的宏伟蓝图中,高质量的线索无疑是构筑成功的基石。缺乏持续、优质的线索供应,任何销售团队都难以跨越销售目标的重重山峦。以软…

Apktool:解包重打包工具

ApKtool是一个apk编译工具,能够反编译apk文件。 解包 使用命令apktool d test.apk 会在同目录下生成一个同名的文件夹 重打包 使用命令apktool b test 会在test文件夹里生成一个dist目录,在dist目录里有打包好的test.apk

Top6 最好的 Android 数据恢复软件免费获取

虽然在智能手机上随身携带您最喜爱的音乐收藏或珍贵的录音很方便,但如果您的设备出现技术问题或您不小心删除了文件,文件也有可能丢失。 不管文件是如何删除或丢失的,丢失那些珍贵的音频文件的痛苦对每个人来说都是一样的。这就是我们创建本…

鸿蒙开发之ArkUI 界面篇 三十三 Builder(封装容器)

鸿蒙开发中遇到容器相同、容器下面的子组件相同,就是子组件的文字不同,背景颜色不同,文字颜色不同之类,就可以使用Builder来封装,语法格式如下: 例如下面的界面: Row4个ColumImageText来实现&am…

Java初阶测试编程题目

文章目录 1.大小写转换2.斐波那契数列2.1递归解决(不推荐)2.2递推公式(非递归) 3.删除公共字符3.1题目说明3.2第一种方法3.3第二种方法 4.字符串的加法4.1题目说明4.2题目核心方法4.3题目代码解析 Java初阶测试编程题目分析与总结…

C++第六讲:STL--vector的使用及模拟实现

C第六讲&#xff1a;STL--vector的使用及模拟实现 1.vector简介2.vector的常见接口介绍2.1constructor -- 构造2.2destructor -- 析构2.3begin、end2.3.1vector和string的区别、vector<string> 2.4rbegin、rend2.5cbegin、cend2.6crbegin、crend2.7size、max_size、resiz…

C++AVL树的介绍和实现

目录 1.AVL树的概念 2.AVL树的实现 2.1AVL树的结构 2.2AVL树的插入 2.2.1AVL树插入一个值的大概过程 2.2.2平衡因子的更新 2.2.3插入节点及更新平衡因子的代码实现(暂未实现旋转逻辑) 2.3旋转 2.3.1旋转的原则 2.3.2右单旋(处理parent->_bf -2 && cur-&g…

简易入门:使用Docke 部署一个tomcat服务

简易入门&#xff1a;使用Docke 部署一个tomcat服务 # 拉取 >docker pull tomcat:9.0# 后台运行容器&#xff0c;端口映射为8080. -p 宿主机端口:容器端口 >docker run -d --name tomcat-c-01 -p 8080:8080 tomcat:9.0# 查看容器id >docker ps CONTAINER ID IMAG…

Qt-系统线程安全(63)

目录 描述 使用 线程不安全 线程安全 释放锁问题 其他的锁 条件变量和信号量 描述 多线程程序太复杂了 在C/C 和 Linux中&#xff0c;我们为了保证线程安全&#xff0c;简单的方式就是加锁 为此 Qt 也封装了自己的一套锁管理 使用 线程不安全 我们先测验一下线程不安…

七、程序流程控制

一、三种执行顺序 执行顺序说明顺序结构自上而下的执行代码分支结构根据条件&#xff0c;选择对应代码执行循环结构控制某段代码重复执行 二、分支结构 1、if 分支 根据条件&#xff08;真或假&#xff09;来决定执行某段代码if 分支有三种形式 //第一种形式 if(条件表达式…

Qt学习(一)——win10系统下Qt安装(Qt5.15.2+QtCreator5.0.3+MSVC2019)

win10平台下&#xff0c;Qt Creator 5.0.3 软件About Qt Creator界面如下&#xff1a; 其基于Qt 5.15.2 MSVC2019&#xff0c;64bit,故在用Qt4 设计师自定义控件所设计的控件能够被Qt Creator加载到&#xff0c;就要安装相应版本的Qt和MSVC。此安装便可支持win10系统下的自定义…

Java项目实战II基于Java+Spring Boot+MySQL的足球青训俱乐部管理后台系统的设计与开发(源码+数据库+文档)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 足球作为世…

【hot100-java】排序链表

链表题。 使用归并排序法。 一图解决。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListNode next) { this.val val; thi…

(刷题记录6)三数之和

三数之和 题目信息&#xff1a;题目思路(环境来自力扣OJ的C)&#xff1a;暴力枚举&#xff1a;双指针&#xff1a;在三数之和上&#xff1a;转化成的两数之和&#xff1a;两数之和小优化&#xff1a; 复杂度&#xff1a;代码和解释&#xff1a;暴力枚举&#xff1a;双指针&…

【C语言】深入理解指针(三)(上)

本篇博客将讲解以下知识&#xff1a; 1、字符指针变量 2、数组指针变量 1、字符指针变量 在指针的类型中&#xff0c;有一种指针类型为字符指针&#xff1a;char* 一般使用&#xff1a; 注意&#xff1a;%s打印字符串的时候&#xff0c;需要提供字符串首元素的起始地址。 易错…