八、MySQL 08JDBC

八、JDBC

8.1 JDBC 介绍

JDBC (Java Database Connectivity,Java数据库连接)

8.1.1 使用 JDBC 的原因

  • Java 通过 JDBC 技术实现对各种数据库的访问,充当 Java 应用程序与各种数据库之间进行对话的媒介
  • 通过 JDBC 可以将程序中的数据持久的保存到数据库当中
  • Sun 公司提供了 JDBC 的接口规范------JDBC API

8.1.2 JDBC 的工作原理

  • JDBC 主要有 JDBC API、JDBC Driver Manager 和 JDBC 驱动组成
Java应用程序
JDBCAPI
JavaJDBCManager
JDBC驱动
JDBC驱动O
MySQL
Oracle

1、JDBC API

  • JDBC API 提供了一套 Java 应用程序与各种数据库交互的标准接口
  • 其中 Connection(连接)接口、Statement 接口、ResultSet(结果集)接口、preparedStatement 接口等都属于 JDBC 接口

2、JDBC Driver Manager

  • JDBC Driver Manager 是 JDBC 体系结构的支柱
  • 负责管理各种 JDBC 驱动
  • JDBC Driver Manager 位于 JDK 的 java.sql 包中

3、JDBC 驱动

  • JDBC 驱动不包含在 JDK中,由第三方中间厂商提供
  • 负责连接各种数据库

8.1.3 JDBC API

  • JDBC API 是 Java 应用与各种数据库交互的标准接口
  • 主要功能是建立与数据库的连接,发送 SQL 语句,返回处理结果
  • JDBC API 主要类/接口 的功能
类/接口作用
DriverManager 类装载驱动程序,并为创建新的数据库连接提供支持
Connection 接口负责连接数据库并担任传送数据的任务
Statement 接口由 Connection 产生,负责执行 SQL 语句
PreparedStatement 接口Statement 的子接口,也由 Connection 产生,负责执行 Sql语句
与 Statement 接口的区别:PreparedStatement 借口具有高安全性、
高性能、高可读性和高可维护性等优点
ResultSet 接口负责保存和处理 Statement 执行后产生的查询结果

8.2 使用 JDBC 连接数据库

8.2.1 使用 JDBC 连接数据库的方法

1、加载 JDBC 驱动

  • JDBC 驱动由数据库厂商或第三方中间件厂商提供,使用 JDBC 连接数据库前要先下载对应版本的驱动
  • 可以在 MySQL 广为下载对应的 JDBC 驱动 JAR 包
  • 导入 JDBC 的驱动 JAR 包后,需要加载驱动
  • 驱动类的类名为 com.mysql.jdbc.Driver
  • 通常使用 Class.forName 加载 JDBC 驱动
  • 使用 Class.forName 加载驱动 语法
try{
    Class.forName("JDBC驱动类的名称")
}catch(ClassNotFoundException){
    //异常输出代码
}

2、与数据库建立连接

  • JDBC 驱动类加载后,需要建立与 MySQL 数据库连接
  • 建立连接使用 DriverManager 类,DriverManager 类是 JDBC 的管理层,作用于用户和驱动程序之间
  • getConnection() 方法用于建立与数据库的连接
  • 调用 getConnection() 方法 需要放入参数:数据库连接地址字符串、连接数据库的用户名和密码
  • 建立连接数据库 语法
Connection conn=DriverManager.getConnection(数据库连接地址字符串,数据库用户名,密码)
  • 数据库连接字符串 语法格式
jdbc:数据库://ip:端口/数据库名称 [?连接参数=参数值]
  • 数据库: JDBC 连接的目标数据库,如 MySQL 数据库
  • ip:JDBC 所连接的目标数据库地址,如果是本地数据库,则可以使用 localhost。即本地主机名
  • 端口:连接数据库的端口号,如果连接 MySQL 数据库,则默认端口号为 3306
  • 数据库名称:目标数据库的名称,如 hospital
  • 连接参数:连接数据库时的参数配置。
  • Connection 接口常用的方法
方法名称作用
Statement createStatement()创建一个 Statement 对象并将 SQL 语句发送到数据库
PreparedStatement preparedStatement(String sql)创建一个 PreparedStatement 对象并将参数化的 SQL 语句发送到数据库
boolean isClosed()查询此 Connection 对象是否已经被关闭。若已关闭,返回true
void close()立即释放此 Connection 对象的数据库和 JDBC 资源

