
JDBCJDBC(Java Data Base Connectivity, Java数据库连接)是 Java 程序和数据库之间的桥梁,包含了一套 Java 定义的用于执行 SQL 语句的接口,使开发者能够编写数据库的程序。
JDBC 的主要作用是:与数据库建立连接、发送 SQL 语句和处理数据库执行结果。

客户端操作数据库的过程主要分为以下几步:
SQL 语句 Java 采取的做法是把以上操作步骤定义了相应的接口,具体的实现交给数据库厂商去做,Java 程序员只需要按照需要调用接口中定义的方法即可,这样不论使用什么数据库,都对于 Java 程序没有任何影响,即便是换一个数据库,也只需要换一下相应厂商的实现依赖。
JDBC 使用过程可以概括为:
StatementSQLJDBCMaven 工程并配置国内镜像Maven 相当于 Java 世界里的应用(依赖)市场,管理市面上所有的应用(依赖),自动化地帮你拉库、编译、打包、测试、部署,一键搞定项目构建。
创建 maven 工程如下图所示:

下面是工程的目录构成:

然后到 maven仓库 查找 MySQL Connector/j,然后点进去复制 maven 代码,如下所示:

复制到 pom.xml 的 dependencies 依赖中,如下图所示:

下载完成就能使用了!
点击编译器右边的 maven 图标,可以看到下面的自动化操作,如下所示,这些后面会系统学!

在下载依赖的时候,可能速度比较慢,这时候就需要去修改配置文件 settings.xml 中的源,改成阿里云镜像,速度会加快:

<mirrors>
<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>
</mirrors>DriverManager 驱动管理类,⽤于管理 JDBC 驱动程序,可以从驱动程序中获取数据库连接,始于 JDK1.1。
DataSource 数据源是 DriverManager 的替代方案,始于 JDK1.4,是获取数据库连接的首选方法,推荐使用。
这两者都可以获取到数据库连接,只不过连接管理方式和资源利用效率不同,如下所示:
DriverManager 每次调用 getConnection 方法都会初始化一个新的连接,使用完成后会关闭真实连接,导致资源浪费。 DataSource 使用了连接池的技术,会在初始化时创建一定数量的数据库连接,这些连接可以重复使用,关闭时并不是真正关闭连接,而是将连接归还给连接池,以供后续使用,有效地提高资源利用率和性能。DriverManager 静态方法获取// 1. 加载驱动注册程序,只有注册了驱动才能使用
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 获取数据库连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/javalearning?useSSL=false&serverTimezone=UTC&characterEncoding=utf8",
"root", "123123");☠ 注意事项:
MySQL8 之后驱动类名是 com.mysql.cj.jdbc.Driver,而不是旧版本的 com.mysql.jdbc.DriverJDBC 连接的 url 的格式是:jdbc:mysql://主机:端口/数据库名?参数键=值&参数键=值DataSource 对象获取(推荐⭐⭐⭐)
// 1. 设置mysql数据源的连接信息
MysqlDataSource mds = new MysqlDataSource();
mds.setUrl("jdbc:mysql://localhost:3306/javalearning?useSSL=false&serverTimezone=UTC&characterEncoding=utf8");
mds.setUser("root");
mds.setPassword("123123");
// 2. 向上转型成DataSource接口
DataSource ds = mds;
// 3. 获取连接
connection = ds.getConnection();StatementStatement 是用于执行静态 SQL 语句并返回执行结果的对象。
// 通过connection获取statement对象
statement = connection.createStatement();PreparedStatement(推荐⭐⭐⭐)这是预编译 SQL 语句对象,SQL 语句被预编译并存储在 PreparedStatement 对象中,可以使用该对象多次执行 SQL 语句,同时解决了SQL注入问题。
在使用 sql 的时候用 ? 号进行占位,然后通过 set 系列函数进行参数绑定。
// 4. 定义sql语句并创建PreparedStatement对象
String sql = "select id, name, sno, gender, enroll_date, class_id from student where name = ?";
prestatement = connection.prepareStatement(sql);
// 5. 进行占位符绑定
prestatement .setString(1, "宋江");SQL 语句select 查询时返回的是一个结果集,用 ResultSet 进行接收,通常用 executeQuery()接口。insert、update、delete 操作时,返回的是受影响的行数,用 int 类型接收然后判断正确即可,通常用 executeUpdate() 接口。// 执行select语句, 并接收结果集
ResultSet resultSet = statement.executeQuery("select id, name, sno, age, gender, enroll_date, class_id from student");
// 执行insert, update, delete语句,并接收受影响的行数
int row = statement.executeUpdate("update student set age = 20 where id = 2");ResultSet如果返回的是一个结果集,也就是进行 select 查询,则需要遍历这个集合获取对应列的值。
此时使用结果集的 next() 函数,如果游标还没走到最后,则返回 true,而游标走到最后则会返回 false,然后可以使用一系列的 getxxx() 方法获取对应的字段,具体代码如下所示:
// 7. 处理结果集
while (resultSet.next()) {
Long id = resultSet.getLong("id");
String name = resultSet.getString("name");
String sno = resultSet.getString("sno");
boolean gender = resultSet.getBoolean("gender");
Date enrollDate = resultSet.getDate("enroll_date");
Long classId = resultSet.getLong("class_id");
System.out.println(id + "\t" + name + "\t" + sno + "\t" + gender + "\t" + enrollDate + "\t" + classId + "\t");
}最后在 finally 代码块中进行资源释放,否则会出现内存泄漏问题:
finally {
// 8. 释放资源
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();
}
}
}DAO 是 Data Access Object(数据访问对象)的缩写,是 Java 等编程语言中常见的一种设计模式,用来封装对数据库的操作逻辑。
简单的说,DAO 就是专门负责 "跟数据库打交道" 的模块,把 SQL 操作从业务代码里分离出来,让业务代码更干净、更易维护、更专业。
比如我们要对学生表和班级表进行增删改查,以及一些特定要求的查询,那我们会创建以下内容:

