Live2D
复制代码

02-JDBC的使用和分析

JDBC使用和问题分析

1、模拟用户登录功能的实现(1)

package ajdbctest;

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

/*
    实现功能:
        1、需求:模拟用户登录功能的实现
        2、业务描述:
            程序运行,提供一个可以让用户输入用户名和密码的入口
            用户输入用户名会让密码之后,提交信息,java程序收集信息
            Java程序连接数据库验证用户名和密码
            合法:显示登陆成功
            不合法:显示登陆失败
        3、在实际开发中,表的设计使用专业的建模工具,这里安装使用的建模工具:PowerDesigner
            使用PD工具来进行数据库表的设计(具体参见user-login.sql脚本)
        4、下面的验证方法是自己写的,是先把表中的所有用户都查询出来,然后进行处理查询结果集遍历与用户输入信息进行if和equals
            比较,该方法可能效率没这么高,因为要把表中的所有数据查出来,还有if语句的原因
 */
public class JDBCTest04 {

    public static void main(String[] args) {

        //初始化用户登录界面方法,让用户输入用户名和密码
        Map<String,String> userLoginInfo = initUI();

        //连接数据库,验证用户输入信息,即登录方法
        boolean userLogin = userLogin(userLoginInfo);

        System.out.println(userLogin?"登录成功!":"登陆失败!");

    }

    /**
     * 连接数据库,验证用户信息的方法
     * @return  返回true,登陆成功;返回false。登录失败
     */
    private static boolean userLogin(Map<String,String> userInfo) {

        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            //注册驱动
            Class.forName("com.mysql.jdbc.Driver");

            //获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysqlstudy","root","rong195302");

            //获取(创建)数据库操作对象
            stmt = conn.createStatement();

            //执行sql查询语句,返回的是查询结果集
            rs = stmt.executeQuery("select * from t_user");

            //处理查询结果集
            while (rs.next()){
                if (userInfo.get("userName").equals(rs.getString("loginName")) && userInfo.get("userPwd").equals(rs.getString("loginPwd"))){
                    return true;
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            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();
                }
            }
        }
        return false;
    }

    /**
     * 初始化用户界面
     * @return  一个map数组,用户输入的用户名和密码
     */
    private static Map<String, String> initUI() {

        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String userName = scanner.nextLine();//该方法表示一次读一行
        System.out.println("请输入密码:");
        String userPwd = scanner.nextLine();

        Map<String,String> userInfo = new HashMap<>();
        userInfo.put("userName",userName);
        userInfo.put("userPwd",userPwd);

        return userInfo;
    }

}

2、模拟用户登录功能的实现(2)

注意与1的区别

package ajdbctest;

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

/*
    实现功能:
        1、需求:模拟用户登录功能的实现
        2、业务描述:
            程序运行,提供一个可以让用户输入用户名和密码的入口
            用户输入用户名会让密码之后,提交信息,java程序收集信息
            Java程序连接数据库验证用户名和密码
            合法:显示登陆成功
            不合法:显示登陆失败
        3、在实际开发中,表的设计使用专业的建模工具,这里安装使用的建模工具:PowerDesigner
            使用PD工具来进行数据库表的设计(具体参见user-login.sql脚本)
        4、下面的验证方法是有SQL注入现象的问题的,是课程中的例子程序
            用户名:sd
            密码:sd' or '1'='1
            登录成功
            这种现象被称为SQL注入
        设置断点在java语句:rs = stmt.executeQuery(sql); 然后Debug,使得该java语句上面的语句都执行,该语句以及下面不执行
        可以看到sql="select * from t_user where loginName='sd' and loginPwd='sd' or '1'='1'";
        该sql语句的原本条件有或没有都没关系啦,因为有:or '1'='1',这个永远为真
        5、SQL注入的根本原因
            用户输入信息中含有sql关键字,并且这些关键字参与了sql语句的编译过程
            导致原SQL语句的含义被扭曲,达到SQL注入。
 */
public class JDBCTest05 {

    public static void main(String[] args) {

        //初始化用户登录界面方法,让用户输入用户名和密码
        Map<String,String> userLoginInfo = initUI();

        //连接数据库,验证用户输入信息,即登录方法
        boolean userLogin = userLogin(userLoginInfo);

        System.out.println(userLogin?"登录成功!":"登陆失败!");

    }