8.3 使用 Statement 执行数据库操作

8.3.1 使用 Statement 接口更新数据

  • 获取 Connection 对象后,需要使用 Connection 对象的 createStatement() 方法创建 Statement 对象,在通过 Statement 对象 将 SQL 语句发送到 MySQL 服务器中执行操作

  • 在 Statement 接口中执行 SQL 命令的 3 种常用方法

方法名称作用
ResultSet executeQuery(String sql)可以执行 SQL 查询并获取 ResultSet 对象
int executeUpdate(Sting sql)可以执行插入、删除、更新等操作,返回值时执行该操作所影响的行数
boolean execute(String sql)可以执行任意 SQL 语句。若结果为 Result 对象,则返回 true;若结果为
更新计数或不存在任何结果,则返回 false
  • 使用 Statement 接口更新数据库中数据的步骤,与插入、修改、删除数据类似,都可以使用 executeUpdate() 方法
  • 使用Statement执行对象实现新增操作 示例
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
/**
 * 准备工作:
 * 1.从官网下载MySql驱动包
 * 2.将驱动包引入到项目工程中
 */
public class LX_insert {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {

        Scanner input=new Scanner(System.in);
        //设置连接数据库需要的参数
        //获取驱动类
        String driver="com.mysql.jdbc.Driver";
        //数据库连接地址
        String url="jdbc:mysql://localhost:3306/hospital?useUnicode=true&characterEncoding=UTF-8";
        //数据库用户名
        String user="root";
        //数据库密码
        String password="root";

        //加载驱动
        Class.forName(driver);
        //建立数据库连接
        Connection conn= DriverManager.getConnection(url,user,password);
        //创建 Statement 对象
        Statement statement=conn.createStatement();
        //获取要添加的数据
        System.out.print("请输入患者密码:");
        String patientPassWord=input.next();
        System.out.print("请输入患者性别:");
        String patientGender=input.next();
        System.out.print("请输入患者姓名:");
        String patientName=input.next();
        //拼接 SQL 语句
        StringBuffer sql=new StringBuffer("INSERT INTO patient(password,gender,patientName) VALUES ('");
        sql.append(patientPassWord);
        sql.append("','");
        sql.append(patientGender);
        sql.append("','");
        sql.append(patientName);
        sql.append("');");
        System.out.println(sql);
        //发送 SQL 语句,并接收结果
        int effectRowNum= statement.executeUpdate(sql.toString());
        //判断是否添加成功
        if(effectRowNum>0){
            System.out.println("添加成功");
        }else{
            System.out.println("添加失败");
        }
        //关闭资源
        statement.close();
        conn.close();
    }
}

运行结果

请输入患者密码:111111
请输入患者性别:男
请输入患者姓名:无名氏
INSERT INTO patient(password,gender,patientName) VALUES ('111111','男','无名氏');
添加成功

8.3.2 使用 Statement 接口和 ResultSet 接口查询数据

  • 使用 JDBC 查询数据库中的数据时,需要使用 ResultSet 对象来接收从数据库中返回的数据

  • ResultSet 常用方法

方法名说明
boolean next()将游标从当前位置向下移动一行
boolean previous()游标从当前位置向上移动一行
void close关闭 ResultSet 对象
int getInt(int colIndex)以 int 形式获取结果集当前行指定列号值
int getInt(String colLabel)以 int 形式获取结果集当前行指定列名值
float getFloat(int colIndex)以 float 形式获取结果集当前行指定列号值
float getFloat(String colLabel)以float形式获取结果集当前行指定列名值
String getString(int colIndex)以String形式获取结果集当前行指定列号值
String getString(String colLabel)以String形式获取结果集当前行指定列名值
  • 使用 Statement 接口和 ResultSet 接口查询数据 示例
import java.sql.*;

/**
 * 准备工作:
 * 1.从官网下载MySql驱动包
 * 2.将驱动包引入到项目工程中
 */
public class LX_Select {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //设置连接数据库需要的参数
        //获取驱动类
        String driver="com.mysql.jdbc.Driver";
        //数据库连接地址
        String url="jdbc:mysql://localhost:3306/hospital?useUnicode=true&characterEncoding=UTF-8";
        //数据库用户名
        String user="root";
        //数据库密码
        String password="root";

