JDBC编程

在这里插入图片描述

MySQL文章专栏 欢迎大家来学习交流!!!

1. 什么是JDBC?

JDBC(Java Database Connectivity,Java数据库连接)是Java程序和数据库之间的桥梁,包含了一整套Java定义的用于执行SQL语句的接口,使得开发者能够编写数据库程序。JDBC的主要作用是:与数据库建立连接、发送SQL语句和处理数据库执行结果。

2. 为什么要使用JDBC?

首先回顾一下正常使用客户端操作数据库的过程:

  • 连接数据库
  • 发送SQL语句
  • 得到返回结果并且显示
  • 关闭连接

同样使用JDBC操作数据库也需要按照上述步骤,不过需要编写相应代码去实现。由于不同数据库(MySQL、Oracle、SQL Server等)对同一个操作不论是协议还是参数都有各自不同,如果让程序员自己去实现,那就必须针对不同的数据库进行编码实现,这个工作量和维护成本也很大。

对于以上问题,Java采取的做法是针对以上操作步骤提供统一接口,但是具体实现交给数据库厂商去完成,程序员只需要按照需要去调用接口中定义的方法即可,这样无论使用什么样的数据库,对于Java程序没有任何影响,即便是换一个数据库,也只需要换一下相应厂商的依赖。

3. JDBC的使用

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

修改Maven配置文件 settings.xml
文件地址:IDEA安装目录\plugins\maven\lib\maven3\conf\settings.xml

打开上述文件,在 <mirrors></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节点 使用国内阿里云仓库镜像 结束 -->

最终结果:
在这里插入图片描述

3.2 获取MySQL驱动包

在Maven仓库中搜索MySQL,找到最新合适版本的驱动包。
在这里插入图片描述

3.3 在IDEA中修改 pom.xml 文件

在对应工程的 pom.xml 文件中的 <dependencies></dependencies> 标签中添加MySQL依赖。
在这里插入图片描述

3.4 编写JDBC执行语句

实现方案1:使用 DriverManager
package org.demoghr;

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

