JDBC中PreparedStatement相较于Statement的优点

本文详细阐述了PreparedStatement相较于Statement的优势,包括提高代码可读性与维护性、预编译机制提升性能及有效防止SQL注入攻击。

之前执行sql语句都是用Statement去执行的,但是学习了PreparedStatement之后发现PreparedStatement更好用,下面就来说一下PreparedStatement的优点。

优点1:
Statement需要进行字符串拼接,可读性和维护性比较差

String sql = “insert into hero values(null,”+"‘提莫’"+","+313.0f+","+50+")";

代码如下:

package jdbc;

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

public class work4 {

	public static void main(String[] args) {
		Connection c = null;
		Statement s = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root" ,"admin");
			String sql = "insert into hero values(null," + "'提莫'" + "," + 313.0f + "," + 50 + ")";//插入信息
			s = c.createStatement();
			s.execute(sql);
			//先释放Statement对象
			s.close();
			//再释放Connection对象
			c.close();
		}catch(ClassNotFoundException e) {
			e.printStackTrace();
		}catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

PreparedStatement 使用参数设置,可读性好,不易犯错

String sql = “insert into hero values(null,?,?,?)”;

代码如下:

package jdbc4;
import java.sql.*;
public class testJDBC {

	public static void main(String[] args) {
		Connection c = null;
		PreparedStatement ps = null;
		ResultSet r = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root","admin");
			String sql = "insert into hero values (null,?,?,?)";
			ps = c.prepareStatement(sql);
			ps.setString(1,"aa");
			ps.setFloat(2, (float) 35.4);
			ps.setInt(3,55);
			ps.execute();
		}catch(ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			if(r != null) {
				try {
					r.close();
				}catch(Exception e) {
					e.printStackTrace();
				}
				r = null;
			}
			
			if(ps != null) {
				try {
					ps.close();
				}catch(Exception e) {
					e.printStackTrace();
				}
				ps = null;
			}
			
			if(c != null) {
				try {
					c.close();
				}catch(Exception e) {
					e.printStackTrace();
				}
				c = null;
			}
		}
	}

}

总结:
使用Statement进行字符串拼接时显得非常的繁琐,会有很多的双引号和单引号的配对,如果缺少一个,程序就会出错。而且查错十分艰难。(之前就被这种字符串拼接搞崩溃了…)
这时PreparedStatement就显得很清晰了,把要插入的元素先用?代替,之后在不同的位置一个一个使用set语句就可以了,十分方便清晰。

优点2:
PreparedStatement有预编译机制,性能比Statement更快
代码如下:

package jdbc;
  
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
  
public class TestJDBC {
    public static void main(String[] args) {
  
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
  
        String sql = "insert into hero values(null,?,?,?)";
        try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");
                Statement s = c.createStatement();
                PreparedStatement ps = c.prepareStatement(sql);
            ) {
            // Statement执行10次,需要10次把SQL语句传输到数据库端
            // 数据库要对每一次来的SQL语句进行编译处理
            for (int i = 0; i < 10; i++) {
                String sql0 = "insert into hero values(null," + "'提莫'" + ","
                        + 313.0f + "," + 50 + ")";
                s.execute(sql0);
            }
            s.close();
  
            // PreparedStatement 执行10次,只需要1次把SQL语句传输到数据库端
            // 数据库对带?的SQL进行预编译
  
            // 每次执行,只需要传输参数到数据库端
            // 1. 网络传输量比Statement更小
            // 2. 数据库不需要再进行编译,响应更快
            for (int i = 0; i < 10; i++) {
                ps.setString(1, "提莫");
                ps.setFloat(2, 313.0f);
                ps.setInt(3, 50);
                ps.execute();
            }
 
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
  
    }
}

总结:
如果需要插入10万条语句到数据库,使用Statement执行sql语句需要一条一条被数据库编译,这肯定会引起卡顿。但是PreparedStatement就不一样了,数据库只要对其刚开始的那条sql语句进行预编译,之后直接插入就可以了。总的来说PreparedStatement更加快。

优点3:
PreparedStatement可以防止SQL注入式攻击

代码如下:

package jdbc;
  
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
  
public class TestJDBC {
    public static void main(String[] args) {
  
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
  
        String sql = "select * from hero where name = ?";
        try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root", "admin");
                Statement s = c.createStatement();
            PreparedStatement ps = c.prepareStatement(sql);
        ) {
            // 假设name是用户提交来的数据
            String name = "'盖伦' OR 1=1";
            String sql0 = "select * from hero where name = " + name;
            // 拼接出来的SQL语句就是
            // select * from hero where name = '盖伦' OR 1=1
            // 因为有OR 1=1,所以恒成立
            // 那么就会把所有的英雄都查出来,而不只是盖伦
            // 如果Hero表里的数据是海量的,比如几百万条,把这个表里的数据全部查出来
            // 会让数据库负载变高,CPU100%,内存消耗光,响应变得极其缓慢
            System.out.println(sql0);
  
            ResultSet rs0 = s.executeQuery(sql0);
            while (rs0.next()) {
                String heroName = rs0.getString("name");
                System.out.println(heroName);
            }
  
            s.execute(sql0);
  
            // 使用预编译Statement就可以杜绝SQL注入
  
            ps.setString(1, name);
  
            ResultSet rs = ps.executeQuery();
            // 查不出数据出来
            while (rs.next()) {
                String heroName = rs.getString("name");
                System.out.println(heroName);
            }
 
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
  
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值