        //加载驱动
        Class.forName(driver);
        //建立数据库连接
        Connection conn= DriverManager.getConnection(url, user, password);
        //创建 Statement 对象
        Statement statement=conn.createStatement();
        //SQL 语句
        String sql="SELECT * FROM patient";
        //向 MySQL 发送 SQL 语句,并接收结果
        ResultSet rs=statement.executeQuery(sql);
        //输出结果
        //判断结果是否还有下一个
        while(rs.next()){
            //如果有下一个 输出 patientID列、patientName列
            System.out.println("病人编号:"+rs.getString("patientID")+"病人姓名:"+rs.getString("patientName"));
        }
        //关闭资源
        rs.close();
        statement.close();
        conn.close();

    }
}

运行结果

病人编号:1病人姓名:夏颖
病人编号:2病人姓名:李政
病人编号:3病人姓名:李沁
病人编号:4病人姓名:李思雨
病人编号:5病人姓名:夏天
病人编号:6病人姓名:刘占波
病人编号:7病人姓名:廖慧颖
病人编号:8病人姓名:李伟忠
病人编号:9病人姓名:姚维新
病人编号:10病人姓名:陈建
病人编号:11病人姓名:林永清
病人编号:12病人姓名:李亚
病人编号:13病人姓名:张菲

8.4 使用 PreparedStatement 接口防止 SQL 注入

8.4.1 SQL 注入攻击

  • SQL 注入攻击是是一种注入攻击,应用程序没有对用户输入数据的合法性进行判断,导致应用程序存在安全隐患,最终达到欺骗服务器执行恶意的SQL命令
  • 用户提交一段 SQL 代码,执行超出其权限的数据操作就被成为 SQL 注入攻击
  • 现在为医院管理系统开发登录功能,要求用户输入密码和姓名,判断是否通过验证

代码演示

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

/**
 * 准备工作:
 * 1.从官网下载MySql驱动包
 * 2.将驱动包引入到项目工程中
 */

public class LX_SQL {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Scanner input=new Scanner(System.in);
        //设置连接数据库需要的参数
        //获取驱动类
        String driver="com.mysql.jdbc.Driver";
        //数据库连接地址
        String url="jdbc:mysql://localhost:3306/hospital?useUnicode=true&characterEncoding=UTF-8";
        //数据库用户名
        String user="root";
        //数据库密码
        String password="root";
        //接收用户输入的姓名和密码
        System.out.print("请输入患者姓名:");
        String patientName=input.next();
        System.out.print("请输入患者密码:");
        String patientPassword=input.next();
        //加载驱动
        Class.forName(driver);
        //建立数据库连接
        Connection conn= DriverManager.getConnection(url, user, password);
        //创建 Statement 对象
        Statement statement=conn.createStatement();
        //SQL 语句
        StringBuffer sql=new StringBuffer("SELECT * FROM patient where patientName='");
        sql.append(patientName);
        sql.append("'and password='");
        sql.append(patientPassword);
        sql.append("';");
        //向 MySQL 发送 SQL 语句,并接收结果
        ResultSet rs=statement.executeQuery(sql.toString());
        //判断输入的是否正确
        if(rs.next()){
            System.out.println("登录成功");
            System.out.println("病人姓名:"+rs.getString("patientName"));
        }else{
            System.out.println("登录失败");
        }
        //关闭资源
        rs.close();
        statement.close();
        conn.close();

    }
    }

效果演示

请输入患者姓名:夏颖
请输入患者密码:123456
登录成功
病人姓名:夏颖

使用 SQL注入攻击 效果演示

请输入患者姓名:*-*
请输入患者密码:100'OR'1'='1
登录成功
病人姓名:夏颖
  • 由上方演示可看出,这是典型的 SQL 注入攻击
  • 原因时在使用 Statement 接口方法时要进行 SQL 语句的拼接。拼接不仅繁琐且容易出错
  • 使用 PreparedStatement 可以规避这些问题

8.4.2 使用 PreparedStatement 接口查询数据

  • PreparedStatement 接口继承自 Statement 接口
  • PreparedStatement 接口的常用方法
