[MySQL] JDBC

1.JDBC 的简介

JDBC (Java Data Base Connectivity,Java数据库连接)是 Java 程序和数据库之间的桥梁 , 包含了一套 Java 定义于执行 SQL 语句的接口 , 使开发者能够编写数据库的程序

JDBC 的主要作用 : 与数据库建立连接 , 发送 SQL 语句 , 处理数据库执行结果

JDBC 工作原理 : 加载驱动 , 建立连接 , 创建 Statement , 执行 SQL , 处理结果 , 关闭资源

2.为什么使用 JDBC

创建客户端操作数据库的过程 :

  1. 确定连接地址 , 添加端口号(数据源)
  2. 连接到数据库服务(数据库连接)
  3. 发送 SQL 语句(执行对象)
  4. 得到返回结果集并显示(结果集)
  5. 关闭连接(释放资源)

Java 采取的做法是把上述操作步骤定义了相应的接口 , 具体实现交给数据库厂商去做 , Java 程序员只需按照需要调用接口中的定义方法即可 , 这样不论使用什么数据库 , 都对 Java 程序没有任何影响 , 即使换一个数据库 , 也只需要换一下相应厂商的是是实现依赖

JDBC 使用过程可以概括为 : 加载数据库厂商的驱动包 , 建立连接 , 创建 Statement , 执行 SQL , 处理结果释放资源 , 关闭连接

3.使用 JDBC

3.1 创建 Maven 工程并配置国内镜像

  • 修改 Maven 配置文件 , 在<mirrors></mirrors>标签中替换为以下代码
java 复制代码
<mirrors>

    <!-- mirror

     | Specifies a repository mirror site to use instead of a given repository. The repository that

     | this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used

     | for inheritance and direct lookup purposes, and must be unique across the set of mirrors.

     |

    -->

    <!-- 加入如下mirror节点 使用国内阿里云仓库镜像  开始 -->

    <mirror>

        <id>aliyunmaven</id>

        <mirrorOf>*</mirrorOf>

        <name>阿里云公共仓库</name>

        <url>https://maven.aliyun.com/repository/public</url>

    </mirror>

    <mirror>

        <id>central</id>

        <mirrorOf>*</mirrorOf>

        <name>aliyun central</name>

        <url>https://maven.aliyun.com/repository/central</url>

    </mirror>

    <mirror>

        <id>spring</id>

        <mirrorOf>*</mirrorOf>

        <name>aliyun spring</name>

        <url>https://maven.aliyun.com/repository/spring</url>

    </mirror>

    <!-- 加入如下mirror节点 使用国内阿里云仓库镜像  结束-->

</mirrors>
  • IDEA 中 Maven 的配置文件夹 : IDEA 安装目录/plugins/maven/lib/maven3/conf/settings.xml

3.2 获取 MySQL 的驱动包

mvnrepository.com 下搜索 MySQL , 找到最新的驱动包

3.3 修改 pom.xml 文件

在 maven 工程中的 pom.xml 中的**<dependencies></denpendencies>**标签中添加 MySQL 依赖

如图所示:

4.创建工程

java 复制代码
import java.sql.*;
import java.text.MessageFormat;
import java.util.Scanner;