比如 Classes 表,存放对应的数据字段,如下所示:
package com.liren.model;
public class Classes {
private Long id; // 主键编号
private String name; // 班级名
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}然后对应的 ClassesDAO.java 中实现对应的增删查改,如下所示:
package com.liren.dao;
import com.liren.model.Classes;
import utils.DBUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* 专门针对班级表的数据库查询对象
*/
public class ClassesDAO {
// 增加操作
public void insert(Classes cs) {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = DBUtil.getConnection();
String sql = "insert into class(id, name) values(?, ?)";
ps = conn.prepareStatement(sql);
ps.setLong(1, cs.getId());
ps.setString(2, cs.getName());
int ret = ps.executeUpdate();
if(ret > 0) {
System.out.println("插入班级成功!");
} else {
System.out.println("插入班级失败!");
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
DBUtil.closeConnection(null, ps, conn);
}
}
// 删除、更新、查询操作......
}上面提到将一些数据源初始化、关闭数据源等操作专门做成一个工具类,可以减少代码冗余,如下所示:
// DBUtil.java文件
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 String url = "jdbc:mysql://localhost:3306/javalearning?useUnicode=true&characterEncoding=utf8";
private static String user = "root";
private static String password = "123123";
private static DataSource ds = null;
// 在类加载的时候初始化dataSource对象
static {
MysqlDataSource mds = new MysqlDataSource();
mds.setURL(url);
mds.setUser(user);
mds.setPassword(password);
ds = mds;
}
// 构造方法私有化,防止其他的地方通过new来创建这个类的对象
private DBUtil() {}
// 获取连接接口
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
// 获取关闭连接接口
public static void closeConnection(ResultSet resultSet, Statement statement, Connection conn) {
if (resultSet != null) {
try {
resultSet.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (Exception e) {
e.printStackTrace();
}
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}在 select 的时候难免会有多表查询,如下所示:
String sql = "select s.id, s.name, s.age, c.id c_id, c.name c_name from student s, class c where s.class_id = c.id and c.name = ?";此时结果集该如何表示呢❓❓❓
这个时候可以在 Student 表中添加 Classes 对象,进行关联,如下所示:
package com.liren.model;
import java.util.Date;
public class Student {
private Long id;
private String name;
private String sno;
private Integer age;
private byte gender;
private Date enroll_date;
private Long class_id;
private Classes cs; // 与课程表关联
public Classes getCs() {
return cs;
}
public void setCs(Classes cs) {
this.cs = cs;
}
// 一系列get、set方法
}这样子只需要在结果集中构造出 Classes 对象,然后设置到 Student 中的 Classes 字段,最后拿到的 List<Student> 返回就能存在 Classes 的字段了!
package com.liren.dao;
import com.liren.model.Classes;
import com.liren.model.Student;
import utils.DBUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* 专门针对学生表的数据库访问对象
*/
public class StudentDAO {
// 增删改查。。。
// 还有专门针对学生表的业务逻辑处理方法
// 比如下面的:根据班级名查询班级中所有的同学信息
public List<Student> selectByClassname(String classname) {
if(classname == null || classname.isEmpty()) {
System.out.println("班级名不能为空!");
return null;
}
Connection conn = null;
ResultSet rs = null;
PreparedStatement ps = null;
try {
List<Student> ret = new ArrayList<Student>();
conn = DBUtil.getConnection();
String sql = "select s.id, s.name, s.age, s.sno, s.gender, s.enroll_date, c.id c_id, c.name c_name from student s, class c where s.class_id = c.id and c.name = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, classname);
rs = ps.executeQuery();
// ❗❗❗❗❗❗❗❗下面是重点❗❗❗❗❗❗❗❗❗
while(rs.next()) {
// 封装Student对象
Student s = new Student();
s.setId(rs.getLong("id"));
s.setName(rs.getString("name"));
s.setAge(rs.getInt("age"));
s.setSno(rs.getString("sno"));
s.setGender(rs.getByte("gender"));
s.setEnroll_date(rs.getDate("enroll_date"));
s.setClass_id(rs.getLong("c_id"));
// 封装Classes对象
Classes c = new Classes();
c.setId(rs.getLong("c_id"));
c.setName(rs.getString("c_name"));
// 设置Student对象中的Classes对象,完成两者的关联,然后添加到List中
s.setCs(c);
ret.add(s);
}
return ret;
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
DBUtil.closeConnection(rs, ps, conn);
}
}
}原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。