JDBC 进阶
一 实体类和ORM
对指定的对象的属性封装
package com.ax.advance.pojo;
public class Employee {
private Integer id;
private String degree;
private String major;
private String school1;
private String school2;
private String school3;
private Integer userId;
public Employee(Integer id, String degree, String major, String school1, String school2, String school3, Integer userId) {
this.id = id;
this.degree = degree;
this.major = major;
this.school1 = school1;
this.school2 = school2;
this.school3 = school3;
this.userId = userId;
}
public Employee() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDegree() {
return degree;
}
public void setDegree(String degree) {
this.degree = degree;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
public String getSchool1() {
return school1;
}
public void setSchool1(String school1) {
this.school1 = school1;
}
public String getSchool2() {
return school2;
}
public void setSchool2(String school2) {
this.school2 = school2;
}
public String getSchool3() {
return school3;
}
public void setSchool3(String school3) {
this.school3 = school3;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", degree='" + degree + '\'' +
", major='" + major + '\'' +
", school1='" + school1 + '\'' +
", school2='" + school2 + '\'' +
", school3='" + school3 + '\'' +
", userId=" + userId +
'}';
}
}
数据封装在对象当中
package com.ax.advance;
import com.ax.advance.pojo.Employee;
import java.sql.*;
public class JDBCa {
public static void main(String[] args) throws SQLException {
//获取连接对象
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/itheima", "root", "tan2179432748");
//预编译SQL语句
PreparedStatement preparedStatement = connection.prepareStatement("select * from tb_user_edu where degree = ?");
//为问号占位符赋值,并执行SQL语句,接收返回的结果集
preparedStatement.setString(1, "本科");
//处理结果集
ResultSet resultSet = preparedStatement.executeQuery();
//遍历结果集
Employee employee = null;
while (resultSet.next()) {
int id = resultSet.getInt("id");
String degree = resultSet.getString("degree");
String major = resultSet.getString("major");
String primaryschool = resultSet.getString("primaryschool");
String middleschool = resultSet.getString("middleschool");
String university = resultSet.getString("university");
int userId = resultSet.getInt("userid");
//封装对象
employee = new Employee(id, degree, major, primaryschool, middleschool, university, userId);
System.out.println(employee);
}
//资源的释放(先开后放)
resultSet.close();
preparedStatement.close();
connection.close();
}
}
对象再封装在集合当中
package com.ax.advance;
import com.ax.advance.pojo.Employee;
import java.sql.*;
import java.util.ArrayList;
public class JDBCb {
public static void main(String[] args) throws SQLException {
//获取连接对象
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/itheima", "root", "tan2179432748");
//预编译SQL语句
PreparedStatement preparedStatement = connection.prepareStatement("select * from tb_user_edu where degree = ?");
//为问号占位符赋值,并执行SQL语句,接收返回的结果集
preparedStatement.setString(1, "本科");
//处理结果集
ResultSet resultSet = preparedStatement.executeQuery();
//创建集合存储对象
ArrayList<Employee> employees = new ArrayList<>();
//遍历结果集
Employee employee = null;
while (resultSet.next()) {
employee = new Employee();
employee.setId(resultSet.getInt("id"));
employee.setDegree(resultSet.getString("degree"));
employee.setMajor(resultSet.getString("major"));
employee.setSchool1(resultSet.getString("primaryschool"));
employee.setSchool2(resultSet.getString("middleschool"));
employee.setSchool3(resultSet.getString("university"));
employee.setUserId(resultSet.getInt("userid"));
employees.add(employee);
}
//输出
employees.forEach(System.out::println);
}
}
二 主键回显
主键回显指在数据库插入操作后,自动获取数据库生成的主键值(如自增ID、序列值等),并将其回填到程序中的对象或变量中。其核心目的是解决多表关联插入时主键依赖问题,例如:主表插入后需获取自增ID,才能将子表数据的外键关联到该ID
实现目的:有效地处理自动生成的主键值
代码实现
package com.ax.advance;
import com.ax.advance.pojo.Employee2;
import java.sql.*;
public class JDBCc {
public static void main(String[] args) throws SQLException {
// 获取连接对象
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/itheima", "root", "tan2179432748");
// 预编译SQL语句并设置返回主键
PreparedStatement preparedStatement =
connection.prepareStatement("insert into ax_new (name, school, age) values (?,?,?)",
Statement.RETURN_GENERATED_KEYS);
//创建对象
Employee2 employee2 = new Employee2(null, "张三", "清华大学", 20);
preparedStatement.setString(1, employee2.getName());
preparedStatement.setString(2, employee2.getSchool());
preparedStatement.setInt(3, employee2.getAge());
// 执行SQL语句,返回受影响的行数(这里已经添加了,主键是自动增长的)
int i = preparedStatement.executeUpdate();
ResultSet resultSet = null;
// 判断是否添加成功
if (i > 0) {
System.out.println("添加成功");
//获取当前新增数据的主键列,回显到Java封装的对象Employee2的id属性中,返回结果放在ResultSet中
resultSet = preparedStatement.getGeneratedKeys();
while (resultSet.next()) {
employee2.setId(resultSet.getInt(1));
}
System.out.println(employee2);
} else {
System.out.println("添加失败");
}
//释放资源
if (resultSet != null) {
resultSet.close();
}
preparedStatement.close();
connection.close();
}
}
三 批量操作
通过合理使用JDBC批量操作,可显著减少网络往返和数据库负载,提升应用性能。
JDBC的批量操作允许一次性执行多个SQL语句,显著提升数据库操作的效率,尤其适用于大量数据插入、更新或删除的场景。
代码实现:
package com.ax.advance;
import java.sql.*;
public class JDBCd {
public static void main(String[] args) throws SQLException {
//获取连接对象
Connection connection = DriverManager.
getConnection("jdbc:mysql://localhost/itheima?rewriteBatchedStatements=True", "root", "tan2179432748");
// 预编译SQL语句
PreparedStatement preparedStatement = connection.prepareStatement("insert into ax_new (name, school, age) values (?,?,?)");
for (int i = 0; i < 10; i++){
preparedStatement.setString(1, "ax" + i);
preparedStatement.setString(2, "清华大学" + i);
preparedStatement.setInt(3, i);
// 添加到批处理中
preparedStatement.addBatch();
}
//执行批处理
preparedStatement.executeBatch();
//资源释放
preparedStatement.close();
connection.close();
}
}
四 连接池
DBC连接池是一种管理和复用数据库连接的技术,旨在减少频繁创建/关闭连接的开销,提升应用性能。(在每次操作数据库都要获取新连接,使用完毕就close释放,频繁的创建和销毁造成资源浪费,连接的数量无法把控对服务器来说压力巨大。)
-
传统JDBC连接的缺点:
-
高开销:每次操作都新建连接,涉及网络握手、身份验证等耗时操作。
-
资源浪费:频繁开关连接会导致数据库负载过高。
-
难以应对高并发:大量并发请求时,频繁创建连接会导致性能瓶颈。
-
-
连接池的核心思想:
-
预创建连接:初始化时创建一定数量的连接,放入“池”中。
-
复用连接:应用从池中借用连接,用完后归还(而非关闭)。
-
动态管理:根据负载动态调整池中的连接数量。
-
常见连接池:
1 Druid连接池的使用
硬编码
package com.ax.advance.pool;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import org.junit.jupiter.api.Test;
import java.sql.SQLException;
public class DruidTest {
@Test
public void testHardCodeDruid() throws SQLException {
//创建DruidDataSource对象
DruidDataSource druidDataSource = new DruidDataSource();
//设置连接池的配置信息
//必须
druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
druidDataSource.setUrl("jdbc:mysql://localhost/itheima");
druidDataSource.setUsername("root");
druidDataSource.setPassword("tan2179432748");
//非必须
druidDataSource.setInitialSize(10);
druidDataSource.setMaxActive(20);
//通过连接池获取连接对象
DruidPooledConnection connection = druidDataSource.getConnection();
//基于connection进行CRUD
//回收连接对象(将连接归还给连接池,而不是释放资源)
connection.close();
}
}
软编码(不基于maven管理工具)
代码实现:
@Test
public void testResourcesDruid() throws Exception {
// 创建Properties集合,用于存储连接池的配置信息(key和value)
// Properties 是 Java 中用来处理属性文件的一个类,通常用于加载配置文件中的键值对。
Properties properties = new Properties();
// 读取外部配置文件,获取输入流,加载到Properties集合中
// 使用ClassLoader的getResourceAsStream方法来获取资源的输入流,这样可以确保在任何环境下都能正确找到资源文件。
// "db.properties" 是一个典型的数据库连接属性文件,其中包含了数据库驱动、URL、用户名、密码等信息。
InputStream inputStream = DruidTest.class.getClassLoader().getResourceAsStream("db.properties");
properties.load(inputStream); // 加载输入流中的内容到Properties对象中
// 创建DruidDataSource对象
// Druid是一个高效的数据库连接池实现,通过传递Properties对象给createDataSource方法,
// 我们可以初始化一个包含所有必要配置的连接池。
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
// 通过连接池获取连接对象
// getConnection 方法从连接池中获取一个可用的数据库连接,这比直接创建新的数据库连接更加高效。
Connection connection = dataSource.getConnection();
System.out.println(connection); // 输出连接对象,通常是调试用
// 基于connection进行CRUD操作
// 这里可以根据需要执行查询、插入、更新或删除操作。具体实现依赖于业务逻辑需求。
// 回收连接对象(将连接归还给连接池,而不是释放资源)
// 调用close方法并不是真的关闭连接,而是将连接返回到连接池中,以便后续使用。
connection.close();
}