Java PreparedStatement和Statement

Java中的Statement和PreparedStatement都是用于执行SQL语句。Statement适用于简单不带参数的SQL,每次执行都需要编译,可能存在SQL注入风险。PreparedStatement是预编译的,适合多次执行相同SQL,提供更高的效率和安全性,能防止SQL注入。CallableStatement是PreparedStatement的扩展,用于调用存储过程。在处理用户输入时,PreparedStatement会转义特殊字符,避免SQL注入。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Statement

  • 什么是Statement?
    Statement是java执行数据库操作的一个重要方法,用于在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句。
    具体步骤:①首先导入java.sql.*;这个包。②然后加载驱动,创建连接,得到Connection接口的的实现对象,比如对象名叫做conn。③然后再用conn对象去创建Statement的实例,方法是:Statement stmt = conn.creatStatement(“SQL语句字符串”);

Statement 对象用于将 SQL 语句发送到数据库中。实际上有三种 Statement 对象,它们都作为在给定连接上执行 SQL语句的包容器:Statement、PreparedStatement(它从 Statement 继承而来)和CallableStatement(它从 PreparedStatement 继承而来)。它们都专用于发送特定类型的 SQL 语句:Statement 对象用于执行不带参数的简单 SQL 语句;PreparedStatement 对象用于执行带或不带参数的预编译 SQL 语句;CallableStatement 对象用于执行对数据库已存储过程的调用。

综上所述,总结如下:Statement每次执行sql语句,数据库都要执行sql语句的编译,最好用于仅执行一次查询并返回结果的情形,效率高于PreparedStatement.但存在sql注入风险。PreparedStatement是预编译执行的。在执行可变参数的一条SQL时,PreparedStatement要比Statement的效率高,因为DBMS预编译一条SQL当然会比多次编译一条SQL的效率高。安全性更好,有效防止SQL注入的问题。对于多次重复执行的语句,使用PreparedStatement效率会更高一点。执行SQL语句是可以带参数的,并支持批量执行SQL。由于采用了Cache机制,则预编译的语句,就会放在Cache中,下次执行相同的SQL语句时,则可以直接从Cache中取出来。
那么CallableStatement扩展了PreparedStatement的接口,用来调用存储过程,它提供了对于输入和输出参数的支持,CallableStatement 接口还有对 PreparedStatement 接口提供的输入参数的sql查询的支持。
PreparedStatement: 数据库会对sql语句进行预编译,下次执行相同的sql语句时,数据库端不会再进行预编译了,而直接用数据库的缓冲区,提高数据访问的效率(但尽量采用使用?号的方式传递参数),如果sql语句只执行一次,以后不再复用。 从安全性上来看,PreparedStatement是通过?来传递参数的,避免了拼sql而出现sql注入的问题,所以安全性较好。

PreparedStatement
PreperedStatement 是 Statement 的孩子,它的实例对象可以通过调用Connection.preparedStatement()方法获得,相对于 Statement 对象而言:PreperedStatement 可以避免 SQL 注入的问题。Statement 会使数据库频繁编译 SQL,可能造成数据库缓冲区溢出。PreparedStatement 可对 SQL 进行预编译,从而提高数据库的执行效率。并且PreperedStatement 对于 sql 中的参数,允许使用占位符的形式进行替换,简化sql 语句的编写。

SQL注入,怎么防止SQL注入
所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。

怎么防止SQL注入,使用存储过程来执行所有的查询;检查用户输入的合法性;将用户的登录名、密码等数据加密保存。

package com.gem.demo.day0824;

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

import com.gem.demo.util.JDBCUtil;

public class Test {
	public static void main(String[] args) {
		Connection connection = null;

		//Statement statement = null;
		PreparedStatement psmt = null;

		ResultSet rs = null;
		//Scanner input = new Scanner(System.in);
		try {
			connection = JDBCUtil.getConnection();
			//System.out.println("输入姓名:");
			//张三 ';delete from preparedstatement_demo where id = 0002
			//String nameString = input.next();
			String sqlString = "select * from preparedstatement_demo where name = ?;";
			//statement = connection.createStatement();
			psmt = connection.prepareStatement(sqlString);
			//模拟sql注入 非法输入
			//(用户输入非法的值)使用Statement对象,无法防止sql注入(DROP操作很危险)
			psmt.setString(1, "张三' 8' = '8'");
			System.out.println(psmt.toString());
			rs = psmt.executeQuery();
			//statement.executeQuery(sqlString);
			//System.out.println(rs);
			while (rs.next()) {
				int id = rs.getInt(1);
				String name = rs.getString(2);
				String password = rs.getString(3);
				System.out.println(id + "\t" + name + "\t" + password);
			}
			//rs = psmt.executeQuery();
		} catch (SQLException e) {
			e.printStackTrace();
		}

	}
}

最终打印出来的是:"com.mysql.cj.jdbc.ClientPreparedStatement: select * from preparedstatement_demo where name = '张三\' 8\' = \'8\';’"由此可见,prepareStatement对象防止sql注入的方式是把用户非法输入的单引号用\反斜杠做了转义,从而达到了防止sql注入的目的。
具体mysql数据库产商,在实现PreparedStatement接口的实现类中的setString(int parameterIndex, String x)函数中做了一些处理,把单引号做了转义(只要用户输入的字符串中有单引号,那mysql数据库产商的setString()这个函数,就会把单引号做转义)
大家有兴趣可以去网上,下载一份mysql数据库的驱动程序的源代码,看看mysql数据库产商的驱动程序的源代码,去源代码中找到setString(int parameterIndex, String x)函数,看看该函数中是怎么写的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值