JDBC
什么是 JDBC
-
概述
JDBC(Java DataBase Connectivity) 是一种开发与数据库无关的"一次编写, 到处运行" 的 Java 数据库应用程序的技术。
同时,JDBC 规范定义接口,我们只需要调用 JDBC 接口中的方法即可,数据库驱动由数据库产商提供,具体的实现也由各大数据库厂商来实现。
即编写的代码无需改变, 就可以访问不同的数据库。
-
好处
提供了很简单、便捷的访问数据库的方法。
非常灵活构建 SQL , 也可以编写很复杂的 SQL 语句。
使用 JDBC 连接数据库,执行数据库查询和增加、删除、修改。
注:
下文例子数据库名为"student" 、表名为"t_student",表结构如下:
-
导入驱动 Jar 包
-
加载驱动
// 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
- 连接数据库
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* @Author: Travelmate
* @CreateTime: 2021/5/28 16:08
* @Description:
*/
public class JDBC {
static Connection conn = null;
private static void connectDB(String url, String name, String pwd) {
try {
// 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 连接数据库
conn = DriverManager.getConnection(url, name, pwd);
System.out.println("连接数据库 : " + conn);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
if (conn != null || conn.isClosed()){
conn.close();
conn = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
// student 为创建的数据库名
String url = "jdbc:mysql://localhost:3306/student?useSSL=false&serverTimezone=GMT%2B8&characterEncoding=UTF-8";
String name = "root";
String pwd = "052018";
// 拼接字符串URL 、 用户名 、 密码
connectDB(url, name, pwd);
}
}
连接结果界面: 成功
4. 获取 Statement 对象并执行查询和更新的 SQL 语句
数据库里的数据:
封装类:操作数据库的流程细节
import java.sql.*;
import java.util.Properties;
/**
* @Author: Travelmate
* @CreateTime: 2021/5/28 16:08
* @Description:
*/
public class JDBC {
static Connection conn = null;
static Statement stmt = null;
static ResultSet rs = null;
public static void connectToAndQueryDB(String driverClass, String url, String name,String pwd, String sql) {
try {
// 加载 JDBC 驱动类
Class.forName(driverClass);
// 连接数据库
Properties info;
conn = DriverManager.getConnection(url, name, pwd);
// 使用 Statement 对象执行 sql 语句并获取查询结果存储在 ResultSet 对象中
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
// 根据 rs 对象获取查询结果的元数据, 表的列数
ResultSetMetaData rsm = rs.getMetaData();
int count = rsm.getColumnCount();
// 输出元数据
for (int i = 1; i <= count; i++) {
System.out.print(rsm.getColumnName(i) + "\t");
}
System.out.println();
// 输出查询结果
while (rs.next()) {
for (int i = 1; i <= count ; i++) {
System.out.print(rs.getObject(i) + "\t");
}
System.out.println();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
// 最后关闭连接
try {
if (rs != null) {
rs.close();
rs = null;
}
if (stmt != null) {
stmt.close();
stmt = null;
}
if (conn != null && conn.isClosed()) {
conn.close();
conn = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
执行类:调用封装类的方法去查询数据库
/**
* @Author: Travelmate
* @CreateTime: 2021/5/28 17:31
* @Description:
*/
public class Test {
public static void main(String[] args) {
// 数据库驱动字符串
String driverClass = "com.mysql.cj.jdbc.Driver";
// 数据库 URL 字符串
String url = "jdbc:mysql://localhost:3306/student?useSSL=false&serverTimezone=GMT%2B8&characterEncoding=UTF-8";
// 数据库用户名
String name = "root";
// 数据库密码
String pwd = "052018";
// 查询语句
String querySQL = "select * from t_student";
JDBC.connectToAndQueryDB(driverClass, url, name, pwd, querySQL);
}
}
查询结果截图:
- 增删改查的 SQL 语句
封装类新增一个方法
public static void connectToAndUpdateDB(String driverClass, String url, String name, String pwd, String sql){
try {
// 加载 JDBC 驱动类
Class.forName(driverClass);
// 连接数据库
Properties info;
conn = DriverManager.getConnection(url, name, pwd);
// 使用 Statement 对象执行 sql 语句并获取查询结果存储在 ResultSet 对象中
stmt = conn.createStatement();
int n = stmt.executeUpdate(sql);
System.out.println("已经更新了 " + n + "条记录");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
// 最后关闭连接
try {
if (rs != null) {
rs.close();
rs = null;
}
if (stmt != null) {
stmt.close();
stmt = null;
}
if (conn != null && conn.isClosed()) {
conn.close();
conn = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
注:
除了查询语句要调用 Statement 的 executeQuery(String sql) 函数, JDBC 的增删改功能都是调用另一个函数 executeUpdate(String sql) 就行。
在本例中,替换 JDBC.connectToAndUpdateDB(String driverClass, String url, String name, String pwd, String sql) 对应的 sql 语句就可以实现对应的功能。
// 插入语句
String insertSQL = "insert into t_student values('9090','小明','24')";
// 更新语句
String updateSQL = "update t_student set age = '29' where id== = '9090'";
// 删除语句
String deleteSQL = "delete from t_student where id = '9090'";
执行结果:
- 查询结果集 ResultSet 的使用
- 封装数据库查询的结果集, 对结果集进行遍历,取出每一条记录。
- 实现 Statement 接口的任何对象 (包含 PreparedStatement ,CallalbleStatement 和 RowSet)都可以创建一个 ResultSet 对象。
ResultSet rs = stmt.executeQuery(sql);
- 可以通过游标访问 ResultSet 对象的数据。
游标可以看做是指向 ResultSet 对象中的一行数据的指针。
最初,游标位于数据表第一行之前。 ResultSet.next() 方法将游标移动到下一行。如果游标位于最后一行之后,此方法返回 false,否则返回 true。 此方法可以作为 while 循环的条件, 来遍历 ResultSet 中的所有数据。
- 获取 PreparedStatement 对象并执行增删改查语句,如果向包含 ?参数的 SQL 语句中插入参数值
-
PreparedStatement 接口是 Statement 的子接口, 它表示一条预编译过的 SQL 语句。
-
PreparedStatement 对象所代表的 SQL 语句中的参数用问号 (?) 来表示。 ?在SQL中表示占位符
调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数. setXxx() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值
编程实现了 ORM:使数据库中的字段 与 实体对象的属性相映射
/**
* @Author: Travelmate
* @CreateTime: 2021/5/28 20:47
* @Description:
*/
public class Student {
private Integer id;
private String name;
private Integer age;
public Student() {
}
public Student(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
操作数据库的封装类
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
/**
* @Author: Travelmate
* @CreateTime: 2021/5/28 16:08
* @Description:
*/
public class JDBC {
Connection con;
/**
* 连接数据库
*/
public JDBC() {
// 数据库驱动字符串
String driverClass = "com.mysql.cj.jdbc.Driver";
// 数据库 URL 字符串
String url = "jdbc:mysql://localhost:3306/student?useSSL=false&serverTimezone=GMT%2B8&characterEncoding=UTF-8";
// 数据库用户名
String name = "root";
// 数据库密码
String pwd = "052018";
try {
// 加载 JDBC 驱动类
Class.forName(driverClass);
// 连接数据库
con = DriverManager.getConnection(url, name, pwd);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 查询
* @return
*/
public List<Student> query() {
List<Student> list = new ArrayList<>();
PreparedStatement pstmt = null;
ResultSet rs = null;
if (con != null) {
try {
// 获取 PrepareStatement 对象, 包含了一个 SQL 语句
pstmt = con.prepareStatement("select * from t_student");
// 用 PrepareStatement 对象执行查询语句, 获取的查询结果赋值给一个 ResultSet 对象
rs = pstmt.executeQuery();
while (rs.next()) {
Student stu = new Student();
stu.setId(rs.getInt("id"));
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
list.add(stu);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
if (rs != null) {
rs.close();
rs = null;
}
if (pstmt != null) {
pstmt.close();
pstmt = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return list;
}
/**
* 插入数据
* @param stu
* @return
*/
public boolean insert(Student stu) {
PreparedStatement pstmt = null;
if (con != null){
try {
// 获取 PrepareStatement 对象, 包含了一个带?参数 SQL 语句
pstmt = con.prepareStatement("insert into t_student values (?,?,?)");
pstmt.setInt(1, stu.getId());
pstmt.setString(2, stu.getName());
pstmt.setInt(3, stu.getAge());
int i = pstmt.executeUpdate();
if (i != 0){
return true;
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
if (pstmt != null) {
pstmt.close();
pstmt = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return false;
}
/**
* 修改学生信息
* @param stu
* @return
*/
public boolean update(Student stu) {
PreparedStatement pstmt = null;
if (con != null) {
try {
pstmt = con.prepareStatement("update t_student set name = ?, age = ? where id = ?");
pstmt.setString(1, stu.getName());
pstmt.setInt(2, stu.getAge());
pstmt.setInt(3, stu.getId());
int i = pstmt.executeUpdate();
if (i != 0) {
return true;
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
if (pstmt != null) {
pstmt.close();
pstmt = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return false;
}
/**
* 按id删除学生记录
* @param id
* @return
*/
public boolean deleteById(int id) {
PreparedStatement pstmt = null;
if (con != null) {
try {
pstmt = con.prepareStatement("delete from t_student where id=?");
pstmt.setInt(1, id);
int i = pstmt.executeUpdate();
if (i != 0) {
return true;
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
if (pstmt != null) {
pstmt.close();
pstmt = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return false;
}
/**
* 关闭数据库连接
*/
public void close() {
try {
if (con != null) {
con.close();
con = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
可执行类:验证增删改查代码的可行性
import java.util.List;
/**
* @Author: Travelmate
* @CreateTime: 2021/5/28 17:31
* @Description:
*/
public class Test {
public static void main(String[] args) {
// 创建封装类的构造方法连接数据库
JDBC jdbc = new JDBC();
System.out.println("查询的数据输出: ");
List<Student> list = jdbc.query();
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
Student stu = new Student(9092, "小明", 15);
if (jdbc.insert(stu)) {
System.out.println("添加成功");
System.out.println("添加后的数据: ");
List<Student> list1 = jdbc.query();
for (int i = 0; i < list1.size(); i++) {
System.out.println(list1.get(i));
}
}else {
System.out.println("添加失败");
}
stu.setName("小红帽");
if (jdbc.update(stu)){
System.out.println("更新成功");
System.out.println("更新后的数据: ");
List<Student> list1 = jdbc.query();
for (int i = 0; i < list1.size(); i++) {
System.out.println(list1.get(i));
}
}else {
System.out.println("更新失败");
}
if (jdbc.deleteById(9092)){
System.out.println("删除成功");
System.out.println("删除后的数据: ");
List<Student> list1 = jdbc.query();
for (int i = 0; i < list1.size(); i++) {
System.out.println(list1.get(i));
}
}else {
System.out.println("删除失败");
}
}
}
执行结果截图: