1. 引言
1.1 数据的存储
我们在开发java程序时,数据都是存储在内存中,属于临时存储,当程序停止或重启时,内存中的数据就丢失了!我们为了解决数据的长期存储问题,有如下方案:
-
数据通过I/O流技术,存储在本地磁盘中,解决了持久化问题,但是没有结构和逻辑,不方便管理和维护。
-
通过关系型数据库,将数据按照特定的形式交给数据库管理系统维护。关系型数据库是通过库和表分隔不同的数据,表中数据存储的方式是行和列,区分相同格式不同值的数据。
2. JDBC
2.1 JDBC的概念
-
JDBC:Java Database Connectivity,意为Java数据库连接
-
JDBC是java提供的一组独立于任何数据库管理系统的API
-
Java提供接口规范,由各个数据库厂商提供接口的实现,厂商提供的实现类封装成jar文件,也就是我们俗称的数据库驱动jar包
-
学习JDBC,充分体现了面向接口编程的好处,程序只关心标准和规范,而无需关注实现过程
2.2 快速入门
package com.mdklea.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("com.mysql.cj.jdbc.Driver");
//2. 获取连接对象
String url = "jdbc:mysql://localhost:3306/atguigu";
String username = "root";
String password = "111111";
Connection connection = DriverManager.getConnection(url, username, password);
//3. 获取执行SQL语句的对象
Statement statement = connection.createStatement();
//4. 编写SQL语句,并执行,接受返回的结果集
String sql = "SELECT emp_id,emp_name,emp_salary,emp_age FROM t_emp";
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();
}
}
3. 核心API理解
3.1 注册驱动
-
Class.forname("com.mysql.cj.jdbc.Driver");
-
在java类中,当使用JDBC连接数据库时,需要加载数据库特定的驱动程序,以便于数据进行通信,加载驱动程序的目的是为了注册驱动程序,使得JDBC API能够识别并与特定的数据库进行交互
-
从JDK6开始,不再需要显示地调用Class.forname() 来加载JDBC驱动程序,只要在类路径中继承了对应的jar文件,会自动在初始化时注册驱动程序。
3.2 Connection
-
Connection 接口是JDBC API的重要接口,用于建立与数据库的通信通道,换而言之,Connection对象不为空,则代表一次数据库连接。
-
在建立连接时,需要制定数据库URL、用户名、密码参数。
-
URL:jdbc:mysql://localhost:3306/atguigu
-
jdbc:mysql://IP地址:端口号/数据库名称?参数键值对1&参数键值对2
-
-
-
Connection 接口还负责管理事务,Connection接口提供了commit和rollback方法,用于提交事务和回滚事务、
-
可以创建Statement对象,用于执行SQL语句并于数据库进行交互。
-
再使用JDBC技术时,必须要先获取Connection对象,在使用完毕后,要释放资源,避免资源占用浪费及泄露
3.3 Starement
-
Statement 接口用于执行SQL语句并与数据库进行交互,它是JDBC API 中的一个重要接口。通过Statement 对象,可以向数据库发送SQL语句并获取执行结果。
-
结果可以是一个或多个结果。
-
增删改:收影响行数单个结果。
-
查询:单行单列、多行多列、单行多列等结果。
-
-
但是Statement 接口在执行SQL语句时,会产生SQL注入攻击问题:
-
当使用Statement 执行动态构建SQL查询时,往往需要将查询条件与SQL语句拼接到一起,直接将参数和SQL语句一并生成,让SQL的查询条件始终未true得到结果。
-
3.4 PreparedStatement
-
PreparedStatement 是 Statement 接口的子接口,用于执行 预编译 的SQL查询 作用如下:
-
预编译SQL语句:在创建PreparedStatement时,就会预编译SQL语句,也就是SQL语句已经固定
-
防止SQL注入:preparedStatement支持参数化查询,将数据作为参数传递到SQL语句中,采用?占位符的方式,将传入的参数用一对单引号包裹起来,无论传递什么都作为值。有效防止传入关键字或值导致SQL注入问题。
-
性能提升:PreparedStatement是预编译SQL语句,同一SQL语句多次执行的情况下,可以复用,不必每次重新编译和解析。
-
-
后续的学习我们是基于PreparedStatement进行实现,更安全,效率更高!
3.5 ResultSet
-
ResultSet是JDBC API 中的一个接口,用于表示从数据库中执行查询语句所返回的结果集,它提供了一种用于遍历和访问查询结果的方式。
-
遍历结果:ReslutSet可以使用next() 方法将游标移动到结果集的下一行,逐行遍历数据库查询的结果,返回值为boolean类型,true代表由下一行结果,false则代表没有。
-
获取单列结果:可以通过 getXxx的方法获取单列的数据,该方法为重载方法,支持索引和列名进行获取。
4. 基于PreparedStatement实现CRUD
4.1 查询单行单列
@SuppressWarnings({"all"})
@Test
public void testQuerySingleRowAndCol() throws SQLException {
//1. 注册驱动 可以省略
DriverManager.registerDriver(new Driver());
//2. 获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "111111");
//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();
}
}
4.2 查询单行多列
@SuppressWarnings({"all"})
@Test
public void testQuerySingleRow() throws SQLException {
//1. 注册驱动
DriverManager.registerDriver(new Driver());
//2. 获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "111111");
//3. 获取SQL语句得到PreparedStatement对象
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM t_emp WHERE emp_id = ?");
//4. 执行SQL语句,获取结果
preparedStatement.setInt(1,3);
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();
}
4.3 查询多行多列
@SuppressWarnings({"all"})
@Test
public void testQueryMoreRow() throws SQLException {
//1. 注册驱动(可省略)
//2. 获取连接
Connection connection = DriverManager.getConnection
("jdbc:mysql:///atguigu","root","111111");
//3. 获取SQL语句得到PreparedStatement 对象
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM t_emp WHERE emp_age > ?");
//4. 执行SQL语句,获取结果
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();
}
4.4 插入数据
@SuppressWarnings({"all"})
@Test
public void testInsert() throws SQLException {
//1. 注册驱动
//2. 获取sql语句得到preparedStatement 对象
Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu","root","111111");
//3. 执行SQL语句,获取结果
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO t_emp (emp_name, emp_salary, emp_age) VALUES (?,?,?)");
//4. 执行SQL语句,获取结果
preparedStatement.setString(1,"MiloK");
preparedStatement.setDouble(2,8888.8);
preparedStatement.setInt(3,20);
int result = preparedStatement.executeUpdate();
if (result > 0 ) {
System.out.println("成功");
}else {
System.out.printf("失败");
}
//6. 释放资源
preparedStatement.close();
connection.close();
}
4.5 改变数据
@SuppressWarnings({"all"})
@Test
public void testUpdate() throws SQLException {
Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu","root","111111");
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE t_emp SET emp_name = ? WHERE emp_id = ?");
preparedStatement.setString(1,"mdk");
preparedStatement.setInt(2,1);
int result = preparedStatement.executeUpdate();
if (result > 0) {
System.out.println("成功");
} else {
System.out.println("失败");
}
preparedStatement.close();
connection.close();
}
4.6 删除数据
@SuppressWarnings({"all"})
@Test
public void testDelete() throws SQLException {
Connection connection = DriverManager.getConnection
("jdbc:mysql:///atguigu","root","111111");
PreparedStatement preparedStatement = connection.prepareStatement("DELETE FROM t_emp WHERE emp_id = ?");
preparedStatement.setInt(1,3);
int result = preparedStatement.executeUpdate();
if (result > 0) {
System.out.println("成功");
}else {
System.out.println("失败");
}
preparedStatement.close();
connection.close();
}