Java笔记25——Java JDBC(上)

Java学习——Java JDBC(上)


一、JDBC的连接

构建JDBC应用程序涉及以下六个步骤:

  • 导入包:需要包含包含数据库编程所需的JDBC类的包。大多数情况下,使用import java.sql.*就足够
    了。
  • 注册JDBC驱动程序:要求您初始化驱动程序,以便您可以打开与数据库的通信通道。
  • 打开连接:需要使用DriverManager.getConnection()方法创建一个Connection对象,该对象表
    示与数据库的物理连接。
  • 执行查询:需要使用类型为Statement的对象来构建和提交SQL语句到数据库。
  • 从结果集中提取数据:需要使用相应的ResultSet.getXXX()方法从结果集中检索数据。
  • 释放资源:需要明确地关闭所有数据库资源,而不依赖于JVM的垃圾收集。

建立JDBC连接是简单的四个步骤:

  • 导入JDBC包:将Java语言的import语句添加到Java代码中导入所需的类。
  • 注册JDBC驱动程序:此步骤将使JVM将所需的驱动程序实现加载到内存中,以便它可以满足您的JDBC
    请求。
  • 数据库URL配置:这是为了创建一个格式正确的地址,指向要连接到的数据库。
  • 创建连接对象:最后,调用DriverManager对象的getConnection()方法来建立实际的数据库连接。

Class.forName();

注册驱动程序最常见的方法是使用Java的Class.forName()方法,将驱动程序的类文件动态加载到内存中,并将其自动注册

try {
    Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException ex) {
    System.out.println("Error: unable to load driver class!");
    System.exit(1);
}

DriverManager.registerDriver()

第二种方法是使用静态DriverManager.registerDriver()方法。

    try {
        Driver myDriver = new com.mysql.cj.jdbc.Driver();
        DriverManager.registerDriver(myDriver);
    } catch (ClassNotFoundException ex) {
        System.out.println("Error: unable to load driver class!");
        System.exit(1);
    }

数据库URL配置
加载驱动程序后,可以使用DriverManager.getConnection()方法建立连接。为了方便参考,让我
列出三个重载的DriverManager.getConnection()方法

  • getConnection(String url)
  • getConnection(String url,Properties prop)
  • getConnection(String url,String user,String password)

在这里插入图片描述
创建数据库连接对象

String URL = "jdbc:mysql://localhost:3306/数据库名?useSSL=false&useUnicode=true&characterEncoding=UTF-8"; 
String USER = "username"; 
String PASS = "password" 
Connection conn = DriverManager.getConnection(URL, USER, PASS);

使用数据库URL和属性对象
DriverManager.getConnection()方法的第三种形式需要一个数据库URL和一个Properties对象

DriverManager.getConnection(String url, Properties info);

关闭数据库连接

为确保连接关闭,您可以在代码中的“finally”块,调用对应对象的close()方法。

例:

import java.util.*; String URL = "jdbc:mysql://localhost:3306/yhp2?serverTimezone=UTC"; 
Properties info = new Properties( ); 
info.put( "user", "username" ); 
info.put( "password", "password" ); 
Connection conn = DriverManager.getConnection(URL, info);

JDBC的 连接示例:

数据库需要提前定义好字段,并存入数据,方便接下来代码中的操作:
数据库名:mydatabase
表:department
在这里插入图片描述
表employee:
在这里插入图片描述

import java.sql.*;

/**
 * JDBC操作步骤
 */
