JDBC编程
JDBC(Java Database Connectivity,Java数据库连接)是Java程序和数据库之间的桥梁,包含了一整套Java定义的用于执行SQL语句的接口,使得开发者能够编写数据库程序。JDBC的主要作用是:与数据库建立连接、发送SQL语句和处理数据库执行结果。
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 DriverManager
和 DataSource
DriverManager
用于管理JDBC驱动程序,可以从驱动程序中获取数据库连接。DataSource
是DriverManager
的替代方案,是获取数据库连接的首要方法。
4.2 DriverManager
和 DataSource
的区别
主要区别体现在连接管理方式:
DriverManager
每次调用getConnection
方法都会初始化一个新连接,使用完成后会关闭真实连接,导致资源浪费。DataSource
使用连接池的技术,会在初始化时创建一定数量的数据库连接,这些连接可以重复使用,关闭时并不是真正关闭连接,而是将连接归还给连接池,以供后续使用,有效提高了资源利用率和性能。如果连接池的连接不够用,就会创建临时连接,当负载降低时,临时连接会销毁。
4.3 Connection
数据库连接
数据库连接(会话)对象,可以接受 getConnection
方法的值,一旦建立了Connection
,就可以通过它来创建Statement
或PreparedStatement
对象。这些对象用于执行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()
执行结果返回的是一个整形,通常用于update
、insert
、delete
操作。
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);
}
}
}
更多推荐
所有评论(0)