zoukankan      html  css  js  c++  java
  • Statement和preparedStatement之间的区别?

    根据JDBC模拟用户功能的实现:
    loginUser.properties
    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://127.0.0.1:3306/mydatabase
    user=root
    password=333
    package com.java.JDBC;
    
    
    import java.sql.*;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.ResourceBundle;
    import java.util.Scanner;
    
    
    /*
    实现功能:
        1 需求:模拟用户登录功能的实现。
        2 业务描述:
            程序运行的时候,提供一个输入的入口,可以让用户输入用户名和密码。
            用户输入用户名和密码之后,提交信息,java程序收集用户信息
            Java程序连接数据库验证用户名和密码是否合法。
            合法:显示登陆成功。
            不合法:显示登陆失败。
        3 数据的准备
            在实际开发中,表的设计会使用专业的建模工具,我们这里安装一个建模工具:PowerDesigner
            使用PD工具来进行数据库表的设计。(参见user-login.sql脚本)
            
        4 当前程序存在的问题:
            用户名:fdsa
            密码:fdsa' or '1'='1
            登录成功
            这种现象被称为SQL注入(安全隐患)。(黑客经常使用)
            
        5 导致SQL注入的根本原因是什么?
            select * from t_user where loginName = 'fdsa' and loginpwd = 'fdsa' or '1'='1';
            用户输入的信息中含有sql语句的关键字,并且这些关键字参与sql语句的编译过程,导致sql语句的原意被扭曲,从而达到sql注入。
        
        
    */
    public class JDBCTest06 {
        public static void main(String[] args) {
            // 初始化一个界面
            Map<String,String> userLoginInfo = initUI();
            // 验证用户名和密码
            boolean loginSuccess = login(userLoginInfo);
            System.out.println(loginSuccess == true ? "登陆成功" : "登陆失败");
        }
        /**
         * 用户登录
         * @param userLoginInfo 用户登录信息
         * @return true表示成功  false表示失败
         */
        private static boolean login(Map<String, String> userLoginInfo) {
            // JDBC代码
            Connection conn = null;
            Statement stmt = null;
            ResultSet rs = null;
            boolean result = false;
            ResourceBundle rb = ResourceBundle.getBundle("loginUser");
            
            String driver = rb.getString("driver");
            String url = rb.getString("url");
            String user = rb.getString("user");
            String password = rb.getString("password");
        
            String loginName = userLoginInfo.get("loginName");
            String loginpwd = userLoginInfo.get("password");
            
            try {
                // 1 注册驱动
                // Class.forName("com.mysql.jdbc.Driver");
                Class.forName(driver);
                // 2 获取连接
                // conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase","root","333");
                conn = DriverManager.getConnection(url,user,password);
                // 3 获取数据库操作对象
                stmt = conn.createStatement();
                // 4 执行sql语句
                String sql = "select * from t_user where loginName = '" + loginName + "' and loginpwd = '" + loginpwd +"'";
                // 以上正好完成了sql语句的拼接,以下代码的含义是,发送sql语句给DBMS进行sql编译。
                // 正好将用户提供的“非法信息”编译进去。导致了原sql语句的含义被扭曲了。
                System.out.println(sql);
                rs = stmt.executeQuery(sql);
                // 5 处理返回结果集
                if (rs.next()){
                    result = true;
                }
                
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                // 6 释放资源
                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 result;
        }
        
        /**
         * 初始化用户界面
         * @return 用户输入的用户名和密码等登陆信息
         */
        private static Map<String, String> initUI() {
            Scanner scanner = new Scanner(System.in);
            System.out.print("用户名: ");
            String username = scanner.nextLine();
            
            System.out.print("密码: ");
            String password = scanner.nextLine();
            
            Map<String,String> userLoginInfo = new HashMap<>();
            userLoginInfo.put("loginName",username);
            userLoginInfo.put("password",password);
            return userLoginInfo;
        }
    }

    案例7:如何解决JDBC注入问题及Statement和PreparedStatement之间的区别?

    package com.java.JDBC;
    
    
    import java.sql.*;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.ResourceBundle;
    import java.util.Scanner;
    /*
    1 解决sql注入问题
        只要用户提供的信息不参与sql语句的编译过程,问题就解决了。
        即使用户提供的信息中心含有sql语句的关键字,但是没有参与编译,不起作用。
        要想用户信息不参与sql语句的编译,必须使用java.sql.PreparedStatement
        PreparedStatement接口继承了java.sql.Statement
        PreparedStatement是属于预编译的数据库操作系统
        PreparedStatement原理是:预先对sql语句的框架进行编译,然后再给sql语句传“值”
        
    2 解决sql注入的关键是什么?
        用户提供的信息中即使含有sql语句的关键字,但是这些关键字并没有参与编译,不起作用。
        
    3 对比一下Statement和PreparedStatement?
        - Statement存在sql注入问题,PreparedStatement解决了sql注入问题。
        - Statement是编译一次执行一次,PreparedStatement是编译一次,可执行n次。PreparedStatement效率较高一些。
        - PreparedStatement会在编译阶段做类型的安全检查。
        
        综上所述:PreparedStatement使用较多,只有极少数的情况下需要使用Statement
    
    
    4 什么情况下必须使用Statement呢?
        业务方面要求必须支持SQL注入的时候。
        Statement支持sql注入,凡是业务方面要求是需要进行sql语句拼接的,必须使用Statement。
        
    */
    public class JDBCTest07 {
        public static void main(String[] args) {
            // 初始化一个界面
            Map<String,String> userLoginInfo = initUI();
            // 验证用户名和密码
            boolean loginSuccess = login(userLoginInfo);
            System.out.println(loginSuccess == true ? "登陆成功" : "登陆失败");
        }
        /**
         * 用户登录
         * @param userLoginInfo 用户登录信息
         * @return true表示成功  false表示失败
         */
        private static boolean login(Map<String, String> userLoginInfo) {
            // JDBC代码
            Connection conn = null;
            PreparedStatement ps = null; // 这里使用PreparedStatement
            ResultSet rs = null;
            boolean result = false;
            ResourceBundle rb = ResourceBundle.getBundle("loginUser");
            
            String driver = rb.getString("driver");
            String url = rb.getString("url");
            String user = rb.getString("user");
            String password = rb.getString("password");
            
            String loginName = userLoginInfo.get("loginName");
            String loginpwd = userLoginInfo.get("password");
            
            try {
                // 1 注册驱动
                // Class.forName("com.mysql.jdbc.Driver");
                Class.forName(driver);
                
                // 2 获取连接
                // conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase","root","333");
                conn = DriverManager.getConnection(url,user,password);
                
                // 3 获取预编译的数据库操作对象
                // sql语句的框子,其中一个?,表示一个占位符,一个?将来接收一个“值”,注意:占位符不能使用单引号括起来
                String sql = "select * from t_user where loginName = ? and loginpwd = ?";
                
                // 程序执行到此处,会发送slq语句框子给DBMS,然后DBMS进行sql语句的预先编译。
                ps = conn.prepareStatement(sql);
                
                // 给占位符?传值(第1个问号下标是1,第2个问号下标是2,JDBC中所有下标从1开始)
                ps.setString(1,loginName);
                ps.setString(2,loginpwd);
                
                // 4 执行sql语句
                rs = ps.executeQuery();
                
                // 5 处理返回结果集
                if (rs.next()){
                    result = true;
                }
                
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                // 6 释放资源
                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 result;
        }
        
        /**
         * 初始化用户界面
         * @return 用户输入的用户名和密码等登陆信息
         */
        private static Map<String, String> initUI() {
            Scanner scanner = new Scanner(System.in);
            System.out.print("用户名: ");
            String username = scanner.nextLine();
            
            System.out.print("密码: ");
            String password = scanner.nextLine();
            
            Map<String,String> userLoginInfo = new HashMap<>();
            userLoginInfo.put("loginName",username);
            userLoginInfo.put("password",password);
            return userLoginInfo;
        }
    }
     
    案例8:使用Statement可以对查询结果集进行升序和降序,但是用PreparedStatement不行,因为他会预编译。
    package com.java.JDBC;
    
    
    import java.sql.*;
    import java.util.Scanner;
    
    
    public class JDBCTest08 {
        public static void main(String[] args) {
            /*// 用户在控制台输入desc就是降序,输入asc就是升序
            Scanner s = new Scanner(System.in);
            System.out.println("请输入desc或asc,desc表示降序,asc表示升序");
            System.out.print("请输入: ");
            String keyWords = s.nextLine();
            
            // 执行sql
            Connection conn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            try {
                // 注册驱动
                Class.forName("com.mysql.jdbc.Driver");
                // 获取数据库连接
                conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase","root","333");
                // 获取数据库对象
                String sql = "select ename from emp order by ename ?";
                ps = conn.prepareStatement(sql);
                // 执行sql语句
                ps.setString(1,keyWords);
                // 处理查询结果集
                rs = ps.executeQuery();
                // 遍历结果集
                while (rs.next()){
                    String ename = rs.getString("ename");
                    System.out.println(ename);
                }
            } catch (Exception 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();
                    }
                }
            }*/
            
            
            // 用户在控制台输入desc就是降序,输入asc就是升序
            Scanner s = new Scanner(System.in);
            System.out.println("请输入desc或asc,desc表示降序,asc表示升序");
            System.out.print("请输入: ");
            String keyWords = s.nextLine();
        
            // 执行sql
            Connection conn = null;
            Statement stmt = null;
            ResultSet rs = null;
            try {
                // 注册驱动
                Class.forName("com.mysql.jdbc.Driver");
                // 获取数据库连接
                conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase","root","333");
                // 获取数据库对象
                stmt = conn.createStatement();
                // 执行sql语句
                String sql = "select ename from emp order by ename " + keyWords;
                // 处理查询结果集
                rs = stmt.executeQuery(sql);
                // 遍历结果集
                while (rs.next()){
                    String ename = rs.getString("ename");
                    System.out.println(ename);
                }
            } catch (Exception 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();
                    }
                }
            }
        }
    }
  • 相关阅读:
    4-STM32+CH395Q(以太网)基本控制篇(自建物联网平台)-安装Web服务器软件Nginx(.Windows系统)
    单片机程序底层BUG问题,及解决方案
    3-STM32+CH395Q(以太网)基本控制篇(自建物联网平台)-编写android连接MQTT服务器程序
    2-STM32+CH395Q(以太网)基本控制篇(自建物联网平台)-移植单片机MQTT包,编写stm32+CH395Q连接MQTT服务器程序
    1-STM32+CH395Q(以太网)基本控制篇(自建物联网平台)-购买云主机,安装MQTT软件(linux系统),测试C# 和 网页web连接MQTT服务器
    1-STM32+CH395Q(以太网)基本控制篇(自建物联网平台)-购买云主机,安装MQTT软件(.Windows系统),测试C# 和 网页web连接MQTT服务器
    springmvc缓存--验证通过
    使用nginx缓存服务器上的静态文件
    使用nginx缓存服务器上的静态文件
    Jenkins+maven+Tomcat+SVN一键自动打包部署应用到服务器
  • 原文地址:https://www.cnblogs.com/xlwu/p/13654061.html
Copyright © 2011-2022 走看看