跳到主要内容

JDBC

概念

JDBC (Java Database Connection) 是Java数据库连接技术的简称,提供连接数据库的能力。

JDBC API

Java 作为目前世界上最流行的高级开发语言,当然不可能考虑去实现各种数据库的连接与操作。但 Java 语言的开发者对数据库的连接与操作提供了相关的接口,供各大数据库厂商去实现。这些接口位于java.sql包中。

Driver

java.sql.Driver: 数据库厂商提供的JDBC驱动包中必须包含该接口的实现,该接口中就包含连接数据库的功能。

// 根据给定的数据库url地址连接数据库
// info 即账号, 密码等信息
Connection connect(String url, java.util.Properties info) throws SQLException;
java

DriverManager

java.sql.DriverManager: 数据库厂商的提供的JDBC驱动交给DriverManager来管理,DriverManager主要负责获取数据库连接对象Connection

// 通过给定的账号、密码和数据库地址获取一个连接
public static Connection getConnection(String url, String user, String password) throws SQLException
java

Connection

java.sql.Connection: 连接接口,数据库厂商提供的JDBC驱动包中必须包含该接口的实现,该接口主要提供与数据库的交互功能

// 创建一个SQL语句执行对象
Statement createStatement() throws SQLException;
// 创建一个预处理SQL语句执行对象
PreparedStatement prepareStatement(String sql) throws SQLException;
// 创建一个存储过程SQL语句执行对象
CallableStatement prepareCall(String sql) throws SQLException;
// 设置该连接上的所有操作是否执行自动提交
void setAutoCommit(boolean autoCommit) throws SQLException;
// 提交该连接上至上次提交以来所作出的所有更改
void commit() throws SQLException;
// 回滚事务,数据库回滚到原来的状态
void rollback() throws SQLException;
// 关闭连接
void close() throws SQLException;
// 设置事务隔离级别
void setTransactionIsolation(int level) throws SQLException;
java
// 不支持事务
int TRANSACTION_NONE = 0;
// 读取未提交的数据
int TRANSACTION_READ_UNCOMMITTED = 1;
// 读取已提交的数据
int TRANSACTION_READ_COMMITTED = 2;
// 可重复读
int TRANSACTION_REPEATABLE_READ = 4;
// 串行化
int TRANSACTION_SERIALIZABLE = 8;
java

Statement

java.sql.Statement: SQL语句执行接口,数据库厂商提供的JDBC驱动包中必须包含该接口的实现,该接口主要提供执行 SQL 语句的功能

// 执行查询,得到一个结果集
ResultSet executeQuery(String sql) throws SQLException;
// 执行更新,得到受影响的行数
int executeUpdate(String sql) throws SQLException;
// 关闭SQL语句执行器
void close() throws SQLException;
// 将SQL语句添加到批处理执行SQL列表中
void addBatch( String sql ) throws SQLException;
// 执行批处理,返回列表中每一条SQL语句的执行结果(每个元素是受影响的行数)
int[] executeBatch() throws SQLException;
java

ResultSet

java.sql.ResultSet: 查询结果集接口,数据库厂商提供的JDBC驱动包中必须包含该接口的实现,该接口主要提供查询结果的获取功能

// 光标从当前位置(默认位置位为0)向前移动一行,如果存在数据,则返回true,否则返回false
boolean next() throws SQLException;
// 关闭结果集
void close() throws SQLException;
// 获取指定列的字符串值
String getString(int columnIndex) throws SQLException;
// 获取指定列的布尔值
boolean getBoolean(int columnIndex) throws SQLException;
// 获取指定列的整数值
int getInt(Sting columnName) throws SQLException;
// 获取指定列的对象
Object getObject(int columnIndex, Class type) throws SQLException;
// 获取结果集元数据:查询结果的列名称、列数量、列别名等等
ResultSetMetaData getMetaData() throws SQLException;
// 光标从当前位置(默认位置位为0)向后移动一行,如果存在数据,则返回true,否则返回false
boolean previous() throws SQLException;
java

JDCB 操作步骤

0. 引入驱动包

新建工程后,将 mysql-connector-java.jar 引入工程中

1. 加载驱动

//MySQL版本为 5.0 的加载方式
//Class.forName("com.mysql.jdbc.Driver");

//MySQL版本为 8.0 的加载方式
Class.forName("com.mysql.cj.jdbc.Driver");
java

2. 获取连接

// jdbc:使用jdbc连接技术
// mysql://localhost:3306 使用的是MySQL数据库协议,访问的是本地计算机3306端口
// hx_demo哪个库
// ? 后面是指定时区(亚洲/上海) mysql8.0要求的(?)
String url = "jdbc:mysql://localhost:3306/hx_demo?serverTimezone=Asia/Shanghai";
String username = "root";
String password = "root";
Connection connection = DriverManager.getConnection(url, username, password);
java

3. 创建 SQL 语句执行器

Statement statement = connection.createStatement();
java

4. 执行 SQL 语句

// 查询
ResultSet rs = statement.executeQuery(sql);
while(rs.next()) {
// 示例: 获取列信息 注意, 数字是从1开始的! 对于的是 [select * ...] 的*的顺序
int id = rs.getInt(1);
String name = rs.getString(2);
}

// 更新
int affectedRows = statement.executeUpdate();
java

5. 释放资源

rs.close();
statement.close();
connection.close();
java

示例:

import java.sql.*;