方法作用
boolean execute()执行 SQL 语句,该语句可以是任何 SQL 语句。若结果为 Result 对象,
则返回 true;若结果是更新计数或没有结果,则返回 false
ResultSet executeQuery()执行 SQL 查询,并返回该查询生成的 ResultSet 对象
int executeUpdate()执行 SQL 语句,该语句必须是一个 DML 语句,如 INSERT、UPDATE 或 DELETE
语句;或者是无返回内容的 SQL 语句和 DDL 语句。返回值时执行该操作所影响的行数
void sexXxx(int index,xxx x)方法名 Xxx 和第二个参数的 xxx 均表示如 int、float、double 等基本数据类型,
并且两个类型必须一致,参数列表中的 x 表示方法的形式参数。把指定数据类型 (xxx)
的值 x 设置为 index 位置的参数。根据参数类型的不同,常见的方法有
setInt(int index,int x)、setFloat(int index,float x),setDouble(int index,double x) 等
void setObject(int index,Object x)除基本数据类型外,参数类型也可以使 Object,可以将 Object 对象 x 设置为 index 位置的参数

8.4.3 创建 PreparedStatement 对象

1、创建 PreparedStatement 对象

  • 通过 Connection 接口的 prepareStatement (String sql) 方法创建 PreparedStatement 对象

  • 在创建 PreparedStatement 对象时应设置号该对象要执行的 SQL 语句

  • SQL 语句可以具有一个或多个输入参数时,这些输入参数的值在 PreparedStatement 创建时违背指定,而

    是为每个参数保留一个 作为占位符

  • 因为 SQL 语句的参数已经固定,所以不会出现 SQL 注入的漏洞

  • 在 SQL 语句中使用 作为占位符 演示

String sql="SELECT * FROM patient where patientName=? and password=?"

2、设置输入参数的值

  • 通过调用 setXxx() 方法完成参数赋值
  • Xxx 时与该参数类型相应的类型,若参数是 String 类型,则使用方法 setString()
  • setXxx() 方法的第一个参数选择设置某个参数 (从1开始计数)
  • 第二个参数用于设置该参数的值
  • 设置 SQL 语句中参数的值 演示
String sql="SELECT * FROM patient where patientName=? and password=?";
PreparedStatement pps=conn.prepareStatement(sql);
pps.setString(1,"夏颖");
pss.setString(2,"123456")

3、使用 PreparedStatement 升级医院管理系统开发登录功能

  • 代码演示
import java.sql.*;
import java.util.Scanner;
import java.sql.*;

/**
 * 准备工作:
 * 1.从官网下载MySql驱动包
 * 2.将驱动包引入到项目工程中
 */

public class LX_SQL {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Scanner input=new Scanner(System.in);
        //设置连接数据库需要的参数
        //获取驱动类
        String driver="com.mysql.jdbc.Driver";
        //数据库连接地址
        String url="jdbc:mysql://localhost:3306/hospital?useUnicode=true&characterEncoding=UTF-8";
        //数据库用户名
        String user="root";
        //数据库密码
        String password="root";
        //接收用户输入的姓名和密码
        System.out.print("请输入患者姓名:");
        String patientName=input.next();
        System.out.print("请输入患者密码:");
        String patientPassword=input.next();
        //加载驱动
        Class.forName(driver);
        //建立数据库连接
        Connection conn= DriverManager.getConnection(url, user, password);
        //SQL 语句
        String sql="SELECT * FROM patient where patientName=? and password=?";
        //创建 PreparedStatement 对象
        PreparedStatement pps=conn.prepareStatement(sql);
        //设置参数值
        pps.setString(1,patientName);
        pps.setString(2,patientPassword);
        //输出 SQL 语句
        System.out.println(pps.toString());
        //接收查询数据
        ResultSet rs=pps.executeQuery();
        //判断输入的是否正确
        if(rs.next()){
            System.out.println("登录成功");
            System.out.println("病人姓名:"+rs.getString("patientName"));
        }else{
            System.out.println("登录失败");
        }
        //关闭资源
        rs.close();
        pps.close();
        conn.close();

    }
    }

运行效果展示

请输入患者姓名:夏颖
请输入患者密码:123456
com.mysql.jdbc.JDBC4PreparedStatement@20ad9418: SELECT * FROM patient where patientName='夏颖' and password='123456'
登录成功
病人姓名:夏颖

测试 SQL 注入攻击 运行效果展示

请输入患者姓名:夏颖
请输入患者密码:100'OR'1'='1
com.mysql.jdbc.JDBC4PreparedStatement@20ad9418: SELECT * FROM patient where patientName='夏颖' and password='100\'OR\'1\'=\'1'
登录失败

8.4.4 PreparedStatement 的优势

  • 可读性高和可维护性高
  • SQL 语句的执行性能高
  • 安全性高
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值