JDBC介绍
JDBC(Java DataBase Connectivity
) 称为Java数据库连接,它是一种用于数据库访问的应用程序API,由一组用Java语言编写的类和接口组成,有了JDBC就可以用统一的语法对多种关系数据库进行访问,而不用担心其数据库操作语言的差异。 有了JDBC,就不必为访问MySQL数据库专门写一个程序,为访问Oracle又专门写一个程序等等。
JDBC的体系结构
JDBC的结构可划分为两层:一个是面向底层的JDBC Driver Interface(驱动程序管理器接口)(各数据库厂商负责实现接口),另一个是面向程序员的JDBC API
使用JDBC编程,可让开发人员从复杂的驱动器调用命令和函数中解脱出来,可以致力于应用程序中的关键地方。JDBC支持不同的关系数据库,这使得程序的可移植性大大加强。
JDBC API是面向对象的,可以让用户把常用的方法封装为—个类,以备后用。但是它也有缺点,一是使用JDBC,访问数据记录的速度会受到一定程度的影响。二是JDBC结构中包含不同厂家的产品,这就给更改数据源带来了很大的麻烦。
JDBC核心接口与类
JDBC核心类库包含在java.sql包中
接口:
Connection
:特定数据库的连接(会话)。在连接上下文中执行SQL语句并返回结果。PreparedStatement
:表示预编译的 SQL 语句的对象。Statement
:用于执行静态 SQL 语句并返回它所生成结果的对象。ResultSet
:表示数据库结果集的数据表,通常通过执行查询数据库的语句生成 。CallableStatement
:用于执行 SQL 存储过程的接口 。
类:
DriverManager
:负责管理JDBC驱动程序。使用JDBC驱动程序之前,必须先将驱动程序加载并注册后才可以使用,同时提供方法来建立与数据库的连接。SQLException
:有关数据库操作的异常
JDBC优缺点
优点:
- JDBC使得编程人员从复杂的驱动器调用命令和函数中解脱出来,可以致力于应用程序中的关键地方。
- JDBC支持不同的关系数据库,这使得程序的可移植性大大加强。
- JDBC API是面向对象的,可以让用户把常用的方法封装为—个类,以备后用。
缺点:
- 使用JDBC,访问数据记录的速度会受到一定程度的影响。
- JDBC结构中包含不同厂家的产品,这就给更改数据源带来了很大的麻烦。
数据库驱动程序
第一类: jdbc-odbc桥
把JDBC API调用转换成ODBC API 调用,然后ODBC API调用针对供应商的ODBC 驱动程序来访问数据库,即利用JDBC- ODBC 桥通过ODBC来存储数据源 。
第二类: 本地API驱动
本地api驱动直接把jdbc调用转变为数据库的标准调用再去访问数据库。这种方法需要本地数据库驱动代码。
第三类: 网络协议驱动
它使用一种与具体数据库无关的协议将数据库请求发送给一个中间服务器。
第四类: 本地协议驱动
这种驱动直接把jdbc调用转换为符合相关数据库系统规范的请求。由于4型驱动写的应用可以直接和数据库服务器通讯,这种类型的驱动完全由java实现,因此实现了平台独立性。 通常开发中多采用第四种方式,这种驱动不需要先把jdbc的调用传给odbc或本地数据库接口或者是中间层服务器,所以它的执行效率是非常高的驱动。
注:各数据库厂商均提供对 JDBC 的支持,即提供数据库连接使用的驱动程序文件需要为数据库应用程序正确加载驱动程序文件以获得数据库连接,实施操作。
开始演示
创建JDBC应用程序的步骤
- 载入JDBC驱动程序
- 定义连接URL
- 建立连接
- 创建Statement对象
- 执行查询或更新
- 结果处理
- 关闭连接
下载 jar 包:https://mvnrepository.com/artifact/mysql/mysql-connector-java,选择和你的MySQL版本一致的jar包
JDBC访问数据库
注意:
Class.forName("com.mysql.cj.jdbc.Driver");
如果是 MySQL8就用
,如果是 MySQL5.x的就用 com.mysql.cj.jdbc.Driver
新创建测试表
CREATE TABLE `user` (
`uid` int NOT NULL,
`name` varchar(255) DEFAULT NULL,
`sex` varchar(255) DEFAULT NULL,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
增删改
package com.mr.jdbctest;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class JdbcTest {
public static void main(String[] args) {
PreparedStatement pstm = null;
Connection conn = null;
// 1.载入JDBC驱动程序
try {
Class.forName("com.mysql.cj.jdbc.Driver");
// 数据库用户名
String username = "root";
// 数据库密码
String password = "123456";
/*
url参数用来确定连接的数据库信息: 数据库机器ip 端口号port 数据库名db_name 连接的参数,比如编解码集、时区...
url格式:jdbc:mysql://ip:port/db_name?k=v参数 ,只需要了解url的组成
*/
// 2.定义连接URL
String url = "jdbc:mysql://localhost:3306/cs?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai";
// 3.建立连接
conn = DriverManager.getConnection(url, username, password);
// url错误创建链接时会出现异常
// 参数错误不会导致运行时异常
/***
* 修改 sql 语句就可以实现 增删改
**/
String sql = "insert into user values(1,'学生一号','男')";
// 4.创建Statement对象
pstm = conn.prepareStatement(sql);
// 5.执行查询或更新
int res = pstm.executeUpdate();
// 6.结果处理,输入1,这是成功,不是 1就是失败了
if (res > 0) {
System.out.println("成功");
} else {
System.out.println("失败");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 7.关闭资源
try {
pstm.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
参数解释:
useUnicode = true&characterEncoding=UTF-8
:MySQL编码默认为GBK,此参数的作用就是允许插入unicode字符集中的数据,使用UTF-8编码方式进行编码。useSSL=false
:SSL是高版本MySQL提供的数据加密、安全保障的新协议,为了向下兼容所以设置为false关闭此协议。serverTimezone=Asia/Shanghai
:为了确保日期类型数据能够正确存储,需要指定时区为上海时区(上海时区与北京一致),默认为美国时区。
查
package com.mr.jdbctest;
import java.sql.*;
public class JdbcTest {
public static void main(String[] args) {
PreparedStatement pstm = null;
Connection conn = null;
// 1.载入JDBC驱动程序
try {
Class.forName("com.mysql.cj.jdbc.Driver");
// 数据库用户名
String username = "root";
// 数据库密码
String password = "123456";
/*
url参数用来确定连接的数据库信息: 数据库机器ip 端口号port 数据库名db_name 连接的参数,比如编解码集、时区...
url格式:jdbc:mysql://ip:port/db_name?k=v参数 ,只需要了解url的组成
*/
// 2.定义连接URL
String url = "jdbc:mysql://localhost:3306/cs?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai";
// 3.建立连接
conn = DriverManager.getConnection(url, username, password);
// url错误创建链接时会出现异常
// 参数错误不会导致运行时异常
String sql = "select * from user;";
// 4.创建Statement对象
pstm = conn.prepareStatement(sql);
// 5.执行查询或更新
ResultSet rs = pstm.executeQuery();
// 6.结果处理
while (rs.next()) {
int uid1 = rs.getInt(1);
String name1 = rs.getString(2);
String se1 = rs.getString(3);
System.out.println("uid1=" + uid1 + ",name1=" + name1 + ",se1=" + se1);
int uid2 = rs.getInt("uid");
String name2 = rs.getString("name");
String sex2 = rs.getString("sex");
System.out.println("uid2=" + uid2 + ",name2=" + name2 + ",sex2=" + sex2);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 7.关闭资源
try {
pstm.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
常用方法
- PreparedStatement常用方法
方法声明 | 作用 |
---|---|
int executeUpdate(String sql) | 可执行增,删,改,返回执行受到影响的行数 |
ResultSet executeQuery(String sql) | 执行SQL查询,并返回ResultSet对象 |
boolean execute(String sql) | 可执行任何SQL语句,返回一个布尔值,表示是否返回ResultSet 。(只有执行查询才为true) |
- ResultSet常用方法
方法声明 | 作用 |
---|---|
boolean next() | 游标下移,判断该行是否有结果 |
xx getXx(int index) | 获取该行结果中某个字段的数据,index为编号,index从1开始 |
xx getXx(String name) | 获取改行结果中某个字段的数据,name为字段名 |
数据绑定
作用:数据绑定:将用户输入的数据,绑定到要执行的SQL语句中。
JDBC执行的SQL中的数据要根据用户的输入发生变化,比如 登录功能背后的查询sql要根据用户名不同,执行不同的条件。这就需要将用户输入的数据绑定到执行的SQL中
1.字符串拼接SQL
步骤:
- 在需要数据的地方,使用变量名替换。
- 在变量名前添加"+,变量后添加+"。
- 注意:如果拼接的是字符串,那么需要在"+之前添加’ 在+"后添加’
演示:根据用户输入的id进行查询。
package com.mr.jdbctest;
import java.sql.*;
import java.util.Scanner;
public class JdbcTest {
public static void main(String[] args) {
PreparedStatement pstm = null;
Connection conn = null;
// 用户输入数据
Scanner sc = new Scanner(System.in);
String id = sc.nextLine();
// 1.载入JDBC驱动程序
try {
Class.forName("com.mysql.cj.jdbc.Driver");
// 数据库用户名
String username = "root";
// 数据库密码
String password = "123456";
// 2.定义连接URL
String url = "jdbc:mysql://localhost:3306/cs?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai";
// 3.建立连接
conn = DriverManager.getConnection(url, username, password);
// url错误创建链接时会出现异常
// 参数错误不会导致运行时异常
String sql = "select * from user where uid = " + id + ";";
// 4.创建Statement对象
pstm = conn.prepareStatement(sql);
// 5.执行查询或更新
ResultSet rs = pstm.executeQuery();
// 6.结果处理
while (rs.next()) {
int uid2 = rs.getInt("uid");
String name2 = rs.getString("name");
String sex2 = rs.getString("sex");
System.out.println("uid2=" + uid2 + ",name2=" + name2 + ",sex2=" + sex2);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 7.关闭资源
try {
pstm.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
SQL注入问题
- 使用
字符串
用字符串拼接可能会出现SQL注入的问题
,如:在进行查询操作时 恶意填入or 1=1 这类字符,使将要执行的SQL变为无条件查询语句,泄漏数据或无法正确验证。
演示:
- 使用占位符 “
?
”
? 占位符是JDBC的一种特殊语法
,专用于参数绑定,可以有效避免SQL注入问题。
使用步骤:
- 在需要使用数据的地方,使用?代替(占位)。
- 发送sql前,通过pstm.setXXX(index,数据)方法给 ? 赋值。
index:占位符编号,从1开始,表示第几个占位符。
xxx 为数据类型,需要根据数据库字段类型选择对应的赋值方法。
演示:解决SQL注入问题
package com.mr.jdbctest;
import java.sql.*;
import java.util.Scanner;
public class JdbcTest {
public static void main(String[] args) {
PreparedStatement pstm = null;
Connection conn = null;
// 用户输入数据
Scanner sc = new Scanner(System.in);
String id = sc.nextLine();
// 1.载入JDBC驱动程序
try {
Class.forName("com.mysql.cj.jdbc.Driver");
// 数据库用户名
String username = "root";
// 数据库密码
String password = "123456";
// 2.定义连接URL
String url = "jdbc:mysql://localhost:3306/cs?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai";
// 3.建立连接
conn = DriverManager.getConnection(url, username, password);
// url错误创建链接时会出现异常
// 参数错误不会导致运行时异常
String sql = "select * from user where uid = ?;";
// 4.创建Statement对象
pstm = conn.prepareStatement(sql);
// 为?占位符赋值
pstm.setString(1,id);
// 5.执行查询或更新
ResultSet rs = pstm.executeQuery();
// 6.结果处理
while (rs.next()) {
int uid2 = rs.getInt("uid");
String name2 = rs.getString("name");
String sex2 = rs.getString("sex");
System.out.println("uid2=" + uid2 + ",name2=" + name2 + ",sex2=" + sex2);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 7.关闭资源
try {
pstm.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
小案例:在数据库中插入用户输入的数据。
package com.mr.jdbctest;
import java.sql.*;
import java.util.Scanner;
public class JdbcTest {
public static void main(String[] args) {
PreparedStatement pstm = null;
Connection conn = null;
// 用户输入数据
Scanner sc = new Scanner(System.in);
System.out.println("请输入编号:");
int id = sc.nextInt();
System.out.println("请输入用户名:");
String name = sc.next();
System.out.println("请输入性别:(男/女)");
String sex = sc.next();
// 1.载入JDBC驱动程序
try {
Class.forName("com.mysql.cj.jdbc.Driver");
// 数据库用户名
String username = "root";
// 数据库密码
String password = "123456";
// 2.定义连接URL
String url = "jdbc:mysql://localhost:3306/cs?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai";
// 3.建立连接
conn = DriverManager.getConnection(url, username, password);
// url错误创建链接时会出现异常
// 参数错误不会导致运行时异常
String sql = "insert into user values(?,?,?);";
// 4.创建Statement对象
pstm = conn.prepareStatement(sql);
// 为?占位符赋值
pstm.setInt(1, id);
pstm.setString(2, name);
pstm.setString(3, sex);
// 5.执行查询或更新
int i = pstm.executeUpdate();
// 6.结果处理
if (i > 0) {
// 处理
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 7.关闭资源
try {
pstm.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}