JDBC_04Statement和PreparedStatement

1.对比Statement和PreparedStatement

1.Statement存在sql注入问题,PreparedStatement解决了sql注入问题。

2.PreparedStatement效率比Statement高一些

在mysql中,执行一条语句需要编译运行。

而如果执行过一条语句后,下一条语句跟前一条语句一模一样,就不会编译,直接运行。

使用Statement时,每次执行都要重新拼接sql语句,每次都需要重新编译运行:

//使用Statement
String sql = "select * from t_user where loginName = '"+ userInfo.get("loginName") +"' and loginPwd = '"+ userInfo.get("loginPwd") +"'";
rs = stmt.executeQuery(sql);

而使用PreparedStatement时,sql语句是固定的,在编译一次后,以后都不需要再次编译,直接运行:

//使用PreparedStatement
String sql = "select * from t_user where loginName = ? and loginPwd = ?";
ps = conn.prepareStatement(sql);

Statement是编译一次执行一次。PreparedStatement是编译一次执行,执行多次。

故PreparedStatement执行效率比Statement高。

3.PreparedStatement会在编译阶段做类型的安全检查

如果使用Statement,在给sql语句传值时,是将值直接拼接在sql语句字符串里的。

如果我需要传一个double类型的密码,那么我实际上传入一个String类型的密码也不会报错。

//使用Statement
String sql = "select * from t_user where loginName = '"+ userInfo.get("loginName") +"' and loginPwd = '"+ userInfo.get("loginPwd") +"'";

如果使用Statement,在给sql语句传值时,是通过setString或setDouble...方法将值传入占位符里的。

如果我需要传一个double类型的密码,那么我就需要调用setDouble方法来传值。

假如我传入一个String类型的密码,那么setDouble方法就会报错。

//PreparedStatement传值
ps.setString(1,loginName);
ps.setString(2,loginPwd);

综上,PreparedStatement使用较多,只有极少数情况下需要使用Statement。

2.必须使用Statement的情况

Statement支持SQL注入,在业务方面要求必须支持SQL注入的时候,必须使用Statement。

  • 凡是业务方面要求是传值的,就使用PreparedStatement。
  • 凡是业务方面要求是需要进行sql语句拼接的,必须使用Statement。

就比如在执行排序操作时,就必须使用sql语句拼接。

因为在执行排序操作时,必须要指定是asc还是desc,并且asc和desc不能被单引号括住。

而如果使用PreparedStatement,就需要使用占位符,然后将asc或者desc放进字符串里,通过setString方法传值进去。

占位符会将传进来的字符串自动转义,给字符串加上单引号,这在sql语句中是不合法的。

//PreparedStatement
private static void orderBy(String orderType) {
    //3.获取预编译的数据库操作对象
	String sql = "select sal from emp order by sal ?";
	PreparedStatement ps = conn.prepareStatement(sql);
	ps.setString(1,orderType);
    //select sal from emp order by sal 'desc'
    //4.执行SQL语句
    rs = ps.executeQuery();
}

所以必须使用sql语句拼接,必须使用Statement。

//Statement
private static void orderBy(String orderType) {
    //3.获取数据库操作对象
    Statement stmt = conn.createStatement();
    //4.执行sql语句
    String sql = "select sal from emp order by sal "+ orderType;
    //select sal from emp order by sal desc
    rs = stmt.executeQuery(sql);
}

完整排序代码:

package com.tsccg.jdbc.statement;

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

/**
 * @Author: TSCCG
 * @Date: 2021/07/28 16:39
 */
public class OrderStatementDemo01 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("排序方式:");
        String orderType = sc.nextLine();
        orderBy(orderType);
    }
    /**
     * 将数据库中的数据排序显示出来
     */
    private static void orderBy(String orderType) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取连接
            String url = "jdbc:mysql://127.0.0.1:3306/tsccg";
            String user = "root";
            String password = "123456";
            conn = DriverManager.getConnection(url,user,password);
            //3.获取数据库操作对象
            stmt = conn.createStatement();
            //4.执行sql语句
            String sql = "select sal from emp order by sal "+ orderType ;
            rs = stmt.executeQuery(sql);
            //5.处理查询结果集
            while (rs.next()) {
                System.out.println(rs.getString("sal"));
            }
        } catch (SQLException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            //6.释放资源
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }

    }
}

运行:

排序方式:asc
0.00
0.00
0.00
800.00
950.00
1100.00
1250.00
1250.00
1500.00
1600.00
2850.00
2975.00
3000.00
3000.00
排序方式:desc
3000.00
3000.00
2975.00
2850.00
1600.00
1500.00
1250.00
1250.00
1100.00
950.00
800.00
0.00
0.00
0.00

3.PreparedStatement实现增删改

3.1增:向t_user表插入数据

package com.tsccg.jdbc.statement;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;

/**
 * @Author: TSCCG
 * @Date: 2021/07/28 17:25
 * 使用PreparedStatement实现增删改
 */
public class PreparedStatementDemo01 {
    public static void main(String[] args) {
        boolean result = change();
        System.out.println(result ? "操作成功" : "操作失败");
    }

    /**
     * 增删改t_user表中的数据
     * @return 返回执行结果
     */
    private static boolean change() {
        boolean isSuccess = false;
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取连接
            String url = "jdbc:mysql://localhost:3306/tsccg";
            String user = "root";
            String password = "123456";
            conn = DriverManager.getConnection(url,user,password);
            //3.获取预编译数据库操作对象
            String sql = "insert into t_user(loginName,loginPwd,realName) values(?,?,?)";
            ps = conn.prepareStatement(sql);
            ps.setString(1,"zhaoliu");
            ps.setString(2,"123456");
            ps.setString(3,"赵六");
            //4.执行sql语句
            int count = ps.executeUpdate();
            if (count > 0) {
                isSuccess = true;
            }

        } catch (SQLException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            //6.释放资源
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
        return isSuccess;
    }
}

运行:

操作成功

JDBC_04Statement和PreparedStatement_sql

3.2改:修改t_user里的数据

将上面程序中第3步的语句修改为:

//3.获取预编译数据库操作对象
String sql = "update t_user set loginName = ?,realName = ? where id = ?";
ps = conn.prepareStatement(sql);
ps.setString(1,"wangwu");
ps.setString(2,"王五");
ps.setInt(3,3);

重新运行程序:

操作成功

JDBC_04Statement和PreparedStatement_sql_02

3.3删:删除t_user中的数据

将上面程序中第3步的语句修改为:

//3.获取预编译数据库操作对象
String sql = "delete from t_user where id = ?";
ps = conn.prepareStatement(sql);
ps.setInt(1,3);

重新运行程序:

操作成功

JDBC_04Statement和PreparedStatement_sql语句_03