jdbc中Statement接口实现CRUD操作(了解)

package loey.java1;

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

/**

  • 实现功能:

  • 1、需求

  •  模拟用户登录功能的实现
    
  • 2、业务描述

  •  程序运行的时候,提供一个输入的入口,可以让用户输入用户名和密码
    
  •  用户输入用户名和密码之后,提交信息,java程序收集用户信息
    
  •  java程序连接数据库验证用户名和密码是否效
    
  •  合法:显示登录成功
    
  •  不合法:显示登录失败
    
  • 3、数据的准备

  •  在实际开发中,表的设计会使用专业的建模工具,我们这里安装一个建模工具:powerDesigner
    
  • 4.当前程序存在问题:

  •  请输入登录名:aaa
    
  •  请输入登录密码:aaa' or '1' = '1
    
  •  登录成功
    
  •  这种现象被称为SQL注入(安全隐患,黑客经常使用
    
  • 5.导致SQL注入的根本原因是什么?

  • 用户输入的信息中含SQL语句的关键字,并且这些关键字参与了SQL语句的编译过程,

  • 导致SQL语句的愿意被扭曲,进而达到SQL注入。

  • @author 刘犁青 邮箱:loey724@163.com

  • @version v1.0

  • @create 2020-09-01 10:34
    */
    public class JDBCTest06 {

    public static void main(String[] args) {
    Map<String, String> userLoginInfo = initUI();
    boolean loginSuccess = loginSuccess(userLoginInfo);
    System.out.println(loginSuccess ? “登录成功” : “登录失败”);

    }

    private static boolean loginSuccess(Map<String,String> userLoginInfo){

     boolean isSuccess = false;
     Connection conn = null;
     Statement stmt = null;
     ResultSet rs = null;
    
     try {
         //1.注册驱动
         Class.forName("com.mysql.jdbc.Driver");
    
         //2.获取连接
         conn = DriverManager.getConnection("jdbc:mysql://localhost:3306" +
                 "/bjpowernode","root","1127");
    
         //3.获取操作数据库的对象
         stmt = conn.createStatement();
    
         //4.执行sql语句
         String sql = "Select * from t_user where loginName = '" + userLoginInfo.get("loginName")
                 +"' and loginPwd = '" + userLoginInfo.get("loginPwd") + "'";
         //以上正好完成了SQL语句拼接,以下代码的含义是:发送SQL语句给DBMS,DBMS进行编译SQL语句,正好
         // 将用户输入的“非法信息”编译进去,导致了原SQL语句的含义被扭曲了。
         rs = stmt.executeQuery(sql);
         while(rs.next()){
             isSuccess = true;
         }
    
     } catch (ClassNotFoundException e) {
         e.printStackTrace();
     } catch (SQLException e) {
         e.printStackTrace();
     } finally {
         if(rs != null){
             try {
                rs.close();
             } catch (SQLException e) {
                 e.printStackTrace();
             }
         }
         if(stmt != null){
             try {
                 stmt.close();
             } catch (SQLException e) {
                 e.printStackTrace();
             }
         }
         if(conn != null){
             try {
                 conn.close();
             } catch (SQLException e) {
                 e.printStackTrace();
             }
         }
     }
     return isSuccess;
    

    }

    /**

    • 用户登录界面

    • @return 返回用户输入的登录名和登录密码
      */
      private static Map<String,String> initUI(){

      HashMap<String, String> userLoginInfo = new HashMap<>();

      Scanner scan = new Scanner(System.in);
      System.out.print(“请输入登录名:”);
      String loginName = scan.nextLine();
      System.out.print(“请输入登录密码:”);
      String loginPwd = scan.nextLine();

      userLoginInfo.put(“loginName”,loginName);
      userLoginInfo.put(“loginPwd”,loginPwd);

      return userLoginInfo;
      }
      }

解决:
package loey.java1;

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

/**

  • 1.解决SQL注入问题
  • 只要用户提供的信息不参与SQL语句的编译,问题就解决了,
  • 即使用户提供的信息含SQL语句的关键字,但是没参与编译,不起作用
  • 要想用户的信息不参与SQL语句的编译,那么必须使用java.sql.PreparedStatement
  • java.sql.PreparedStatement接口继承了java.sql.Statement
  • PreparedAtatement的原理是:预先对SQL语句的框架进行编译,然后再给SQL语句传“值”。
  • 请输入登录名:aaa
  • 请输入登录密码:aaa’ or ‘1’ = '1
  • 登录失败
  • PreparedStatement和Statement对比?
  • —Statement存在SQL注入问题,PreparedStatement解决了SQL注入问题
  • —Statement是编译一次执行一次,PreparedStatement是编译一次,可执行N次,PreparedStatement效率较高一些
  • —PreparedStatement会在编译阶段做类型的安全检查
  • 5、什么情况下必须使用Statement呢?
  • 业务方面要求必须支持SQL注入的时候
  • Statement支持SQL注入,凡是业务方面要求是需要进行SQL语句拼接的,必须使用Statement

public class JDBCTest07 {
public static void main(String[] args) {
Map<String, String> userLoginInfo = initUI();
boolean loginSuccess = loginSuccess(userLoginInfo);
System.out.println(loginSuccess ? “登录成功” : “登录失败”);

}

/**
 * 判断用户登录是否成功
 *
 * @param userLoginInfo 用户输入的登录名和登录密码
 * @return true:登录成功 false:登录失败
 */
private static boolean loginSuccess(Map<String, String> userLoginInfo) {

    boolean isSuccess = false;
    Connection conn = null;
    PreparedStatement ps = null;//这里使用预编译的数据库操作对象
    ResultSet rs = null;

    try {
        //1.注册驱动
        Class.forName("com.mysql.jdbc.Driver");

        //2.获取连接
        conn = DriverManager.getConnection("jdbc:mysql://localhost:3306" +
                "/bjpowernode", "root", "1127");

        //3.获取预编译的数据库操作对象
        // sql语句的框架中,一个?,表示一个占位符,一个?将来接收一个"值"。注意:占位符不要用单引号括起来
        String sql = "select * from t_user where loginName = ? and loginPwd = ?";
        // 程序执行到此处,会发送sql语句框架给DBMS,DBMS对sql语句框架进行预编译。
        ps = conn.prepareStatement(sql);

        // 给占位符?传值,第一个?的下标是1,第二个?的下标是2(JDBC中下标都从1开始)
        ps.setString(1,userLoginInfo.get("loginName"));
        ps.setString(2,userLoginInfo.get("loginPwd"));


        rs = ps.executeQuery();
        while (rs.next()) {
            isSuccess = true;
        }

    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    return isSuccess;
}

/**
 * 用户登录界面
 *
 * @return 返回用户输入的登录名和登录密码
 */
private static Map<String, String> initUI() {

    HashMap<String, String> userLoginInfo = new HashMap<>();

    Scanner scan = new Scanner(System.in);
    System.out.print("请输入登录名:");
    String loginName = scan.nextLine();
    System.out.print("请输入登录密码:");
    String loginPwd = scan.nextLine();

    userLoginInfo.put("loginName", loginName);
    userLoginInfo.put("loginPwd", loginPwd);

    return userLoginInfo;
}

}

  • 5、什么情况下必须使用Statement呢?
  • 业务方面要求必须支持SQL注入的时候
  • Statement支持SQL注入,凡是业务方面要求是需要进行SQL语句拼接的,必须使用Statement
    //用户输入desc表示降序,输入asc表示升序
上一篇:亚马逊aws emr hadoop集群 调度工具azkaban安装


下一篇:原创 | CRUD更要知道的Spring事务传播机制