JDBC
Java Database Connectivity
1、Java 提供一套用于数据库操作的接口
2、不同数据库厂商针对 JDBC 提供不同实现,程序员只面向 JDBC 编程
3、统一、规范应用程序与数据库连接、执行 SQL 语句等操作
4、相关类在 java.sql 包、javax.sql 包中
JDBC 程序编写步骤
1、前置:项目导入 mysql-connector-java.jar 包
2、注册驱动:加载 Driver 类
3、获取连接:得到 Connection
4、执行增删改查:发送 SQL 语句到 MySQL 执行
5、释放资源:关闭相关链接
连接数据库的五种方式
1、直接使用 com.mysql.jdbc.Driver,属于静态加载,灵活性差,依赖性强
import com.mysql.jdbc.Driver;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class Program {
public static void main(String[] args) throws SQLException {
//注册驱动,获取 Driver 对象
Driver driver = new Driver();
/*
得到连接,本质是 socket 连接
jdbc:mysql:// 是规定的协议,通过 JDBC 连接 MySQL 服务
localhost 代表本地主机,也可以填写 IP 地址
3306 是 MySQL 服务监听的端口
db_name 是 MySQL DBMS 所连接的数据库
*/
String url = "jdbc:mysql://localhost:3306/db_name";
//使用 Properties 对象储存用户名、密码
Properties properties = new Properties();
//user、password 是规定格式,用户名、密码根据情况填写
properties.setProperty("user", "用户名");
properties.setProperty("password", "密码");
//根据 url、properties 连接数据库,得到 Connection,获取连接
Connection connection = driver.connect(url, properties);
//指定 SQL 语句
String sql = "";
//preparedStatement 预处理 SQL 语句,避免 SQL 注入,减少编译次数,提高效率
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.execute(sql);
//释放资源
preparedStatement.close();
connection.close();
}
}
2、使用反射动态加载,更灵活,减少依赖性
import com.mysql.jdbc.Driver;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class Program {
public static void main(String[] args) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException {
//通过反射加载 Driver 类
Class<?> cls = Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) cls.newInstance();
/*
得到连接,本质是 socket 连接
jdbc:mysql:// 是规定的协议,通过 JDBC 连接 MySQL 服务
localhost 代表本地主机,也可以填写 IP 地址
3306 是 MySQL 服务监听的端口
db_name 是 MySQL DBMS 所连接的数据库
*/
String url = "jdbc:mysql://localhost:3306/db_name";
//使用 Properties 对象储存用户名、密码
Properties properties = new Properties();
//user、password 是规定格式,用户名、密码根据情况填写
properties.setProperty("user", "用户名");
properties.setProperty("password", "密码");
//根据 url、properties 连接数据库,得到 Connection,获取连接
Connection connection = driver.connect(url, properties);
//指定 SQL 语句
String sql = "";
//preparedStatement 预处理 SQL 语句,避免 SQL 注入,减少编译次数,提高效率
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.execute(sql);
//释放资源
preparedStatement.close();
connection.close();
}
}
3、使用 DriverManager 代替 Driver,进行统一管理,拓展性更好
import com.mysql.jdbc.Driver;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Program {
public static void main(String[] args) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException {
//通过反射加载 Driver 类
Class<?> cls = Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) cls.newInstance();
/*
得到连接,本质是 socket 连接
jdbc:mysql:// 是规定的协议,通过 JDBC 连接 MySQL 服务
localhost 代表本地主机,也可以填写 IP 地址
3306 是 MySQL 服务监听的端口
db_name 是 MySQL DBMS 所连接的数据库
*/
String url = "jdbc:mysql://localhost:3306/db_name";
//user、password 是规定格式,用户名、密码根据情况填写
String user = "用户名";
String password = "密码";
//注册 Driver 驱动
DriverManager.registerDriver(driver);
//根据 url、user、password 连接数据库,得到 Connection,获取连接
Connection connection = DriverManager.getConnection(url, user, password);
//指定 SQL 语句
String sql = "";
//preparedStatement 预处理 SQL 语句,避免 SQL 注入,减少编译次数,提高效率
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.execute(sql);
//释放资源
preparedStatement.close();
connection.close();
}
}
4、(建议)使用 Class.forName() 自动完成注册驱动,简化代码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Program {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
//通过反射加载 Driver 类
Class.forName("com.mysql.jdbc.Driver");
/*
得到连接,本质是 socket 连接
jdbc:mysql:// 是规定的协议,通过 JDBC 连接 MySQL 服务
localhost 代表本地主机,也可以填写 IP 地址
3306 是 MySQL 服务监听的端口
db_name 是 MySQL DBMS 所连接的数据库
*/
String url = "jdbc:mysql://localhost:3306/db_name";
String user = "用户名";
String password = "密码";
//根据 url、user、password 连接数据库,得到 Connection,获取连接
Connection connection = DriverManager.getConnection(url, user, password);
//指定 SQL 语句
String sql = "";
//preparedStatement 预处理 SQL 语句,避免 SQL 注入,减少编译次数,提高效率
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.execute(sql);
//释放资源
preparedStatement.close();
connection.close();
}
}
(1)Driver 类中 static 代码块
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.mysql.cj.jdbc;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
(2)5.1.6 驱动版本之后不需要 Class.forName("com.mysql.jdbc.Driver");
(3)JDK 1.5 之后使用 JDBC4,不需要显示调用 Class.forName("com.mysql.jdbc.Driver"); 注册驱动,会自动调用驱动 .jar 包下 META-INF\services\java.sql.Driver 文本中的类名称,自动完成注册
com.mysql.cj.jdbc.Driver
5、(建议)在方式 4 的基础上,使用 Properties 文件改进,更灵活
(1)Properties 配置文件
user=用户名
password=密码
url=jdbc:mysql://localhost:3306/db_name
driver=com.mysql.jdbc.Driver
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class Program {
public static void main(String[] args) throws SQLException, IOException, ClassNotFoundException {
Properties properties = new Properties();
//假设存放路径为 src\mysql.properties
properties.load(new FileInputStream("src\\mysql.properties"));
/*
得到连接,本质是 socket 连接
jdbc:mysql:// 是规定的协议,通过 JDBC 连接 MySQL 服务
localhost 代表本地主机,也可以填写 IP 地址
3306 是 MySQL 服务监听的端口
db_name 是 MySQL DBMS 所连接的数据库
*/
String url = properties.getProperty("url");
String user =properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
//可省略
Class.forName(driver);
//根据 url、user、password 连接数据库,得到 Connection,获取连接
Connection connection = DriverManager.getConnection(url, user, password);
//指定 SQL 语句
String sql = "";
//preparedStatement 预处理 SQL 语句,避免 SQL 注入,减少编译次数,提高效率
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.execute(sql);
//释放资源
preparedStatement.close();
connection.close();
}
}
ResultSet 接口
1、表示数据库结果集的数据表,通常由执行查询数据库的语句生成
2、ResultSet 对象
(1)编译类型:ResultSet,运行类型:JDBC42ResultSet
(2)保持一个光标指向当前数据行
(3)ResultSet 光标最初位于第一行之前,第一次调用 next 使第一行成为当前行,第二次调用 next 使第二行成为当前行,依此类推
(4)在 ResultSet 对象中没有更多行时,返回 false,因此可以在 while 循环中遍历结果集
Statement(不使用)
1、Statement 对象用于执行静态 SQL 语句,并返回其生成结果的对象
2、连接建立后,对数据库访问,执行命名或 SQL 语句,通过以下对象执行
(1)Statement:存在 SQL 注入风险
(2)PreparedStatement:预处理
(3)CallableStatement:存储过程
3、SQL 注入:利用系统没有对用户输入数据进行充分检查,其中含非法 SQL 命令或语句段,恶意攻击数据库
PreparedStatement
1、执行 SQL 语句中的参数 ?(相当于占位符)表示,调用 setXxx 方法设置参数
2、不使用 + 拼接语句,减少语法错误,解决 SQL 注入,减少编译次数,效率高
3、Connection 对象创建 PreparedStatement 对象时,传入 SQL 进行预处理
4、调用 execute 等方法,不需要传入 SQL 语句,除非 SQL 不含 ?,则可以传入 SQL 语句
5、把参数中的特殊字符进行转义处理,避免 SQL 注入
JDBC API
1、DriverManager 驱动管理类
(1)注册驱动
public static synchronized void registerDriver(java.sql.Driver driver) throws SQLException
public static synchronized void registerDriver(java.sql.Driver driver, DriverAction da) throws SQLException
(2)获取连接
public static Connection getConnection(String url, java.util.Properties info) throws SQLException
public static Connection getConnection(String url, String user, String password) throws SQLException
public static Connection getConnection(String url) throws SQLException
2、Connection 接口
(1)创建 Statement 对象(不使用)
(2)创建预处理对象
PreparedStatement prepareStatement(String sql) throws SQLException;
PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException;
PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException;
PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException;
PreparedStatement prepareStatement(String sql, int columnIndexes[]) throws SQLException;
PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException;
3、PreparedStatement 接口
(1)执行在 PreparedStatement对象中的 SQL 语句,它必须是一个 DML 语句,或不返回任何内容的 SQL 语句,如 DDL 语句,DML 语句所影响的行总数,或不返回内容的 SQL 语句:0
int executeUpdate() throws SQLException;
(2)当返回的行数可能超过 Integer.MAX_VALUE 时,应使用此方法
default long executeLargeUpdate() throws SQLException
(3)执行此 PreparedStatement 对象中的 SQL 查询,并返回查询 PreparedStatement 的 ResultSet 对象
ResultSet executeQuery() throws SQLException;
(4)执行此 PreparedStatement 对象中的 SQL 语句,可能是任何类型的 SQL 语句,如果第一个结果是一个ResultSet对象,则返回 false;如果第一个结果是更新计数或没有结果,则返回 true
boolean execute() throws SQLException;
(4)大量 setXxx(int parameterIndex, Xxx x) 方法,第一个参数:SQL 语句中 ? 的索引(从 1 开始),第二个参数:设置 SQL 语句,在 parameterIndex 位置填充参数
4、ResultSet 接口(结果集)
(1)光标向下移动一行,ResultSet 光标最初位于第一行之前,第一次调用 next 使第一行成为当前行,依此类推,若下一行不存在,返回 false
boolean next() throws SQLException;
(2)光标向上移动一行,当光标位于第一行之前,返回 false
boolean previous() throws SQLException;
(3)大量 getXxx 方法,以 Xxx 类型接收该行某列的值,若传入 int 表示列的索引(从 1 开始),若传入 String 表示列名
JDBCUtils:封装 JDBC 操作
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils {
private static String user;
private static String password;
private static String url;
private static String driver;
static {
try {
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
user = properties.getProperty("user");
password = properties.getProperty("password");
url = properties.getProperty("url");
driver = properties.getProperty("driver");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//连接数据库,获取 Connection 对象
public static Connection getConnection() {
try {
return DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//关闭相关资源
public static void close(ResultSet resultSet, PreparedStatement preparedStatement, Connection connection) {
try {
if (resultSet != null) {
resultSet.close();
}
if (preparedStatement != null) {
preparedStatement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
事务
1、JDBC 程序中当创建一个 Connection 对象时,默认自动提交事务,所有 SQL 语句将作为单个事务执行并提交
(1)对于 DML 语句和 DDL 语句,语句在执行完成后立即完成
(2)对于 SELECT 语句,当关联的结果集关闭时,该语句将完成
(3)对于 CallableStatement 对象或返回多个结果的语句,当所有关联的结果集都已关闭并且已检索到所有更新计数和输出参数时,该语句将完成
3、Connection 事务相关方法
(1)将此连接的自动提交模式设置为给定状态,true 启用自动提交模式,false 禁用自动提交模式
void setAutoCommit(boolean autoCommit) throws SQLException;
(2)在当前事务中创建一个未命名的保存点,并返回代表它的新的 Savepoint 对象,如果 setSavepoint 在活动事务之外被调用,那么将在这个新创建的保存点处启动一个事务
Savepoint setSavepoint() throws SQLException;
(3)在当前事务中创建具有给定名称的保存点,并返回代表它的新的 Savepoint 对象,如果 setSavepoint 在活动事务之外被调用,那么将在这个新创建的保存点处启动一个事务
Savepoint setSavepoint(String name) throws SQLException;
(4)撤销在当前事务中所做的所有更改,并释放此 Connection 对象当前持有的任何数据库锁,只有当自动提交模式被禁用时,才应该使用此方法
void rollback() throws SQLException;
(5)撤消在给定的 Savepoint 对象设置后进行的所有更改,只有当自动提交被禁用时,才应该使用此方法
void rollback(Savepoint savepoint) throws SQLException;
(6)使上次提交 / 回滚之后所做的所有更改都将永久性,并释放此 Connection 对象当前持有的任何数据库锁,只有当自动提交模式被禁用时,才应该使用此方法
void commit() throws SQLException;
批处理
1、成批插入 / 更新记录,一次性提交多条 SQL 语句
2、PreparedStatemrnt 批处理相关方法,除 addBatch,其余继承 Statement 接口的方法
(1)向此 PreparedStatement 对象添加一组批量处理的 SQL 语句或参数
void addBatch() throws SQLException;
(2)将一批命令提交到数据库以执行,并且所有命令都执行成功,返回一个更新计数的数组,返回的数组的 int 元素被排序以对应于批次中的命令,这些命令根据它们添加到批处理的顺序进行排序
int[] executeBatch() throws SQLException;
(3)当返回的行数可能超过 Integer.MAX_VALUE 时,应使用此方法
default long[] executeLargeBatch() throws SQLException
(4)清空该 Statement 对象当前的 SQL 命令列表
void clearBatch() throws SQLException
3、PreparedStatemrnt 与 批处理搭配,既减少编译次数,又减少运行次数
4、JDBC 连接 MySQL 时,若使用批处理功能,需要在 url 末尾添加参数 ?rewriteBatchedStatements=true
url=jdbc:mysql://localhost:3306/db_name?rewriteBatchedStatements=true
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战