public class Main {
public static void main(String[] args) {
//MySQL版本为 8.0 的加载方式
try {
// 选择使用的加载方式
Class.forName("com.mysql.cj.jdbc.Driver");
// 进行数据库连接
String url = "jdbc:mysql://localhost:3306/hx_demo?serverTimezone=Asia/Shanghai";
String username = "root";
String password = "root";
Connection connection = DriverManager.getConnection(url, username, password);
// 创建SQL语句执行器
Statement statement = connection.createStatement();

// 执行sql语句
String sql = "select * from stu";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
int id = resultSet.getInt(1);
String name = resultSet.getString(2);
int sex = resultSet.getInt(3);
String biday = resultSet.getString(4);
String className = resultSet.getString(5);
System.out.println(id + "|" + name + "|" + sex + "|" + biday + "|" + className);
}

sql = "update stu set name = '老登' where id = 1";

System.out.println("更新了: " + statement.executeUpdate(sql) + "行");

// 关闭资源
resultSet.close();
statement.close();
connection.close();
} catch (ClassNotFoundException | SQLException e) {
throw new RuntimeException(e);
}
}
}
java

预处理SQL

在日常开发中,我们经常会根据用户输入的信息从数据库中进行数据筛选,现有 stu 表数据如下:

+----+----------+------+------------+---------+
| id | name | sex | birthday | class |
+----+----------+------+------------+---------+
| 1 | 老登 | 2 | 1997-07-18 | 计科2|
| 2 | 宋宛丝 | 0 | 1992-05-24 | 软工1|
| 3 | 卫鸿文 | 0 | 1990-06-15 | 计科2|
| 4 | 袁巧蕊 | 0 | 1993-02-09 | 计科2|
| 5 | 罗浩轩 | 0 | 1991-03-13 | 计科1|
| 6 | 羊海瑶 | 1 | 1992-10-04 | 计科2|
| 7 | 伏鸿远 | 2 | 1993-10-12 | 计科1|
| 8 | 赫连春蕾 | 2 | 1993-03-15 | 计科1|
| 9 | 柯浩阔 | 0 | 1999-02-24 | 软工2|
+----+----------+------+------------+---------+
sql

现要根据用户输入的学生姓名查询学生信息。

Scanner sc = new Scanner(System.in);
System.out.println("请输入学生姓名:");
String name = sc.next();
String sql = "SELECT id, name, sex, age FROM stu WHERE name='" + name + "'";
java

如果此时用户输入信息为: 张华' or 1='1,那么,上面的代码执行后 SQL 语句变为

SELECT id, name, sex, age FROM stu WHERE name='张华' or 1='1'
sql

因为 1='1' 是恒成立的, 会被套出所有的数据~

显然查询的结果发生了变化,这样的情况被称作为 SQL 注入

为了防止 SQL 注入,Java 提供了PreparedStatement接口对 SQL 进行预处理,该接口是Statement接口的子接口,其常用方法如下:

// 执行查询,得到一个结果集
ResultSet executeQuery() throws SQLException;
// 执行更新,得到受影响的行数
int executeUpdate() throws SQLException;
// 使用给定的整数值设置给定位置的参数
void setInt(int parameterIndex, int x) throws SQLException;
// 使用给定的长整数值设置给定位置的参数
void setLong(int parameterIndex, long x) throws SQLException;
// 使用给定的双精度浮点数值设置给定位置的参数
void setDouble(int parameterIndex, double x) throws SQLException;
// 使用给定的字符串值设置给定位置的参数
void setString(int parameterIndex, String x) throws SQLException;
// 使用给定的对象设置给定位置的参数
void setObject(int parameterIndex, Object x) throws SQLException;
// 获取结果集元数据
ResultSetMetaData getMetaData() throws SQLException;
java

如何获取 PreparedStatement 接口对象呢?

PreparedStatement ps = connection.prepareStatement(sql);
java

PreparedStatement是如何进行预处理的?

使用PreparedStatement时,SQL 语句中的参数一律使用?号来进行占位,然后通过调用setXxx()方法来对占位的?号进行替换。从而将参数作为一个整体进行查询。

上面的示例使用 PreparedStatement 编写 SQL 语句为:

Scanner sc = new Scanner(System.in);
System.out.println("请输入学生姓名:");
String name = sc.next();
String sql = "SELECT id, name, sex, age FROM stu WHERE name=?";
PreparedStatement ps = connection.prepareStatement(sql);
ps.setString(1, name);
ResultSet rs = ps.executeQuery();
java

建议都使用预处理SQL, 因为它 "安全"

完整代码:

public class Main {
static Scanner sc = new Scanner(System.in);

public static void main(String[] args) {
// 选择使用的加载方式
try {
Class.forName("com.mysql.cj.jdbc.Driver");
// 进行数据库连接
String url = "jdbc:mysql://localhost:3306/hx_demo?serverTimezone=Asia/Shanghai";
String username = "root";
String password = "root";
Connection connection = DriverManager.getConnection(url, username, password);

String _name;
System.out.println("请输入需要查询的名称: ");
_name = sc.nextLine();

// 创建SQL预处理器
String sql = "select * from stu where name = ?";
PreparedStatement ps = connection.prepareStatement(sql);
ps.setString(1, _name);

ResultSet rs = ps.executeQuery();
while (rs.next()) {
int id = rs.getInt(1);
String name = rs.getString(2);
int sex = rs.getInt(3);
String biday = rs.getString(4);
String className = rs.getString(5);
System.out.println(id + "|" + name + "|" + sex + "|" + biday + "|" + className);
}

} catch (ClassNotFoundException | SQLException e) {
throw new RuntimeException(e);
}
}
}
java
请作者喝奶茶:
Alipay IconQR Code
Alipay IconQR Code
本文遵循 CC CC 4.0 BY-SA 版权协议, 转载请标明出处
Loading Comments...