JDK 版本使用:JDK 21
框架思想:实体类及ORM思想
反射技术:BaseDAO 封装的过程
解决现有问题的角度,主要是 JDBC的基础应用
一、、JDBC 可以解决的问题
1.1 数据存储的问题
解决数据长期的存储问题:
- 数据通过 I/O 流技术,存储在本地磁盘中,解决了持久化问题。但是这个数据没有结构和逻辑,不方便管理和维护。
- 通过关系型数据库(比如:MySQL),将数据按照特定的格式交由数据库管理系统维护。关系型数据库是通过库和表分隔不同的数据,表中数据存储的方式是行和列,区分相同格式不同值的数据。
1.2 Java 程序读取数据的问题
如何通过 Java 程序对数据库中数据做增删改查?
答:使用JDBC 技术,通过Java 程序来操作数据库。
二、JDBC 概述
2.1 什么是 JDBC
- JDBC:Java Database Connectivity(Java 数据库连接)
- JDBC 是 Java 提供的一组独立于任何数据库管理系统的 API
- Java 提供接口规范,由各个数据库厂商提供接口的实现,厂商提供的实现类封装成 jar 文件(数据库驱动 jar 包)
- 面向接口编程,程序员只关心标准和规范,无需关注实现过程。
2.2 JDBC 的核心组成
JDBC:Java 提供接口,数据库厂商提供实现(数据库驱动),程序员调用实现(数据库驱动)来操作数据库。
1、接口规范
- 提高了项目代码的可移植性、可维护性。SUN 公司制定了 Java 程序连接各种数据库的统一接口规范。
- 接口存储在 java.sql 和 javax.sql 包下
2、实现规范
- 数据库厂商自己实现Java 提供的接口规范
- 厂商将实现内容和过程封装成 jar 文件,程序员只需要将 jar 文件引入到项目中集成即可,就可以调用实现过程操作数据库了。
- 驱动从数据库官网上下载
三、JDBC 快速入门
3.1 JDBC 搭建步骤
- 准备数据库
- 官网下载数据库连接驱动 jar 包:https://downloads.mysql.com/archives/c-j/
- 创建 Java 项目,在项目下创建 lib 文件夹,将下载的驱动 jar 包复制到文件夹里。
- 选中 lib 文件夹右键 ——》Add as Library,与项目集成
- 编写代码
驱动版本:8.0.25 之前的 MySql 驱动是需要设置时区的
3.2 熟悉 JDBC 核心编码六个步骤
package com.atguigu.base;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JDBCQuick {
public static void main(String[] args) throws Exception {
// 核心六步
//1.注册驱动(将厂商提供的驱动类,通过类加载的方式加载到我们程序中来)
//Class.forName() 指定要加载的类的全类名
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接对象
String url = "jdbc:mysql://localhost:3306/atguigu";
String username = "root";
String password = "123456";
//拿到连接对象
Connection connection = DriverManager.getConnection(url, username, password);
//3.获取执行 SQL 语句的对象(把SQL语句发送给MySQL的对象 )
Statement statement = connection.createStatement();
//4.编写SQL语句,并执行,接收返回的结果集
String sql = "select * from t_emp";
//返回一个set集合
ResultSet resultSet = statement.executeQuery(sql);
//5.处理结果:遍历resultSet结果集
while (resultSet.next()) {
int empId = resultSet.getInt("emp_id");
String empName = resultSet.getString("emp_name");
double empSalary = resultSet.getDouble("emp_salary");
int empAge = resultSet.getInt("emp_age");
System.out.println(empId+"\t"+empName+"\t"+empSalary+"\t"+empAge);
}
//6.释放资源(对象)【先开后关的原则】
resultSet.close();
statement.close();
connection.close();
}
}
四、核心 API
4.1 注册驱动(可省略)
4.2 Connection 接口(⭐)
Connection 代表着一次连接,用完要释放
4.3 Statement 接口
使用 statement 会产生SQL注入的问题:
package com.atguigu.base;
import java.sql.*;
import java.util.Scanner;
//Injection :注入
public class JDBCInjection {
public static void main(String[] args) throws Exception {
//1.注册驱动(可以省略)
//2.获取连接对象
Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "123456");
//3.获取执行SQL语句对象
Statement statement = connection.createStatement();
//动态注入
System.out.println("请输入员工姓名:");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
//4.编写SQL语句,并执行,接收返回的结果集
String sql = "select * from t_emp where name = '" + name + "'";
ResultSet resultSet = statement.executeQuery(sql);
//5.处理结果,遍历resultSet
while (resultSet.next()) {
int empId = resultSet.getInt("emp_id");
String empName = resultSet.getString("emp_name");
double empSalary = resultSet.getDouble("emp_salary");
int empAge = resultSet.getInt("emp_age");
System.out.println(empId+"\t"+empName+"\t"+empSalary+"\t"+empAge);
}
//6.释放资源
resultSet.close();
statement.close();
connection.close();
}
}
4.4 PreparedStatement 接口(⭐⭐⭐)
package com.atguigu.base;
import java.sql.*;
import java.util.Scanner;
//prepareStatement
public class JDBCPrepared {
public static void main(String[] args) throws Exception {
//1.注册驱动(可以省略)
//2.获取连接对象
Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "123456");
//3.获取执行SQL语句对象
PreparedStatement preparedStatement = connection.prepareStatement("select * from t_emp where emp_name = ?");
//动态注入
System.out.println("请输入员工姓名:");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
//4.为?占位符复制,并执行,接收返回的结果集
preparedStatement.setString(1, name);
ResultSet resultSet = preparedStatement.executeQuery();
//5.处理结果,遍历resultSet
while (resultSet.next()) {
int empId = resultSet.getInt("emp_id");
String empName = resultSet.getString("emp_name");
double empSalary = resultSet.getDouble("emp_salary");
int empAge = resultSet.getInt("emp_age");
System.out.println(empId+"\t"+empName+"\t"+empSalary+"\t"+empAge);
}
//6.释放资源
resultSet.close();
preparedStatement.close();
connection.close();
}
}
4.5 ResultSet 接口
只代表查询的结果
ORM:封装
五、基于 PreparedStatement 完成 CRUD,防止SQL 注入
5.1 查询单行单列
/**
* 单行单列
* @throws Exception
*/
@Test //引入测试
public void testQuerySingleRowAndCol() throws Exception {
//1.注册驱动
//2.获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "123456");
//3.预编译SQL语句,得到 PreparedStatement 对象
PreparedStatement preparedStatement = connection.prepareStatement("select count(*) as count from t_emp");
//4.执行SQL语句,获取结果
ResultSet resultSet = preparedStatement.executeQuery();
//5.处理结果(如果自己明确一定只有一个结果,那么 resultSet 最少要做一次 next的判断,才能拿到我们要的列的结果)
while(resultSet.next()) {
int count = resultSet.getInt("count");
System.out.println(count);
}
//6.释放资源
resultSet.close();
preparedStatement.close();
connection.close();
}
5.2 查询单行多列
/**
* 单行多列
* @throws Exception
*/
@Test
public void testQuerySingleRow() throws Exception {
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "123456");
//3.预编译SQL语句获得PreparedStatement对象
PreparedStatement preparedStatement = connection.prepareStatement("select * from t_emp where emp_id = ?");
//4.为占位符赋值,然后执行,并接收结果
preparedStatement.setInt(1,4);
ResultSet resultSet = preparedStatement.executeQuery();
//5.处理结果
while (resultSet.next()) {
int empId = resultSet.getInt("emp_id");
String empName = resultSet.getString("emp_name");
double empSalary = resultSet.getDouble("emp_salary");
int empAge = resultSet.getInt("emp_age");
System.out.println(empId + "\t" + empName + "\t" + empSalary + "\t" + empAge);
}
//6.释放资源
resultSet.close();
preparedStatement.close();
connection.close();
}
5.3 查询多行多列
/**
* 多行多列
* @throws Exception
*/
@Test
public void testQueryMoreRow() throws Exception {
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "123456");
//3.预编译SQL语句,获取PreparedStatement对象
PreparedStatement preparedStatement = connection.prepareStatement("select * from t_emp where emp_age > ?");
//4.为占位符赋值,然后执行,并获取结果
preparedStatement.setInt(1,25);
ResultSet resultSet = preparedStatement.executeQuery();
//5.处理结果
while(resultSet.next()){
int empId = resultSet.getInt("emp_id");
String empName = resultSet.getString("emp_name");
double empSalary = resultSet.getDouble("emp_salary");
int empAge = resultSet.getInt("emp_age");
System.out.println(empId + "\t" + empName + "\t" + empSalary + "\t" + empAge);
}
//6.释放资源
resultSet.close();
preparedStatement.close();
connection.close();
}
5.4 新增
/**
* 新增
* @throws Exception
*/
@Test
public void testInsert() throws Exception {
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "123456");
//3.预编译SQL语句,获取PreparedStatement对象
PreparedStatement preparedStatement = connection.prepareStatement("insert into t_emp(emp_name,emp_salary,emp_age) values (?,?,?)");
//4.为占位符赋值,然后执行,并获取结果
preparedStatement.setString(1,"rose");
preparedStatement.setDouble(2,345.67);
preparedStatement.setInt(3,28);
int result = preparedStatement.executeUpdate();
//5.处理结果
if(result > 0){
System.out.println("成功!");
} else {
System.out.println("失败!");
}
//6.释放资源
preparedStatement.close();
connection.close();
}
5.5 修改
/**
* 修改
* @throws Exception
*/
@Test
public void testUpdate() throws Exception {
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu","root","123456");
//3.预编译SQL语句,获取PreparedStatement对象
PreparedStatement preparedStatement = connection.prepareStatement("update t_emp set emp_salary = ? where emp_id = ?");
//4.为占位符赋值,然后执行,并获取结果
preparedStatement.setDouble(1,888.88);
preparedStatement.setInt(2,6);
//5.处理结果
int result = preparedStatement.executeUpdate();
if(result > 0){
System.out.println("成功!");
}else {
System.out.println("失败!");
}
//6.释放资源
preparedStatement.close();
connection.close();
}
5.6 删除
/**
* 删除
* @throws Exception
*/
@Test
public void testDelete() throws Exception {
//1.加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "123456");
//3.预编译SQL语句,获取PreparedStatement对象
PreparedStatement preparedStatement = connection.prepareStatement("delete from t_emp where emp_id = ?");
//4.为占位符赋值,然后执行,并获取结果
preparedStatement.setInt(1,6);
int result = preparedStatement.executeUpdate();
//5.处理结果
if (result>0){
System.out.println("成功!");
}else {
System.out.println("失败!");
}
//6.释放资源
preparedStatement.close();
connection.close();
}
六、常见问题
6.1 资源的管理
在使用 JDBC 的相关资源时,比如 Connection、PreparedStatement、ResultSet,使用完毕后,要及时关闭这些资源以释放数据库服务器资源和避免内存泄漏是很重要的。