JDBC 学习笔记2

本文通过 Java JDBC 的示例,展示了如何处理数据库查询结果,并深入探讨了 SQL 注入的风险及其解决方案。通过对比 Statement 和 PreparedStatement 的使用,强调了预编译 SQL 语句在防止 SQL 注入攻击中的关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.处理查询结果集(遍历结果集)
在这里插入图片描述

package test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ResourceBundle;

public class jdbcTest04 {
    public static void main(String[] args) {
        ResourceBundle bundle = ResourceBundle.getBundle("JDBC");
        String driver = bundle.getString("driver");
        String url = bundle.getString("url");
        String user = bundle.getString("user");
        String password = bundle.getString("password");
        Connection con = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            //1.注册驱动
            Class.forName(driver);
            //2.获得连接
            con = DriverManager.getConnection(url, user, password);
            //3.获取数据库操作对象
            stmt = con.createStatement();
            //4.执行sql语句
            String sql = "select id, 李在赣神魔 from test order by id";
            //int executeUpdate(insert, delete, update);
            //ResultSet executeQuery(select);
            rs = stmt.executeQuery(sql); //专门执行DQL语句的办法
            //5.处理查询结果集
            while(rs.next()) { //光标指向的行有数据,取数据
                //getString()方法的特点是,不管数据库中的数据类型是什么,都以String的形式取出
                //这个是以列的下表获取
                /*String a = rs.getString(1); //jdbc中所有下标从1开始,不是从0开始
                String b = rs.getString(2);
                System.out.println(a + "," + b);*/
                //这个不是以列的下标获取,而是以列的名字获取
                String a = rs.getString("id"); //重点注意:列名称不是表中的列名称,是查询结果集的列名称
                String b = rs.getString("李在赣神魔");
                System.out.println(a + "," + b);
                //另外注意,除了可以以String类型取出外,还可以以特定的类型取出,如getInt(),getDouble()等
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            try {
                if(rs != null)
                    rs.close();
            }
            catch (Exception e) {
                e.printStackTrace();
            }
            try {
                if(stmt != null)
                    stmt.close();
            }
            catch (Exception e) {
                e.printStackTrace();
            }
            try {
                if(con != null)
                    con.close();
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

2.demo
在这里插入图片描述

package test;

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

public class jdbcTest05 {
    public static void main(String[] args) {
        //初始化一个界面
        Map<String, String> userLoginInfo = initUI();
        //验证用户名和密码
        boolean loginSuccess = login(userLoginInfo);
        //最后输出结果
        System.out.println(loginSuccess ? "登陆成功" : "登陆失败");
    }

    /**
     *用户登录
     * @param userLoginInfo 用户登陆信息
     * @return false表示失败 true表示成功
     */
    private static boolean login(Map<String, String> userLoginInfo) {
        boolean loginSuccess = false;
        //jdbc代码
        Connection con = null;
        Statement stmt = null;
        ResultSet rs = null;
        ResourceBundle bundle = ResourceBundle.getBundle("JDBC");
        String driver = bundle.getString("driver");
        String url = bundle.getString("url");
        String user = bundle.getString("user");
        String password = bundle.getString("password");
        try {
            //1.注册驱动
            Class.forName(driver);
            //2.获得连接
            con = DriverManager.getConnection(url, user, password);
            //3.获得数据库操作对象
            stmt = con.createStatement();
            //4.执行sql语句
            String sql = "select * from t_user where loginName = '"+userLoginInfo.get("loginName")+"' and " +
                    "loginPwd = '"+userLoginInfo.get("loginPwd")+"'";
            rs = stmt.executeQuery(sql);
            //5.处理结果集
            if(rs.next())
                loginSuccess = true;
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            //6.释放资源
            try {
                if(rs != null)
                    rs.close();
            }
            catch(SQLException e) {
                e.printStackTrace();
            }
            try {
                if(stmt != null)
                    stmt.close();
            }
            catch(SQLException e) {
                e.printStackTrace();
            }
            try {
                if(con != null)
                    con.close();
            }
            catch(SQLException e) {
                e.printStackTrace();
            }
        }
        return loginSuccess;
    }

    /**
     * 初始化用户界面
     * @return 用户输入的用户名和密码等登陆信息
     */
    private static Map<String, String> initUI() {
        Scanner console = new Scanner(System.in);
        System.out.println("用户名: ");
        String loginName = console.nextLine();
        System.out.println("密码: ");
        String loginPwd = console.nextLine();
        Map<String, String> userLoginInfo = new HashMap<>();
        userLoginInfo.put("loginName", loginName);
        userLoginInfo.put("loginPwd", loginPwd);
        return  userLoginInfo;
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3.上面的程序是有漏洞的,诸位看到了在我的数据库表中只有zhangsan和jack两个人,但是如果我输入:
用户名:
fdsa
密码:
fdsa’ or ‘1’='1
则会登陆成功:
在这里插入图片描述
原因是:
在这里插入图片描述
在这里插入图片描述
解决SQL注入问题:
只要用户提供的信息不参与SQL语句的编译过程,问题就解决了。
即使用户提供的信息中心含有SQL语句的关键字,但是没有参与编译,不起作用。
要想用户信息不参与SQL语句的编译,那么必须使用java.sql.PreparedStatement
PreparedStatement接口继承了java.sql.Statement
PreparedStatement是属于预编译的数据库操作对象
PreparedStatement原理:预先对SQL语句的框架进行编译,然后再给SQL语句传值。
下面对上面的代码进行修改:

package test;

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

public class jdbcTest06 {
    public static void main(String[] args) {
        //初始化一个界面
        Map<String, String> userLoginInfo = initUI();
        //验证用户名和密码
        boolean loginSuccess = login(userLoginInfo);
        //最后输出结果
        System.out.println(loginSuccess ? "登陆成功" : "登陆失败");
    }

    /**
     *用户登录
     * @param userLoginInfo 用户登陆信息
     * @return false表示失败 true表示成功
     */
    private static boolean login(Map<String, String> userLoginInfo) {
        boolean loginSuccess = false;
        //jdbc代码
        Connection con = null;
        PreparedStatement ps = null; //这里使用PreparedStatement(预编译的数据库操作对象)
        ResultSet rs = null;
        ResourceBundle bundle = ResourceBundle.getBundle("JDBC");
        String driver = bundle.getString("driver");
        String url = bundle.getString("url");
        String user = bundle.getString("user");
        String password = bundle.getString("password");
        try {
            //1.注册驱动
            Class.forName(driver);
            //2.获得连接
            con = DriverManager.getConnection(url, user, password);
            //3.获取预编译数据库操作对象
            //SQL语句的框子,其中一个问号表示一个占位符,一个问号将来接受一个值。注意占位符不能用单引号括起来
            String sql = "select * from t_user where loginName = ? and loginPwd = ?";
            //程序执行到此处,会发送sql语句框子给DBMS,然后DBMS进行SQL语句的预先编译
            ps = con.prepareStatement(sql);
            //给占位符?传值(第一个问号下标是1,第二个问号下标是2,JDBC中所有下标从1开始)
            ps.setString(1,userLoginInfo.get("loginName"));
            ps.setString(2,userLoginInfo.get("loginPwd"));
            //4.执行sql语句
            rs = ps.executeQuery();
            //5.处理结果集
            if(rs.next())
                loginSuccess = true;
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            //6.释放资源
            try {
                if(rs != null)
                    rs.close();
            }
            catch(SQLException e) {
                e.printStackTrace();
            }
            try {
                if(ps != null)
                    ps.close();
            }
            catch(SQLException e) {
                e.printStackTrace();
            }
            try {
                if(con != null)
                    con.close();
            }
            catch(SQLException e) {
                e.printStackTrace();
            }
        }
        return loginSuccess;
    }

    /**
     * 初始化用户界面
     * @return 用户输入的用户名和密码等登陆信息
     */
    private static Map<String, String> initUI() {
        Scanner console = new Scanner(System.in);
        System.out.println("用户名: ");
        String loginName = console.nextLine();
        System.out.println("密码: ");
        String loginPwd = console.nextLine();
        Map<String, String> userLoginInfo = new HashMap<>();
        userLoginInfo.put("loginName", loginName);
        userLoginInfo.put("loginPwd", loginPwd);
        return  userLoginInfo;
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值