    /**
     * 连接数据库,验证用户信息的方法
     * @return  返回true,登陆成功;返回false。登录失败
     */
    private static boolean userLogin(Map<String,String> userInfo) {

        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            //注册驱动
            Class.forName("com.mysql.jdbc.Driver");

            //获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysqlstudy?useSSL=false","root","rong195302");

            //获取(创建)数据库操作对象
            stmt = conn.createStatement();

            //执行sql查询语句,返回的是查询结果集
            String sql = "select * from t_user where loginName='"+userInfo.get("userName")+"' and loginPwd='"+userInfo.get("userPwd")+"'";
            //以上正好完成了sql语句的拼接,下面代码就是将sql语句发送各DBMS,DBMS进行sql编译。
            //正好将用户提供的"非法信息"编译进去。导致了原SQL语句的含义被扭曲
           rs = stmt.executeQuery(sql);

            //处理查询结果集
            while (rs.next()){
                return true;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            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();
                }
            }
        }
        return false;
    }

    /**
     * 初始化用户界面
     * @return  一个map数组,用户输入的用户名和密码
     */
    private static Map<String, String> initUI() {

        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String userName = scanner.nextLine();//该方法表示一次读一行
        System.out.println("请输入密码:");
        String userPwd = scanner.nextLine();

        Map<String,String> userInfo = new HashMap<>();
        userInfo.put("userName",userName);
        userInfo.put("userPwd",userPwd);

        return userInfo;
    }

}

3、解决SQL注入风险

package ajdbctest;

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

/*
    1、解决SQL注入问题
        使用户提供的用户信息不参与sql语句的编译就可以解决了
        如何实现:使用java.sql.PreparedStatement
        java.sql.PreparedStatement接口继承了java.sql.Statement接口
        java.sql.Statement是数据库操作对象
        java.sql.PreparedStatement是属于预编译的数据库操作对象
        原理:先对给定的sql框架进行预编译,然后在传所需要的条件值

     2、对比Statement和PreparedStatement
        -前者存在SQL注入问题,后者解决了SQL注入问题
        -一般情况下,我们在Windows命令窗口里执行一条SQL语句,第一次执行需要编译,但第二次还是这条不变的SQL语句时不会编译直接执行
        -所以前者是编译一次执行一次,后者由于SQL语句框架不变,编译一次执行N次,PreparedStatement效率高
        -后者会在编译阶段做安全检查
      综上所述:PreparedStatement使用较多,Statement使用较少

      3、什么情况下使用Statement?
        业务方面要求必须支持SQL注入
 */
public class JDBCTest06 {

    public static void main(String[] args) {

        //初始化用户登录界面方法,让用户输入用户名和密码
        Map<String,String> userLoginInfo = initUI();

        //连接数据库,验证用户输入信息,即登录方法
        boolean userLogin = userLogin(userLoginInfo);

        System.out.println(userLogin?"登录成功!":"登陆失败!");

    }