public class test1 {
    public static void main(String[] args) {
        //分离出来方便关闭资源
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            // 1. 加载数据库厂商提供的驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2. 获取数据库连接
            connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bit_1027?characterEncoding=utf8" +
                                                     "&allowPublicKeyRetrieval=true&useSSL=false","root","119856");
            // 3. 创建 statement对象
            statement = connection.createStatement();
            // 4. 定义SQL并执行SQL语句
            System.out.println("请输入学生姓名");
            Scanner scanner = new Scanner(System.in);
            //接收用户输入
            String name = scanner.next();
            String sql = "select id,name,gender ,age,class_id from students where name = '"+name+"'";
            // 5. 执行SQL, 获取查询结果集
            resultSet = statement.executeQuery(sql);
            // 6. 对结果集进行遍历 , 获取数据
            while(resultSet.next()){
                int id = resultSet.getInt(1);
                String stuname = resultSet.getString(2);
                String stugender = resultSet.getString(3);
                int age = resultSet.getInt(4);
                int class_id = resultSet.getInt(5);
                System.out.println(MessageFormat.format("学生编号 = {0} , 学生姓名 = {1} , 性别 = {2} , 年龄 = {3}  , 班级编号 = {4}",id,stuname,stugender,age,class_id));
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        finally {
            // 依次从下往上释放资源,关闭连接
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

目标数据库 :


① 建立数据库连接


② 创建 Statement


④ 执行 SQL 语句

  • 执行 select 查询时返回的是一个结果集 , 用 ResultSet 接收
  • 执行 nsert , update , delete 操作时 , 返回的是受影响的行数 , 用 int 类型接收
  • executeQuery() , 执行返回的是一个结果集 , 通常用于 select 操作
  • executeUpdate() , 执行结果是一个整型 , 通常用于 insert , update , delete 操作

⑤ 处理结果集

  • 如果返回的是一个结果集 , 则需要遍历这个集合获取对应列的值

⑥ 释放资源

  • 在整个数据库访问的过程中的对象都需要释放 , 包括 : ResultSet,Statement和Connection, 后创建的先释放

5. 优化 1

1.SQL 注入

SQL注⼊即是指web应⽤程序对⽤⼾输⼊数据的合法性没有判断或过滤不严,攻击者可以在web应 ⽤程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现⾮法操 作,以此来实现欺骗数据库服务器执⾏⾮授权的任意查询,从⽽进⼀步得到相应的数据信息

示例 : 将 正常的条件值替换为

java 复制代码
'or/**/1=1;# 
  • 此操作仅用于理解 SQL 注入的危害,实际开发中必须使用 PreparedStatement****参数化查询 (如之前建议的代码修改),从根源上杜绝注入风险。
  • 未经授权对系统进行注入测试属于违法行为,务必遵守法律法规和道德规范。

解决方案

使用 PreparedStatement 预编译 SQL 语句对象 , 实现参数化查询 , 杜绝 SQL 注入分享 , 符合企业级开发规范

通过 Connection 对象获取到 PreparedStatement 对象 , 需要传入 SQL 模板 , 动态参数用占位符 ? 表示

2.如果要执行别的 SQL 语句需要重复打开客户端

使用 DriverManager 每次调用 getConnection 方法都会初始化一个新的连接 , 使用完后会关闭真实连接 , 导致资源浪费

解决方案

使用 DataSource 连接池技术 , 会在初始化时 创建一定数量的数据库连接 , 这些连接可以重复使用 , 关闭时并不是真正关闭 , 而是将连接归还给连接池 , 以供后续使用 , 有效提高资源利用率和性能

java 复制代码
import com.mysql.cj.jdbc.MysqlDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.Scanner;

public class test2 {
    public static void main(String[] args) {
        //定义MySQL数据源对象
        MysqlDataSource mysqlDataSource = new MysqlDataSource();
        //设置数据库连接串
        mysqlDataSource.setURL("jdbc:mysql://127.0.0.1:3306/bit_1027?characterEncoding=utf8" +
                               "&allowPublicKeyRetrieval=true&useSSL=false");
        //用户名
        mysqlDataSource.setUser("root");
        //密码
        mysqlDataSource.setPassword("119856");

        //定义JDBC的数据源对象
        DataSource dataSource = mysqlDataSource;

        //定义连接对象
        Connection connection = null;
        //定义预处理SQL执行对象
        PreparedStatement statement = null;
        //定义结果集对象
        ResultSet resultSet = null;
        try {
            // 1.通过数据源获取数据库连接
            connection = dataSource.getConnection();
            // 2.获取预处理SQL执行对象
            //定义要执行的SQL
            String sql = "select id,name,gender ,age,class_id from students where name = ?";
            statement = connection.prepareStatement(sql);
            //接收用户输入
            System.out.println("请输入学生姓名");
            Scanner scanner = new Scanner(System.in);
            String name = scanner.next();
            // 3.用真实姓名替代占位符
            statement.setString(1,name);
            // 4.执行SQL ,获取结果集
            resultSet = statement.executeQuery();
            //遍历结果集
            while(resultSet.next()){
                int id = resultSet.getInt(1);
                String stuname = resultSet.getString(2);
                String stugender = resultSet.getString(3);
                int age = resultSet.getInt(4);
                int class_id = resultSet.getInt(5);
                System.out.println(MessageFormat.format("学生编号 = {0} , 学生姓名 = {1} , 性别 = {2} , 年龄 = {3}  , 班级编号 = {4}",id,stuname,stugender,age,class_id));
            }
            //            while(resultSet.next()){
            //                int id = resultSet.getInt("id");
            //                String stuname = resultSet.getString("name");
            //                String stugender = resultSet.getString("gender");
            //                int age = resultSet.getInt("age");
            //                int class_id = resultSet.getInt("class_id");
            //                // 打印逻辑不变
            //            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        finally {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection .close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

6. 优化 2

1. 封装

将 获取数据库连接 和 释放资源,关闭连接 等 , 封装起来

java 复制代码
package util;

import com.mysql.cj.jdbc.MysqlDataSource;
import com.mysql.cj.xdevapi.Collection;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class DBUtil {
    //数据源
    private static DataSource dataSource = null;
    //数据库连接对象
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/bit_1027?characterEncoding=utf8" +
    "&allowPublicKeyRetrieval=true&useSSL=false";
    //用户名
    private static final String USER = "root";
    //密码
    private static final String PASSWORD = "119856";

    //当类加载到JVM时 , 执行数据源的初始化
    static {
        MysqlDataSource mysqlDataSource = new MysqlDataSource();
        mysqlDataSource.setURL(URL);
        mysqlDataSource.setUser(USER);
        mysqlDataSource.setPassword(PASSWORD);
        dataSource = mysqlDataSource;
    }

    //构造方法私有化 ,防止new这个对象
    private DBUtil() {
    }

    //获取数据库连接
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    //释放资源 , 关闭连接
    public static void close(ResultSet resultSet, Statement statement, Connection connection) {
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

示例 : 执行一条插入语句

java 复制代码
import util.DBUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;

public class insertTest1 {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement statement= null;
        //插入语句不需要定义结果集 (insert返回的是受影响的行数)
        try {
            // 1.获取数据库连接
            connection = DBUtil.getConnection();
            // 2.定义SQL语句
            String sql = "insert into students(name,gender,age,class_id) values (?,?,?,?);";
            // 3.定义SQL预处理对象
            statement = connection.prepareStatement(sql);
            // 4.接收用户参数
            System.out.println("请输入姓名");
            Scanner scanner = new Scanner(System.in);
            String name = scanner.next();

            System.out.println("请输入性别");
            String gender = scanner.next();

            System.out.println("请输入年龄");
            Integer age = Integer.valueOf(scanner.next());

            System.out.println("请输入班级");
            Integer class_id = Integer.valueOf(scanner.next());

            // 5.用真实数据填充占位符
            statement.setString(1,name);
            statement.setString(2,gender);
            statement.setInt(3,age);
            statement.setInt(4,class_id);

            // 执行插入操作并获取受影响行数
            int rows = statement.executeUpdate();
            System.out.println("插入成功,受影响行数:" + rows);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        finally {
            //释放资源,关闭连接
            DBUtil.close(null,statement,connection);
        }
    }
}
相关推荐
千里马学框架19 小时前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台19 小时前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone19 小时前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc20 小时前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo1 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077001 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone1 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen1 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone1 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui