Java MySQL-JDBC编程

文章目录

  • 初始JDBC
    • JDBC的工作原理
  • 初始Maven
    • Maven入门简介
    • 修改Maven的配置文件
    • 在idea中查看当前的maven使用
    • 在当前Maven工程中加载数据库驱动
  • DriverManager连接方案
    • 注册一个驱动
    • 创建一个连接
    • 获取一个操作SQL的对象
    • 创建SQL查询获取结果集
    • 遍历结果集输出结果
    • 关闭资源以及完整代码
  • DriverManager & Statement的弊端分析
    • DriverManger和DataSource的连接方式分析
    • Statement的弊端以及SQL注入现象
  • DataSource连接方案(PreparedStatement优化)
    • 连接到数据库
    • 创建一个连接
    • 获得预编译操作对象
    • 动态构建SQL语句
    • 收集结果并输出
    • 关闭资源以及完整代码
  • 化简方案代码总览

初始JDBC

首先我们的问题是, 什么是JDBC, JDBC的全称是(Java Data Connectivity, Java数据库连接) 是Java程序与数据库之间的桥梁, 包含了一套Java定义的用于执行SQL语句的接口, 使开发者能够编写数据库的程序. JDBC的主要作用是 : 与数据库建立连接, 发送SQL语句和处理数据库执行结果


其实JDBC就是一套Java提供的编程接口, 然后由不同的数据库厂商去实现这一套接口, 然后把实现好的一套类库打包成文件, 也就是jar包, 作为Java开发人员, 可能每个数据库对数据的操作都是不一样的(编解码), 但是我们并不需要关心内部的实现, 只需要面向接口编程就可以了, 这就提高了程序的扩展力, 降低了程序的耦合度, 这其实也就是接口在开发中最重要的作用, 当我们更换数据库的时候, 代码几乎不需要进行改动, 因为我们是面向接口进行编程的

在这里插入图片描述

JDBC的工作原理

JDBC的基本的工作原理就下面的几个步骤, 我们接下来的分析都是基于下面的基本步骤来处理的

  • 加载驱动 : 可以通过在数据库官网下载文件到本地使用, 也可以通过配置maven
  • 建立连接 : 可以通过DriverManager或者是DataSource来建立连接
  • 执行SQL : 通过静态的执行工具Statement, 或者是预编译的PreparedStatement来执行SQL
  • 处理结果 : 处理结果, 通过结果集收集结果然后收集迭代
  • 关闭资源 : 通过close()方法倒叙关闭开启的资源

初始Maven

Maven入门简介

Maven其实是一种基于项目对象模型的项目管理工具,可以对 Java 项目进行构建、依赖管理等操作, 其实简单点理解就是, 可以理解为一个云的应用商店, 如果没有maven的话, 我们配置JDBC也就需要下载各大服务器厂商的驱动Jar包到本地使用, 如果Jar包的内容过多就不是很方便, 但是通过Maven我们就不需要下载, 通过远程加载maven仓库中的依赖的方式直接使用Jar包, 更加便捷


修改Maven的配置文件

由于我们idea的自带的maven工具的远端仓库是在国外的, 由于国家防火墙等原因, 可能导致我们无法正常访问, 所以我们需要把maven工程的镜像配置到国内的阿里云上(阿里云上有一个原装maven仓库的镜像)


找到maven的默认位置
我们的idea自带的maven工具的位置是在idea安装目录的plugins里面
下面的图片是找到配置文件的完整路径
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意, 上面的setting.xml才是我们的配置文件的本体, 上面的带日期的那个是我们怕修改错误拷贝的副本, 然后在vscode中打开这个文件, 找到<mirrors></mirrors>镜像这个标签, 修改配置文件为下图
在这里插入图片描述
配置文件<mirrors></mirrors>配置到阿里云的代码, 注意一定按照上面的图片完整拷贝

<mirrors>
    <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>

至此, 我们的maven就成功修改为了国内镜像

在idea中查看当前的maven使用

在这里插入图片描述
在这里插入图片描述
可以看到我们现在的Maven home pathBundled(Maven3)也就是我们的默认节点

在当前Maven工程中加载数据库驱动

完成了上面的操作之后, 我们就可以进行下一步, 在当前的工程中使用远端的maven仓库依赖
创建一个maven工程如下图
在这里插入图片描述
打开当前maven项目的pom.xml的maven配置文件
在这里插入图片描述
上图是没有进行依赖配置的初始代码, 下面是源代码

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mysql_module</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

</project>

现在我们添加一个MySQL数据库连接依赖
首先创建一个<dependencies></dependencies>节点
在这里插入图片描述


获取MySQL驱动包
在下面这个网址中找到你所需要的maven依赖
https://mvnrepository.com, 搜索MySQL
在这里插入图片描述
第一个是最新的, 第二个是历史版本, 找到你所需要的即可
在这里插入图片描述
找到一个打开, 复制maven地址到idea配置文件里的<dependencies></dependencies>即可
在这里插入图片描述
复制内容源代码如下

	<!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.0.33</version>
        </dependency>

如果不报错就证明环境配置成功了, 依赖加载完毕, 配置成功

DriverManager连接方案

这个方案我们不太推荐使用, 因为这种连接的模式就是简单的物理连接, 连接一次直接就关闭不用了, 比较浪费资源


注册一个驱动

public static void main(String[] args) {

        try {
            // 1. 注册一个驱动(其实就是加载导入一个类, 异常我们捕获一下)
            Class.forName("com.mysql.cj.jdbc.Driver");
         
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

我们查看一下Driver就会发现, 里面有一个static代码块
在这里插入图片描述
也就是这个类在进行类加载的时候就会自动注册一个驱动


创建一个连接

利用刚才的DriverManager类创建一个连接即可, URL是链接码, 格式如下

  • jdbc:mysql://服务器地址:端⼝/数据库?参数名=值[&参数名=值]
  • “jdbc:mysql://127.0.0.1:3306/java113mysql?characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false”;
  • 可以修改的位置我们用加重标记了, 直接参照上面的格式即可

User就是用户名, Password是密码

public static void main(String[] args) {

        try {
            // 1. 注册一个驱动(其实就是加载导入一个类, 异常我们捕获一下)
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2. 创建一个连接(抛出异常捕获一下, URL是连接码, user是用户名, password是密码(不展示))
            String URL = "jdbc:mysql://127.0.0.1:3306/java113mysql?" +
                    "characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false";
            String user = "root";
            String password = "*****";//不予展示
            Connection connection = DriverManager.getConnection(URL, user, password);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

获取一个操作SQL的对象

可以获取一个静态的操作对象Statement(可能发生SQL注入)也可以使用预编译SQL处理对象PreparedStatement

public static void main(String[] args) {

        try {
            // 1. 注册一个驱动(其实就是加载导入一个类, 异常我们捕获一下)
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2. 创建一个连接(抛出异常捕获一下, URL是连接码, user是用户名, password是密码(不展示))
            String URL = "jdbc:mysql://127.0.0.1:3306/java113mysql?" +
                    "characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false";
            String user = "root";
            String password = "*****";//不予展示
            Connection connection = DriverManager.getConnection(URL, user, password);
            // 3. 获取一个操作SQL的对象, 可以是静态的Statement, 也可以是预编译PreparedStatement(需要传参, 等会再说)
            Statement statement = connection.createStatement();
            //PreparedStatement preparedStatement = connection.prepareStatement(参数);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

创建SQL查询获取结果集

这一步就没什么可说的了, 就是创建一个SQL语句获取一下结果集(我们这里是静态的获取)

public static void main(String[] args) {

        try {
            // 1. 注册一个驱动(其实就是加载导入一个类, 异常我们捕获一下)
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2. 创建一个连接(抛出异常捕获一下, URL是连接码, user是用户名, password是密码(不展示))
            String URL = "jdbc:mysql://127.0.0.1:3306/java113mysql?" +
                    "characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false";
            String user = "root";
            String password = "*****";//不予展示
            Connection connection = DriverManager.getConnection(URL, user, password);
            // 3. 获取一个操作SQL的对象, 可以是静态的Statement, 也可以是预编译PreparedStatement(需要传参, 等会再说)
            Statement statement = connection.createStatement();
            //PreparedStatement preparedStatement = connection.prepareStatement(参数);
            // 4. 定义一个SQL语句用来操作(不建议使用*因为要使用索引, DQL是excuteQuary, DML是excuteUpdate)
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入要查询的员工姓名:");
            String name = sc.nextLine();
            String sql = "select empno, ename, sal from emp where ename = '" + name + "'";
            ResultSet resultSet = statement.executeQuery(sql);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

遍历结果集输出结果

我们输出结果的方式其实是通过类似迭代器的方式的方式进行遍历

/**
 * 这个类主要就是测试DriverManager如何进行JDBC连接的
 */
public class Demo1_DriverManager {
    public static void main(String[] args) {

        try {
            // 1. 注册一个驱动(其实就是加载导入一个类, 异常我们捕获一下)
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2. 创建一个连接(抛出异常捕获一下, URL是连接码, user是用户名, password是密码(不展示))
            String URL = "jdbc:mysql://127.0.0.1:3306/java113mysql?" +
                    "characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false";
            String user = "root";
            String password = "*****";//不予展示
            Connection connection = DriverManager.getConnection(URL, user, password);
            // 3. 获取一个操作SQL的对象, 可以是静态的Statement, 也可以是预编译PreparedStatement(需要传参, 等会再说)
            Statement statement = connection.createStatement();
            //PreparedStatement preparedStatement = connection.prepareStatement(参数);
            // 4. 定义一个SQL语句用来操作(不建议使用*因为要使用索引, DQL是excuteQuary, DML是excuteUpdate)
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入要查询的员工姓名:");
            String name = sc.nextLine();
            String sql = "select empno, ename, sal from emp where ename = '" + name + "'";
            ResultSet resultSet = statement.executeQuery(sql);
            // 5. 遍历结果集收集结果(类似迭代器, 下标从1开始)
            while(resultSet.next()){
                int empno = resultSet.getInt(1);
                String ename = resultSet.getString(2);
                double sal = resultSet.getDouble(3);
                //输出一下结果(使用格式化风格)
                System.out.println(MessageFormat.format("员工编号={0}, 员工姓名={1}, 员工薪资={2}", empno, ename, sal));
            }
            // 6. 关闭资源在finally代码块(因为不管如何都会执行到finally)
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

关闭资源以及完整代码

我们需要在finally语句块中关闭资源, 因为不管怎样, finally语句块的内容都会执行到, 但是由于作用域的原因, 我们需要把变量的声明到try-catch块外部, 我们释放资源的方式是按照倒叙释放资源的模式
完整的执行代码如下

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

/**
 * 这个类主要就是测试DriverManager如何进行JDBC连接的
 */
public class Demo1_DriverManager {
    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. 创建一个连接(抛出异常捕获一下, URL是连接码, user是用户名, password是密码(不展示))
            String URL = "jdbc:mysql://127.0.0.1:3306/java113mysql?" +
                    "characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false";
            String user = "root";
            String password = "*****";//不予展示
            connection = DriverManager.getConnection(URL, user, password);
            // 3. 获取一个操作SQL的对象, 可以是静态的Statement, 也可以是预编译PreparedStatement(需要传参, 等会再说)
            statement = connection.createStatement();
            //PreparedStatement preparedStatement = connection.prepareStatement(参数);
            // 4. 定义一个SQL语句用来操作(不建议使用*因为要使用索引, DQL是excuteQuary, DML是excuteUpdate)
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入要查询的员工姓名:");
            String name = sc.nextLine();
            String sql = "select empno, ename, sal from emp where ename = '" + name + "'";
            resultSet = statement.executeQuery(sql);
            // 5. 遍历结果集收集结果(类似迭代器, 下标从1开始)
            while(resultSet.next()){
                int empno = resultSet.getInt(1);
                String ename = resultSet.getString(2);
                double sal = resultSet.getDouble(3);
                //输出一下结果(使用格式化风格)
                System.out.println(MessageFormat.format("员工编号={0}, 员工姓名={1}, 员工薪资={2}", empno, ename, sal));
            }
            // 6. 关闭资源在finally代码块(因为不管如何都会执行到finally)
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //在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();
                }
            }
        }
    }
}

执行结果如下
在这里插入图片描述

DriverManager & Statement的弊端分析

DriverManger和DataSource的连接方式分析

上面我们说到了, DriverManager是纯粹的物理连接, 就是连接一次close的时候就关闭, 这样实际上非常的浪费资源, 但是DataSource就完全不一样了, 这个是通过连接池的方式来节约资源, 需要连接的时候从池中拿一个现成的连接直接用, 用完了再放回去就可以了


所以我们在开发里一般都是用的DataSource, 包括一些框架封装的也是DataSource的连接方式

Statement的弊端以及SQL注入现象

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


由于我们的Statement是静态的操作SQL的方式就非常容易发生SQL注入现象
比如看下面的例子

// 我们在输入name的时候, 用输入下面的字符串
String name = "'or/**/1=1#";
String sql = "select empno, ename, sal from emp where ename = '" + name + "'";
// 这样我们字符串拼接之后就是下面的结果
select empno, ename, sql from emp where ename = ''or/**/1=1#';
// 看一下下面的执行结果

在这里插入图片描述
我们居然查出来了用户的信息, 这实际上是非常危险的, 所以为了避免SQL注入现象的发生, 我推荐使用PreparedStatement预编译的SQL处理对象


DataSource连接方案(PreparedStatement优化)

连接到数据库

首先通过MySQL厂商实现的MysqlDataSource进行连接, 连接完毕之后交给DataSource(JDBC层面)

/**
 * 这个类的作用就是测试DataSource是如何进行JDBC数据库连接的(并且使用PreparedStatement优化)
 */
public class Demo2_DataSource {
    public static void main(String[] args) {
        // 1. 首先还是连接数据库
        MysqlDataSource mysqlDataSource = new MysqlDataSource();
        mysqlDataSource.setURL("jdbc:mysql://127.0.0.1:3306/java113mysql?characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false");
        mysqlDataSource.setUser("root");
        mysqlDataSource.setPassword("*******");//不予展示
        // MysqlDataSource是MySQl厂商的实现, 我们Java程序员使用的JDBC层面的东西, 所以要再次交给JDBC
        DataSource dataSource = mysqlDataSource;
    }
}

创建一个连接

这个和上面的那个DriverManager其实是一样的

/**
 * 这个类的作用就是测试DataSource是如何进行JDBC数据库连接的(并且使用PreparedStatement优化)
 */
public class Demo2_DataSource {
    public static void main(String[] args) {
        try {
            // 1. 首先还是连接数据库
            MysqlDataSource mysqlDataSource = new MysqlDataSource();
            mysqlDataSource.setURL("jdbc:mysql://127.0.0.1:3306/java113mysql?characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false");
            mysqlDataSource.setUser("root");
            mysqlDataSource.setPassword("*******");//不予展示
            // MysqlDataSource是MySQl厂商的实现, 我们Java程序员使用的JDBC层面的东西, 所以要再次交给JDBC
            DataSource dataSource = mysqlDataSource;
            // 2. 建立一个连接
            Connection connection = dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

获得预编译操作对象

PreparedStatement构建的时候需要传入一个SQL语句进行预编译, 这也就是为什么说这叫预编译

public class Demo2_DataSource {
    public static void main(String[] args) {
        try {
            // 1. 首先还是连接数据库
            MysqlDataSource mysqlDataSource = new MysqlDataSource();
            mysqlDataSource.setURL("jdbc:mysql://127.0.0.1:3306/java113mysql?characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false");
            mysqlDataSource.setUser("root");
            mysqlDataSource.setPassword("*******");//不予展示
            // MysqlDataSource是MySQl厂商的实现, 我们Java程序员使用的JDBC层面的东西, 所以要再次交给JDBC
            DataSource dataSource = mysqlDataSource;
            // 2. 建立一个连接
            Connection connection = dataSource.getConnection();
            // 3. 获得预编译操作对象(并传入待编译的SQL语句, 不确定的用占位符?填充)
            String sql = "select empno, ename, sal from emp where ename = ?";
            PreparedStatement statement = connection.prepareStatement(sql);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}


为什么这个可以解决SQL注入
因为我们下文输入name的时候, 内部会直接把输入的字符串直接当作ename查找, 不会进行拼接

动态构建SQL语句

通过PreparedStatement中的方法动态构建查询语句(下标从1开始)

public class Demo2_DataSource {
    public static void main(String[] args) {
        try {
            // 1. 首先还是连接数据库
            MysqlDataSource mysqlDataSource = new MysqlDataSource();
            mysqlDataSource.setURL("jdbc:mysql://127.0.0.1:3306/java113mysql?characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false");
            mysqlDataSource.setUser("root");
            mysqlDataSource.setPassword("*******");//不予展示
            // MysqlDataSource是MySQl厂商的实现, 我们Java程序员使用的JDBC层面的东西, 所以要再次交给JDBC
            DataSource dataSource = mysqlDataSource;
            // 2. 建立一个连接
            Connection connection = dataSource.getConnection();
            // 3. 获得预编译操作对象(并传入待编译的SQL语句, 不确定的用占位符?填充)
            String sql = "select empno, ename, sal from emp where ename = ?";
            PreparedStatement statement = connection.prepareStatement(sql);
            // 4. 动态构建查询SQL语句(内容填充)
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入查询的员工姓名:");
            String name = sc.nextLine();
            statement.setString(1, name);
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

收集结果并输出

这个就和之前的完全一样了

public class Demo2_DataSource {
    public static void main(String[] args) {
        try {
            // 1. 首先还是连接数据库
            MysqlDataSource mysqlDataSource = new MysqlDataSource();
            mysqlDataSource.setURL("jdbc:mysql://127.0.0.1:3306/java113mysql?characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false");
            mysqlDataSource.setUser("root");
            mysqlDataSource.setPassword("*******");//不予展示
            // MysqlDataSource是MySQl厂商的实现, 我们Java程序员使用的JDBC层面的东西, 所以要再次交给JDBC
            DataSource dataSource = mysqlDataSource;
            // 2. 建立一个连接
            Connection connection = dataSource.getConnection();
            // 3. 获得预编译操作对象(并传入待编译的SQL语句, 不确定的用占位符?填充)
            String sql = "select empno, ename, sal from emp where ename = ?";
            PreparedStatement statement = connection.prepareStatement(sql);
            // 4. 动态构建查询SQL语句(内容填充)
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入查询的员工姓名:");
            String name = sc.nextLine();
            statement.setString(1, name);
            // 5. 执行结果接收结果集(这里的excuteQuery()是不传参的)
            ResultSet resultSet = statement.executeQuery();
            while(resultSet.next()){
                int empno = resultSet.getInt(1);
                String ename = resultSet.getString(2);
                double sal = resultSet.getDouble(3);
                System.out.println(MessageFormat.format("员工编号={0}, 员工姓名={1}. 员工薪资={2}", empno, ename, sal));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } 
    }
}

关闭资源以及完整代码

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;

/**
 * 这个类的作用就是测试DataSource是如何进行JDBC数据库连接的(并且使用PreparedStatement优化)
 */
public class Demo2_DataSource {
    public static void main(String[] args) {

        DataSource dataSource = null;
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            // 1. 首先还是连接数据库
            MysqlDataSource mysqlDataSource = new MysqlDataSource();
            mysqlDataSource.setURL("jdbc:mysql://127.0.0.1:3306/java113mysql?characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false");
            mysqlDataSource.setUser("root");
            mysqlDataSource.setPassword("*******");//不予展示
            // MysqlDataSource是MySQl厂商的实现, 我们Java程序员使用的JDBC层面的东西, 所以要再次交给JDBC
            dataSource = mysqlDataSource;
            // 2. 建立一个连接
            connection = dataSource.getConnection();
            // 3. 获得预编译操作对象(并传入待编译的SQL语句, 不确定的用占位符?填充)
            String sql = "select empno, ename, sal from emp where ename = ?";
            statement = connection.prepareStatement(sql);
            // 4. 动态构建查询SQL语句(内容填充)
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入查询的员工姓名:");
            String name = sc.nextLine();
            statement.setString(1, name);
            // 5. 执行结果接收结果集(这里的excuteQuery()是不传参的)
            resultSet = statement.executeQuery();
            while(resultSet.next()){
                int empno = resultSet.getInt(1);
                String ename = resultSet.getString(2);
                double sal = resultSet.getDouble(3);
                System.out.println(MessageFormat.format("员工编号={0}, 员工姓名={1}. 员工薪资={2}", empno, ename, sal));
            }
        } 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();
                }
            }
        }
    }
}

执行结果
在这里插入图片描述

化简方案代码总览

import com.mysql.cj.jdbc.MysqlDataSource;

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

/**
 * 我们尝试把之前的建立数据库连接的代码简化一下
 */
public class DataSourceLite {

    /**
     * 首先定义连接所需要的常量
     */
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/java113mysql?characterEncoding" +
            "=utf8&allowPublicKeyRetrieval=true&useSSL=false";

    private static final String USER = "root";

    //不予展示
    private static final String POSSWORD = "*******";

    private static DataSource dataSource;

    /**
     * 在进行类加载的时期就创建一个数据库连接
     */
    static {
        // 创建一个连接(用特定的值)
        MysqlDataSource mysqlDataSource = new MysqlDataSource();
        mysqlDataSource.setURL(URL);
        mysqlDataSource.setUser(USER);
        mysqlDataSource.setPassword(POSSWORD);
        // 赋值交给JDBC层面的接口
        dataSource = mysqlDataSource;
    }

    /**
     * 获取一个connection(直接把异常抛出来交给调用方处理)
     */
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }


    /**
     * 释放资源的方案(直接在这个方案内部捕获就行了, 没必要进行上抛
     */
    public static void free(Statement statement, Connection connection){
        if(statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

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

public class Test_DataSourceLite {
    public static void main(String[] args) {
        //由于作用域的问题, 我们的所有代码都需要在外部声明(try-catch)
        Connection connection = null;
        PreparedStatement statement = null;

        try {
            // 1. 直接获取一个connection连接
            connection = DataSourceLite.getConnection();
            // 2. 创造一个预编译的SQL处理器
            String sql = "insert into t_student values (?,?,?,?);";
            statement = connection.prepareStatement(sql);
            // 3. 提示用户输入查询的信息
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入插入的编号:");
            int stuNo = sc.nextInt();
            System.out.println("请输入插入的学生姓名:");
            String stuName = sc.next();
            System.out.println("请输入插入的年龄:");
            int stuAge = sc.nextInt();
            System.out.println("请输入插入的学校编号:");
            int schNo = sc.nextInt();
            // 4. 进行动态的信息填充
            statement.setInt(1, stuNo);
            statement.setString(2, stuName);
            statement.setInt(3, stuAge);
            statement.setInt(4, schNo);
            // 5. 进行excuteUpdate()并收集结果集(返回的是收到影响的行数)
            int affectRow = statement.executeUpdate();
            if(affectRow == 1){
                System.out.println("插入成功...");
            }else{
                System.out.println("插入失败...");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 6. 关闭释放资源
            DataSourceLite.free(statement, connection);
        }
    }
}

执行结果如下
在这里插入图片描述
查询一下现在数据库的记录
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/904639.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TCP全连接队列与 tcpdump 抓包

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;计算机网络高效通关之路 欢迎大家点赞收藏评论&#x1f60a; 目录 listen第二个参数详解 全连接队列与半连接队列半开放连接队列&#xff08;SYN队列&#xff09;全连接队列&#xff08;接受队列…

20241030在荣品PRO-RK3566开发板的适配Rockchip原厂的buildroot的时候配置DTS中的电源域

20241030在荣品PRO-RK3566开发板的适配Rockchip原厂的buildroot的时候配置DTS中的电源域 2024/10/30 17:38 请问 RK3566开发板上的 电源配置 和 DTS文件是如何对应的&#xff1f; 底板原理图 PRO-RK3566-B-20210329原理图.pdf vccio4-supply 是1.8V。 对不上呀&#xff1f; Z:…

【Java】数组的定义与使用

数组的定义与使用 1. 数组的基本概念1.1 为什么要使用数组1.2 什么是数组1.3 数组的创建及初始化1.3.1 数组的创建1.3.2 数组的初始化 1.4 数组的使用1.4.1 数组中元素访问1.4.2 遍历数组 2. 数组是引用类型2.1 初始JVM的内存分布2.2 基本类型变量与引用类型变量的区别2.3 再谈…

活动回顾丨艾体宝《开源软件供应链安全的最佳实践》线下研讨会圆满落幕!

10月&#xff0c;艾体宝联合Mend成功举办了一场主题为“开源软件供应链安全最佳实践”的研讨会。此次活动吸引了众多业内专家、技术领袖和企业代表参与&#xff0c;共同探讨在当今数字化转型浪潮中&#xff0c;企业如何应对开源软件供应链安全的挑战。会议围绕三大核心议题展开…

复现第一周24

1.[SWPUCTF 2021 新生赛]gift_F12 1&#xff09;打开题目 2&#xff09;看源码 3&#xff09;直接ctrl&#xff0b;f搜索flag 2.[SWPUCTF 2021 新生赛]nc签到 1&#xff09;开题 2&#xff09;下载附件用记事本打开 3&#xff09;打开kali使用nc连接代码 输入l\s命令绕过黑名…

如何写出爆款脚本,很多人都忽略了这一项——口语化

不是每次写的视频脚本都绞尽脑汁吗&#xff1f; 你让观众觉得在和你‘聊天’&#xff0c;可一开写就生长硬、平淡、没有吸引力&#xff1f; 其实&#xff0c;只要掌握一些口语化的写作技巧&#xff0c;剧本也能写得像聊天一样轻松自然&#xff0c;让观众从头尾看到&#xff0…

ubuntu 22.04网线连接无ip、网络设置无有线网界面(netplan修复)

目前遇到过树莓派和其他设备安装 ubuntu22.04&#xff0c; 使用有线网络一段时间&#xff08;可能有其他软件安装导致&#xff09;造成有线网络未启动无ip分配的问题。 1、动态分配 通过命令行启动dhcpclient实现 网络eth0存在异常&#xff0c;网口灯电源和信号灯均点亮&am…

Machine Learning on the Edge

安装 python3 网址&#xff1a;https://www.python.org/downloads/release/python-3120/ 打开命令行安装esptool包&#xff0c;pip install esptool 下载Node.js 网址&#xff1a;https://nodejs.org/en/download/prebuilt-installer

国产骄傲,华为自研编程语言,新式中文编程拒绝卡脖子

六大模块助力开发 10月30日&#xff0c;华为自研的通用编程语言——仓颉编程语言迎来了重要的里程碑时刻。其官方网站正式上线&#xff0c;并开放了首个公测版本的下载通道。这不仅标志着华为在编程语言领域的又一重大突破&#xff0c;也为开发者们带来了全新的编程选择与体验。…

qt QMainWindow详解

一、概述 QMainWindow继承自QWidget&#xff0c;并提供了一个预定义的布局&#xff0c;将窗口分成了菜单栏、工具栏、状态栏和中央部件区域。这些区域共同构成了一个功能丰富的主窗口&#xff0c;使得应用程序的开发更加简单和高效。 二、QMainWindow的常用组件及功能 菜单栏&…

VUE errolog, vue 错误集

I) installation As to command “npm install” on cmd or powershell, we must execute it under the program folder

Jenkins发布vue项目,版本不一致导致build错误

问题一 yarn.lock文件的存在导致在自动化的时候&#xff0c;频频失败问题二 仓库下载的资源与项目资源版本不一致 本地跑好久的一个项目&#xff0c;现在需要部署在Jenkins上面进行自动化打包部署&#xff1b;想着部署后今后可以省下好多时间&#xff0c;遂兴高采烈地去部署&am…

Laravel5 抓取第三方网站图片,存储到本地

背景 近期发现&#xff0c;网站上的部分图片无法显示&#xff0c; 分析发现&#xff0c;是因为引用的第三方网站图片&#xff08;第三方服务器证书已过期&#xff09; 想着以后显示的方便 直接抓取第三方服务器图片&#xff0c;转存到本地服务器 思路 1. 查询数据表&#xff0…

Linux特种文件系统--tmpfs文件系统前传:虚拟内存子系统

虚拟内存子系统是操作系统中的一个重要组成部分&#xff0c;它负责管理和优化计算机的内存使用。虚拟内存的概念允许操作系统为每一个进程创建一个虚拟地址空间&#xff0c;这个空间比实际物理内存要大得多。虚拟内存子系统通过将部分虚拟地址映射到物理内存&#xff0c;部分映…

【源码】Sharding-JDBC源码分析之Sql解析的原理

Sharding-JDBC系列 1、Sharding-JDBC分库分表的基本使用 2、Sharding-JDBC分库分表之SpringBoot分片策略 3、Sharding-JDBC分库分表之SpringBoot主从配置 4、SpringBoot集成Sharding-JDBC-5.3.0分库分表 5、SpringBoot集成Sharding-JDBC-5.3.0实现按月动态建表分表 6、【…

【ECMAScript标准】深入解析ES5:现代JavaScript的基石

&#x1f9d1;‍&#x1f4bc; 一名茫茫大海中沉浮的小小程序员&#x1f36c; &#x1f449; 你的一键四连 (关注 点赞收藏评论)是我更新的最大动力❤️&#xff01; &#x1f4d1; 目录 &#x1f53d; 前言1️⃣ ES5的概述2️⃣ ES5的关键特性3️⃣ ES5与之前版本的区别4️⃣ …

Unity(四十八):Unity与Web双向交互

效果 游戏对象绑定脚本 游戏脚本源码 using System.Collections; using System.Collections.Generic; using UnityEngine;public class Tent : MonoBehaviour {public Camera camera;// Start is called before the first frame updatevoid Start(){}// Update is called once…

CloudSat数据产品数据下载与处理 (matlab)

CloudSat数据下载 这个数据我之前和CALIPSO弄混了&#xff0c;后来发现它们虽然是同一个火箭上去&#xff0c;但是数据产品却在不同的平台下&#xff0c;CloudSat的数据更加关注云的特性&#xff0c;包括云覆盖、云水当量、云分类数据。 数据网址在&#xff1a;CloudSat网址 …

端侧大模型浪潮奔涌而至:态势、影响与建议

腾讯研究院大模型研究小分队出品 自苹果推出AI手机以来&#xff0c;端侧大模型的产品发布进入加速期。 10月10日&#xff0c;Vivo推出蓝心端侧大模型 3B&#xff0c;其AI能力已覆盖60多个国家和地区&#xff0c;服务超5亿手机用户&#xff0c;大模型token输出量超过3万亿&…

【jvm】为什么Xms和Xmx的值通常设置为相同的?

目录 1. 说明2. 避免性能开销3. 提升稳定性4. 简化配置5. 优化垃圾收集6. 获取参数6.1 代码示例6.2 结果示例 1. 说明 1.-Xms 和 -Xmx 参数分别用于设置堆内存的初始大小&#xff08;最小值&#xff09;和最大大小。2.在开发环境中&#xff0c;开发人员可能希望快速启动应用程…