    /**
     * 连接数据库,验证用户信息的方法
     * @return  返回true,登陆成功;返回false。登录失败
     */
    private static boolean userLogin(Map<String,String> userInfo) {

        Connection conn = null;

        //Statement stmt = null;
        PreparedStatement ps = null;

        ResultSet rs = null;
        try {
            //注册驱动
            Class.forName("com.mysql.jdbc.Driver");

            //获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysqlstudy?useSSL=false","root","rong195302");

            //获取(创建)预编译的数据库操作对象
            //stmt = conn.createStatement();
            //SQL语句的框架。其中?表示一个占位符,一个?将来接收一个"值",里面的问号不能用单引号括起来,因为你不知道将来传进的值一定是字符串类型
            String sql = "select * from t_user where loginName= ? and loginPwd= ?";
            //程序执行到下面语句,发送sql语句框子给DBMS,DBMS进行sql语句的预先编译
            ps = conn.prepareStatement(sql);
            //给占位符?传值(第一个?下标是1,第二个?下标是2,JDBC中所有的下标都是从1开始)
            //传值方法的set后面跟传入值的类型,这里是字符串 所以是setString
            ps.setString(1,userInfo.get("userName"));
            ps.setString(2,userInfo.get("userPwd"));

            //执行sql查询语句,返回的是查询结果集
            //rs = stmt.executeQuery(sql);
            rs = ps.executeQuery();//sql语句已经放进预编译数据库操作对象里了,所以不在传sql语句参数

            //处理查询结果集
            while (rs.next()){
                return true;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
        return false;
    }

    /**
     * 初始化用户界面
     * @return  一个map数组,用户输入的用户名和密码
     */
    private static Map<String, String> initUI() {

        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String userName = scanner.nextLine();//该方法表示一次读一行
        System.out.println("请输入密码:");
        String userPwd = scanner.nextLine();

        Map<String,String> userInfo = new HashMap<>();
        userInfo.put("userName",userName);
        userInfo.put("userPwd",userPwd);

        return userInfo;
    }

}

4、适合使用Statement的情景

package ajdbctest;

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

/*
    演示只能使用Statement的功能需求:
        输入参数使查询结果升序或者是降序输出,需要将升序降序关键字的字符串拼接到SQL语句中

 */
public class JDBCTest07 {

    public static void main(String[] args) {

//        //用户输入控制查询结果升序降序的信息
//        Scanner scanner = new Scanner(System.in);
//        System.out.println("请输入关键字信息:升序asc,降序desc");
//        String info = scanner.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/mysqlstudy?useSSL=false","root","rong195302");
//
//            String sql = "select sal from emp order by sal ?";
//            ps = conn.prepareStatement(sql);
//            ps.setString(1,info);
//
//            rs = ps.executeQuery();
//
//            while (rs.next()){
//                String sal = rs.getString(1);
//                System.out.println(sal);
//            }
//
//        } catch (ClassNotFoundException e) {
//            e.printStackTrace();
//        } catch (SQLException throwables) {
//            throwables.printStackTrace();
//        }finally {
//            if (rs != null) {
//                try {
//                    rs.close();
//                } catch (SQLException throwables) {
//                    throwables.printStackTrace();
//                }
//            }
//            if (ps != null) {
//                try {
//                    ps.close();
//                } catch (SQLException throwables) {
//                    throwables.printStackTrace();
//                }
//            }
//            if (conn != null) {
//                try {
//                    conn.close();
//                } catch (SQLException throwables) {
//                    throwables.printStackTrace();
//                }
//            }
//        }


        //用户输入控制查询结果升序降序的信息
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入关键字信息:升序asc,降序desc");
        String info = scanner.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/mysqlstudy?useSSL=false","root","rong195302");

            stmt = conn.createStatement();

            String sql = "select sal from emp order by sal "+info;
            rs = stmt.executeQuery(sql);

            while (rs.next()){
                String sal = rs.getString(1);
                System.out.println(sal);
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            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();
                }
            }
        }

    }

}

5、使用PrepareStatement进行增删操作

package ajdbctest;

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

/*
    使用PreparedStatement进行增删改
 */
public class JDBCTest08 {

    public static void main(String[] args) {

        Connection conn = null;
        PreparedStatement ps = null;

        try {

            Class.forName("com.mysql.jdbc.Driver");

            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysqlstudy?useSSL=false","root","rong195302");

            //增
//            String sql = "insert into dept(deptno,dname,loc) values (?,?,?)";
//            ps = conn.prepareStatement(sql);
//            ps.setInt(1,50);
//            ps.setString(2,"销售部");
//            ps.setString(3,"北京");

            //改
//            String sql = "update dept set dname = ?,loc = ? where deptno = ?";
//            ps = conn.prepareStatement(sql);
//            ps.setString(1,"技术部");//要注意下标
//            ps.setString(2,"大唐");
//            ps.setInt(3,50);

            //删
            String sql ="delete from dept where deptno = ?";
            ps = conn.prepareStatement(sql);
            ps.setInt(1,50);

            int count = ps.executeUpdate();//注意这里不是Query
            System.out.println(count);

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

    }

}

posted @ 2021-08-01 12:16  Milen-jie  阅读(34)  评论(0编辑  收藏  举报