public class Demo1_DriverManger {
    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/ghr?characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false", "root", "25800852ghr");
            // 3. 创建Statement对象
            statement = connection.createStatement();
            // 4. 定义SQL语句
            String name1 = "孙权";
            int chinese1 = 70;
            String sql = "select id, name, chinese, math, english from exam where name = '" + name1 + "' and chinese = " + chinese1;
            // 5. 指定SQL语句
            resultSet = statement.executeQuery(sql);
            // 6. 遍历结果集,获取数据行
            while (resultSet.next()) {
                // 获取ID列的值
                long id = resultSet.getLong(1);
                // 获取name列的值
                String name = resultSet.getString(2);
                int chinese = resultSet.getInt(3);
                int math = resultSet.getInt(4);
                int english = resultSet.getInt(5);
                System.out.println(MessageFormat.format("学生编号={0}, 姓名={1}, 语文={2}, 数学={3}, 英语={4}", id, name, chinese, math, english));
            }
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            // 释放结果集对象
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            // 释放Statement对象
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            // 关闭数据库连接
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
实现方案2:使用 DataSource
package org.demoghr;

import com.mysql.cj.jdbc.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.*;
import java.text.MessageFormat;

public class Demo2_DataSource {
    public static void main(String[] args) {
        // 1. 定义数据源
        DataSource dataSource = null;
        // 2. 定义连接对象
        Connection connection = null;
        // 3. 定义预编译对象
        PreparedStatement preparedStatement = null;
        // 4. 定义结果集对象
        ResultSet resultSet = null;
        // 5. 设置数据源
        MysqlDataSource mysqlDataSource = new MysqlDataSource();
        mysqlDataSource.setURL("jdbc:mysql://127.0.0.1:3306/数据库(根据个人情况填写)?characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false");
        mysqlDataSource.setUser("用户名(根据个人情况填写)");
        mysqlDataSource.setPassword("密码(根据个人情况填写)");
        // 转换为JDBC数据源
        dataSource = mysqlDataSource;
        // 6. 获取连接
        try {
            connection = dataSource.getConnection();
            // 获取SQL语句
            preparedStatement = connection.prepareStatement("select id, name, chinese, math, english from exam where name = ?");
            // 用真实值替换占位符
            preparedStatement.setString(1, "猪悟能");
            // 将查询结果放入结果集
            resultSet = preparedStatement.executeQuery();
            // 处理结果集,由于这次查询的是一条记录,使用if即可
            if (resultSet.next()) {
                // 使用对应类型接受结果
                long id = resultSet.getLong("id");
                String name = resultSet.getString("name");
                int chinese = resultSet.getInt("chinese");
                int math = resultSet.getInt("math");
                int english = resultSet.getInt("english");
                // 打印结果
                System.out.println(MessageFormat.format("{0}, {1}, {2}, {3}, {4}", id, name, chinese, math, english));
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            // 关闭所有资源
            // 关闭结果集
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            // 关闭预编译对象
            if (preparedStatement != null) {
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            // 关闭数据库连接
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

4. JDBC常用接口类

4.1 DriverManagerDataSource

  • DriverManager 用于管理JDBC驱动程序,可以从驱动程序中获取数据库连接。
  • DataSourceDriverManager 的替代方案,是获取数据库连接的首要方法。

4.2 DriverManagerDataSource 的区别

主要区别体现在连接管理方式:

  • DriverManager 每次调用 getConnection 方法都会初始化一个新连接,使用完成后会关闭真实连接,导致资源浪费。
  • DataSource 使用连接池的技术,会在初始化时创建一定数量的数据库连接,这些连接可以重复使用,关闭时并不是真正关闭连接,而是将连接归还给连接池,以供后续使用,有效提高了资源利用率和性能。如果连接池的连接不够用,就会创建临时连接,当负载降低时,临时连接会销毁。

4.3 Connection 数据库连接

数据库连接(会话)对象,可以接受 getConnection 方法的值,一旦建立了Connection,就可以通过它来创建StatementPreparedStatement对象。这些对象用于执行SQL语句。

4.4 Statement 对象

用于执行静态SQL语句并返回执行结果。由于只能执行静态语句,所以如果一个语句中需要动态参数,那么只能通过字符串拼接的方式组装完成的SQL语句。例如:

String name1 = "孙权";
int chinese1 = 70;
String sql = "select id, name, chinese, math, english from exam " +
             "where name = '" + name1 + "' and chinese = " + chinese1;

注意:字符串拼接形式构造SQL语句时,如果不处理参数中的特殊字符就会造成SQL注入,这是一个非常严重的安全性问题。

4.5 SQL 注入

攻击者在管理员不知情的情况下实现非法操作,以此来欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。例如:

select id, name, chinese, math, english from exam where name = '' or 1 = 1;

4.6 PreparedStatement

预编译SQL语句对象,SQL语句被预编译并且存储在PreparedStatement对象中,可以多次使用该对象执行SQL语句,同时可以解决SQL注入问题。可以在SQL语句中设置占位符?,并且为动态参数设置真实值,从下标1开始。例如:

preparedStatement = connection.prepareStatement("select id, name, chinese, math, english from exam where name = ?");
preparedStatement.setString(1, "猪悟能");

4.7 executeQuery()

执行结果返回的是一个结果集,用于select操作。

4.8 executeUpdate()

执行结果返回的是一个整形,通常用于updateinsertdelete操作。

4.9 ResultSet 结果集

查询结果保存在其中。ResultSet对象维护了一个指向当前数据行的游标,最初游标位于第一行之前,调用next()方法将游标移动到下一行,当ResultSet中没有更多的数据行时返回false,所以可以用while循环来遍历结果集。例如:

while (resultSet.next()) {
    long id = resultSet.getLong("id");
    String name = resultSet.getString("name");
    int chinese = resultSet.getInt("chinese");
    int math = resultSet.getInt("math");
    int english = resultSet.getInt("english");
    System.out.println("学生编号=" + id + ", 姓名=" + name + ", 语文=" + chinese + ", 数学=" + math + ", 英语=" + english);
}

5. 模板整合

因为JDBC编程中出现了很多代码量很大但是又经常重复的数据,因此我们在这里做了一个类专门存放这些重复代码,并且提供统一接口供外界调用。

5.1 DBUtil

package org.demoghr;

import com.mysql.cj.jdbc.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.*;

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

    // 当类加载到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, PreparedStatement preparedStatement, Connection connection) {
        // 释放结果集
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        // 释放preparedStatement
        if (preparedStatement != null) {
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        // 关闭数据库连接
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

5.2 使用案例

package org.demoghr;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Demo3_DateSource {
    public static void main(String[] args) {
        // 1. 定义连接对象
        Connection connection = null;
        // 2. 定义预编译对象
        PreparedStatement preparedStatement = null;
        // 3. 增删改操作不涉及结果集
        // 4. 获取连接
        try {
            connection = DBUtil.getConnection();
            // 5. 接受SQL语句
            preparedStatement = connection.prepareStatement("update exam set chinese = 100 where name = ?");
            // 6. 真实值替换占位符
            preparedStatement.setString(1, "猪悟能");
            // 7. 执行SQL语句
            int ret = preparedStatement.executeUpdate();
            // 8. 判断是否执行成功
            if (ret == 1) {
                System.out.println("成功");
            } else {
                System.out.println("失败");
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            // 9. 释放所有资源
            DBUtil.close(null, preparedStatement, connection);
        }
    }
}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