目录
1.前言
哈喽大家好吖,今天来给大家带来Java中的JDBC的讲解,之前学习的都是操作数据库的sql语言,那么我们如何通过程序来操作数据库呢?就是通过JDBC了,正文开始。
2.正文
2.1JDBC概念
JDBC是干什么的呢?
目的:使Java程序能够通过统一接口访问多种关系型数据库(如MySQL、Oracle、PostgreSQL等)。
核心思想:通过驱动(Driver)实现与具体数据库的解耦,开发者只需调用JDBC API,无需关心底层数据库差异。
访问数据库的常用流程:
- 确定数据库服务器的地址,端口号。(数据源)
- 建立连接,用户名,密码。(不同的数据库以哪种协议建立连接)(数据库连接)
- 发送要执行的SQL。(以什么样的形式发送,这里主要考虑编码的格式,即协议)(执行对象)
- 接收返回结果 (结果集,受影响的行数) 以哪种协议解析结果。 (结果集)
- 关闭连接。(释放资源,关闭连接)
JDBC是JAVA平台提供的接口,具体的实现是由数据库厂商去完成的。
2.2三种编码方式
在JDBC前记得先在maven中导入jar包:
Maven Repository: Search/Browse/Explorehttps://mvnrepository.com/pom文件是这样:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
测试的数据库代码我也在这里先提供给大家:
create database StudyRoom;
use StudyRoom;
-- 用户表
CREATE TABLE users (
user_id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
phone VARCHAR(20) UNIQUE NOT NULL,
email VARCHAR(100),
school VARCHAR(100),
points INT DEFAULT 0
);
INSERT INTO users values(01,'tom','12345','123456789','@123456789','HEDU',10)
正式开始:
2.2.1第一种
代码:
import java.sql.*;
import java.text.MessageFormat;
import java.util.Scanner;
public class jdbc1 {
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/studyroom?characterEncoding=utf8" +
"&allowPublicKeyRetrieval=true&useSSL=false", "root", "123456");
// 3. 创建Statement对象
statement = connection.createStatement();
// 4. 定义SQL并执行SQL语句
System.out.println("请输入学生编号:");
Scanner scanner = new Scanner(System.in);
// 接收用户的输入
int id = scanner.nextInt();
String sql = "select user_id, username, password, phone, email, school, points from users where user_id = '" + id + "'";
// 5. 执行SQL,获取查询结果
resultSet = statement.executeQuery(sql);
// 6. 对结果集进行遍历,获取数据
// 如果一下条有记录,返回true,没有则返回false
while (resultSet.next()) {
// 获取学生Id
long user_id = resultSet.getLong(1);
String username = resultSet.getString(2);
String password = resultSet.getString(3);
String phone = resultSet.getString(4);
String email = resultSet.getString(5);
String school = resultSet.getString(6);
long points= resultSet.getLong(7);
System.out.println(MessageFormat.format("学生编号={0}, 姓名={1}, 密码={2}, 手机号={3}, 邮箱={4}, 学校={5}, 点数={6}", user_id, username, password, phone
, email, school, points));
}
} 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();
}
}
}
}
}
核心思路讲解:
1.加载数据库驱动
使用
Class.forName("com.mysql.cj.jdbc.Driver")
加载 MySQL 数据库的 JDBC 驱动类,这是建立与 MySQL 数据库连接的必要步骤,让 Java 程序能够识别并使用 MySQL 的驱动来与数据库进行通信。2.获取数据库连接
通过
DriverManager.getConnection
方法,使用数据库的 URL(包括数据库的地址、端口、数据库名以及一些连接参数,如字符编码、是否允许公钥检索、是否使用 SSL 等)、用户名和密码来获取与数据库的连接,将返回的连接赋值给 connection 对象。3.创建 Statement 对象
调用 connection 对象的
createStatement
方法创建一个 Statement 对象,这个对象用于向数据库发送 SQL 语句并执行。4.定义 SQL 查询语句并执行
提示用户输入学生编号,并通过 Scanner 对象接收用户的输入。
根据用户输入的学生编号构建 SQL 查询语句,查询 users 表中对应学生编号的相关信息,包括 user_id、username、password、phone、email、school、points 等字段。
使用 statement 对象的
executeQuery
方法执行构建好的 SQL 查询语句,将查询结果存储在 resultSet 对象中。5.处理查询结果
使用 while 循环和 resultSet 对象的
next
方法遍历查询结果集,每次调用next
方法都会将结果集中的指针向下移动一行,如果还有数据则返回 true,否则返回 false。在循环体内,使用 resultSet 对象的 get 系列方法(如
getLong
、getString
等)根据字段的顺序或列名获取每一行数据中的各个字段值。使用 MessageFormat.format 方法将获取到的字段值按照指定的格式(包含占位符)组合成一个字符串,并输出到控制台,显示学生的所有相关信息。
6.关闭资源
在 finally 块中,依次判断 resultSet、statement、connection 对象是否不为 null,如果不为 null,则分别调用它们的 close 方法关闭这些资源,释放数据库连接和相关资源,这是非常重要的一步,避免了资源泄漏的问题。即使在执行过程中出现异常,finally 块中的代码也会被执行,确保资源被正确关闭。
2.2.2第二种(优化版)
代码:
import com.mysql.cj.jdbc.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.*;
import java.text.MessageFormat;
import java.util.Scanner;
public class jdbc2 {
public static void main(String[] args) {
// 定义MySQL数据源对象
MysqlDataSource mysqlDataSource = new MysqlDataSource();
// 设置数据库连接串
mysqlDataSource.setURL("jdbc:mysql://127.0.0.1:3306/studyroom?characterEncoding=utf8" +
"&allowPublicKeyRetrieval=true&useSSL=false");
// 用户名
mysqlDataSource.setUser("root");
// 密码
mysqlDataSource.setPassword("123456");
// 定义JDBC的数据源对象
DataSource dataSource = mysqlDataSource;
// 定义连接对象
Connection connection = null;
// 定义预处理SQL执行对象
PreparedStatement statement = null;
// 定义结果集对象
ResultSet resultSet = null;
try {
// 1. 通过数据源获取数据库连接
connection = dataSource.getConnection();
// 2. 获取预处理SQL执行对象
//输入
System.out.println("请输入学生编号:");
Scanner scanner = new Scanner(System.in);
int id = scanner.nextInt();
// 定义要执行的SQL
String sql = "select user_id, username, password, phone, email, school, points from users where user_id = ?";
statement = connection.prepareStatement(sql);
// 3. 用真实值替换占位符
statement.setInt(1, id);
// 4. 执行SQL,获取结果集
resultSet = statement.executeQuery();
// 5. 遍历结果集
while (resultSet.next()) {
// 获取学生Id
long user_id = resultSet.getLong(1);
String username = resultSet.getString(2);
String password = resultSet.getString(3);
String phone = resultSet.getString(4);
String email = resultSet.getString(5);
String school = resultSet.getString(6);
long points= resultSet.getLong(7);
System.out.println(MessageFormat.format("学生编号={0}, 姓名={1}, 密码={2}, 手机号={3}, 邮箱={4}, 学校={5}, 点数={6}", user_id, username, password, phone
, email, school, points));
}
} 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();
}
}
}
}
}
核心思路讲解:
1.配置数据库连接信息
创建
MysqlDataSource
对象,通过设置其 URL、用户名和密码来配置数据库连接信息,这种方式将连接信息集中管理,使得代码更加清晰和易于维护,方便后续对连接信息的修改。2.获取数据库连接
将配置好的
MysqlDataSource
对象赋值给DataSource
类型的变量 dataSource,然后通过 dataSource 的getConnection
方法获取数据库连接,这与直接使用DriverManager
获取连接相比,更符合 JDBC 的最佳实践,便于后续进行连接池等高级功能的集成。3.使用 PreparedStatement 执行 SQL 语句
定义 SQL 语句时使用了占位符 "?",然后通过
connection.prepareStatement(sql)
获取PreparedStatement
对象,这种方式可以有效防止 SQL 注入攻击,因为 PreparedStatement 会对参数进行预编译和转义处理。使用
statement.setInt(1, id)
将用户输入的学生编号设置到 SQL 语句的占位符位置,将参数与 SQL 语句分离,提高了代码的安全性和可读性。4.执行查询和处理结果
调用
statement.executeQuery()
执行查询操作,获取结果集。遍历结果集的方式与之前的代码类似,通过
resultSet.next()
移动指针并获取数据,然后使用MessageFormat.format
方法输出格式化后的学生信息。5.关闭资源
在 finally 块中关闭资源的逻辑与之前代码相同,确保无论是否出现异常,都会关闭 resultSet、statement 和 connection 对象,释放数据库资源。
相比第一种有哪些优化呢?
数据库连接管理 :之前的代码直接通过
DriverManager.getConnection
获取连接,而本代码使用了MysqlDataSource
数据源来配置和获取连接,这种方式更灵活,便于后续进行连接池等优化,提高了代码的可维护性和可扩展性。SQL 注入防护 :之前的代码通过字符串拼接构建 SQL 语句,容易受到 SQL 注入攻击,而本代码使用了
PreparedStatement
和参数占位符的方式,有效防止了 SQL 注入问题,增强了程序的安全性。代码可读性和可维护性 :通过将数据库连接信息集中配置在数据源中,以及使用 PreparedStatement 的参数设置方式,使得代码结构更加清晰,便于理解和后续的维护。
2.2.3第三种(更优化版)
我们发现,如果每一次尝试通过程序来操作数据库都要一次一次建立连接,代码会非常麻烦,于是我们引入连接池的概念,将连接数据库与释放资源的操作封装起来,这样就会非常方便。
代码结构:
DButil:
package utils;
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 DButil {
private static DataSource dataSource = null;
private static final String URL = "jdbc:mysql://127.0.0.1:3306/studyroom?characterEncoding=utf8" +
"&allowPublicKeyRetrieval=true&useSSL=false";
private static final String USER = "root";
private static final String PASSWORD = "123456";
static {
MysqlDataSource mysqlDataSource = new MysqlDataSource();
mysqlDataSource.setURL(URL);
mysqlDataSource.setUser(USER);
mysqlDataSource.setPassword(PASSWORD);
dataSource = mysqlDataSource;
}
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();
}
}
}
}
JDBC3:
package com.example.demo;
import utils.DButil;
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 jdbc3 {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DButil.getConnection();
String sql = "select user_id, username, password, phone, email, school, points from users where user_id = ?";
statement = connection.prepareStatement(sql);
Scanner scanner = new Scanner(System.in);
int id = scanner.nextInt();
statement.setInt(1,id);
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) {
// 获取学生Id
long user_id = resultSet.getLong(1);
String username = resultSet.getString(2);
String password = resultSet.getString(3);
String phone = resultSet.getString(4);
String email = resultSet.getString(5);
String school = resultSet.getString(6);
long points= resultSet.getLong(7);
System.out.println(MessageFormat.format("学生编号={0}, 姓名={1}, 密码={2}, 手机号={3}, 邮箱={4}, 学校={5}, 点数={6}", user_id, username, password, phone
, email, school, points));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DButil.close(null,statement,connection);
}
}
}
代码核心思路:
DButil
类(工具类)
功能 :
专门用于管理数据库连接和资源关闭的工具类,将数据库连接的获取和资源关闭的逻辑抽取出来,方便在多个地方复用,避免重复代码,提高代码的可维护性和复用性。
静态代码块初始化数据源 :
在类加载时,通过静态代码块创建并配置
MysqlDataSource
对象,设置数据库的 URL、用户名和密码,并将其赋值给dataSource
对象。这种方式确保数据源只初始化一次,提高了效率。私有构造方法 :
将构造方法私有化,防止外部创建该工具类的实例,因为工具类主要用于提供静态方法,不需要实例化。
获取数据库连接 :
提供
getConnection
静态方法,通过调用dataSource.getConnection()
向外提供数据库连接对象,方便其他类使用。关闭资源 :
提供
close
静态方法,接收ResultSet
、Statement
和Connection
对象作为参数,并依次判断它们是否不为 null,若不为 null 则关闭它们,释放资源。这样统一管理资源关闭逻辑,避免资源泄漏。
jdbc3
类(主程序类):
功能 :
使用
DButil
工具类获取数据库连接,并通过PreparedStatement
执行 SQL 查询语句,根据用户输入的学生编号查询学生信息并输出。获取数据库连接 :
调用
DButil.getConnection()
方法获取数据库连接,而不是像之前的代码直接在主程序中配置连接信息和创建连接,这样使得数据库连接的获取更加规范和集中管理。执行 SQL 查询 :
定义 SQL 语句时继续使用占位符 "?",并通过
connection.prepareStatement(sql)
获取PreparedStatement
对象,然后使用statement.setInt(1, id)
设置参数值,有效防止 SQL 注入,同时提高代码的可读性和安全性。处理查询结果和关闭资源 :
执行查询获取结果集后,遍历结果集并输出学生信息,这部分逻辑与之前的代码类似。
在 finally 块中调用
DButil.close
方法关闭资源,而不是像之前在主程序中手动关闭,简化了资源关闭的代码,减少了出错的可能性。
优化点:
代码复用和单一职责 :将数据库连接的获取和资源关闭的逻辑抽取到专门的
DButil
工具类中,遵循单一职责原则,使每个类的职责更加明确,提高了代码的复用性。在之前的代码中,这些逻辑都分散在主程序中,导致代码重复且不易维护。资源管理更规范 :通过工具类统一管理资源关闭,确保在任何情况下(即使出现异常)都能正确关闭资源,避免资源泄漏的问题。之前的代码虽然也有在 finally 块中关闭资源,但随着项目规模的扩大和复杂性的增加,这种方式容易出现遗漏或错误。
提高可维护性和可扩展性 :如果将来需要更改数据库连接信息或切换数据库类型,只需修改
DButil
类中的相关配置即可,而无需修改每个使用数据库连接的地方,大大提高了代码的可维护性和可扩展性。
运行截图:
3.小结
今天的分享到这里就结束了,喜欢的小伙伴点点赞点点关注,你的支持就是对我最大的鼓励,大家加油!