public class Demo1 {
    public static void main(String[] args) {
        //创建需要使用到的类的对象
        Connection conn = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            //1.加载驱动
            //  方法一、将驱动程序的类文件动态加载到内存中,并将其自动注册
            Class.forName("com.mysql.cj.jdbc.Driver");
            //  方法二、是使用静态DriverManager.registerDriver()方法。
/*
            Driver myDriver = new com.mysql.cj.jdbc.Driver();
            DriverManager.registerDriver(myDriver);
*/

            //2.获得链接
            String username = "root";   //数据库用户名
            String password = "111111"; //密码
            String url = "jdbc:mysql://localhost:3306/mydatabase?serverTimezone=UTC";   //连接的数据库信息:数据库地址:使用端口号/使用数据库名
            conn = DriverManager.getConnection(url, username, password);  //与该url下的数据库建立连接

            //3.定义sql,用于执行sql语句(进行sql语句的发送)
            //  方法一、创建状态通道 Statement
            statement = conn.createStatement();
            //  方法二、创建预状态通道 PreparedStatement (参考预状态通道,可防止sql注入)
//            PreparedStatement statement1 = conn.prepareStatement("");

            //通过statement对象调用方法,执行sql语句
            //  (1)、对数据库进行查询操作(DQL),并返回结果集
            resultSet = statement.executeQuery("select * from employee");
            //  (2)、对数据库执行 增删改 操作(DML语句),使用Statement类中的executeUpdate方法
/*
            int result1 = statement.executeUpdate("insert into department(depid,depname) values('555','行政部')");  //对数据库进行数据添加操作,并返回影响行数
            int result2 = statement.executeUpdate("update employee set sex = '女' where name = '张三'");  //对数据库进行数据修改操作,并返回影响行数
            int result3 = statement.executeUpdate("delete from employee where name = '赵六'");  //对数据库进行数据添加操作,并返回影响行数
            System.out.println("返回行数:" + result1);
*/
            //  (3)、对数据库执行数据库定义操作(执行SQL DDL语句或需要使用真正的动态SQL时),返回的是布尔类型
            //        如果执行sql语句得到的是resultSet结果集则返回true,如果是得到的是update count或是没产生结果则返回false
/*
            boolean resultCondition = statement.execute("create table test(id int primary key auto_increment,name varchar(20),sex char(2) not null)");
            System.out.println("返回情况:" + resultCondition);
*/

            //4.取出结果集信息
            while (resultSet.next()) {  //首先判断下是否存在下条数据(类似迭代器)
                //取出数据:resultSet.getXX()方法
                System.out.println("姓名:" + resultSet.getString("name") + ",性别:" + resultSet.getString("sex") +
                        ",职称:" + resultSet.getString("title") + ",生日:" + resultSet.getDate("birthday") + ",员工id:" + resultSet.getString("empid"));

            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            try {
                //5.关闭资源
                if (resultSet != null) {
                    resultSet.close();
                }
                if (statement != null) {
                    statement.close();
                }
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

二、SQL注入与预处理通道

1. SQL注入

此时我们的数据库test表中如下数据:
在这里插入图片描述

在代码中如是写下:

public static void main(String[] args) {
        //创建需要使用到的类的对象
        Connection conn = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            String username = "root";   //数据库用户名
            String password = "111111"; //密码
            String url = "jdbc:mysql://localhost:3306/mydatabase?serverTimezone=UTC";   
            conn = DriverManager.getConnection(url,username,password); 
            statement = conn.createStatement();
            String uname = "aa",upass = "123";	//表中数据查询
            resultSet = statement.executeQuery("select * from test where name = '"+ uname +"' and password = " + upass);
            if (resultSet.next()) {	//查询到结果时,视为登陆成功
                System.out.println("登录成功!");
            }else {
                System.out.println("登录失败!");
            }
            } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            try {
                //关闭资源
                if (resultSet != null) {
                    resultSet.close();
                }
                if (statement != null) {
                    statement.close();
                }
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }

此时的uname 与 upass 的数据正确:
在这里插入图片描述

SQL注入情况:当我们的uname 与 upass 传入下面的情况时,upass里的值 表达的是恒成立,所以会出现登录成功的情况:

String uname = "111",upass = "' ' or 1=1";

在这里插入图片描述
这种情况便称为:SQL注入,用户名和密码与我们数据库数据对不上号,但还是能够查询到结果。

2. 预处理通道

为防止SQL注入的情况出现我们使用预处理通道 PrepareStatement

该PreparedStatement的接口扩展了Statement接口,它为您提供了一个通用的Statement对象有两个优点附加功能。
此语句使您可以动态地提供参数。

格式:

PreparedStatement pstmt = null; 
try{
    String SQL = "Update Employees SET age = ? WHERE id = ?";
    pstmt = conn.prepareStatement(SQL); 
    . . .
}catch(
    SQLException e){
    . . .
}finally{ 
    . . .
}

示例:

public static void main(String[] args) {
        //预状态通道的使用
        Connection conn = null;
//        Statement statement = null;
        ResultSet resultSet = null;
        PreparedStatement pps = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            String username = "root";   //数据库用户名
            String password = "111111"; //密码
            String url = "jdbc:mysql://localhost:3306/mydatabase?serverTimezone=UTC";
            conn = DriverManager.getConnection(url,username,password);
            String sql = "select * from test where name=? and password=?";  //在变量的位置使用占位符?
            pps = conn.prepareStatement(sql);
            String uname = "111",upass = "' ' or 1=1";
            //给占位符?赋值:方法(下标,参数传递)
            pps.setString(1,uname);
            pps.setString(2,upass);
            resultSet = pps.executeQuery();     //直接调用空参方法
            if (resultSet.next()) {	    //查询到结果时,视为登陆成功
                System.out.println("登录成功!");
            }else {
                System.out.println("登录失败!");
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            try {
                //关闭资源
                if (resultSet != null) {
                    resultSet.close();
                }
                if (pps != null) {
                    pps.close();
                }
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }

使用了预状态通道,SQL注入便失效了,只有当使用正确的数据时,才能登入:
在这里插入图片描述

对比statement和PreparedStatement

  1. statement属于状态通道,PreparedStatement属于预状态通道。
  2. 预状态通道会先编译sql语句,再去执行,比statement执行效率高。
  3. 预状态通道支持占位符?,给占位符赋值的时候,位置从1开始。
  4. 预状态通道可以防止sql注入,原因:预状态通道在处理值的时候以字符串的方式处理。

总结

Java JDBC(上),( ̄︶ ̄)↗ !!!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值