Spring 核心技术解析【纯干货版】- IX:Spring 数据访问模块 Spring-Jdbc 模块精讲
在现代企业级应用中,数据访问层的稳定性和高效性至关重要。为了简化和优化数据库操作,Spring Framework 提供了 Spring-JDBC 模块,旨在通过高度封装的 JDBC 操作,简化开发者的编码负担,减少冗余代码,同时提升系统的健壮性和可维护性。Spring-JDBC 模块的核心组成之一,
JdbcTemplate
,是开发者在数据库交互中最常用的工具,它不仅大幅度减少了样板代码,还自动处理了事务和异常管理。本文将深入探讨 Spring-JDBC 模块的基本功能、核心组件以及事务管理机制,帮助开发者更好地理解和使用该模块,从而提升数据访问的效率与安全性。
文章目录
- 1、Spring-Jdbc 模块介绍
- 1.1、Spring-Jdbc 模块概述
- 1.2、Spring-Jdbc 模块依赖
- 1.3、Spring-Jdbc 模块作用
- 2、Spring-Jdbc 核心组件
- 2.1、配置文件和依赖
- 2.2、配置 Spring 容器
- 2.3、启动 Spring 容器
- 2.4、使用 `EmpDao` 类中的方法
- 3、Spring-Jdbc 事务管理
- 3.1、Spring JDBC 事务管理概述
- 3.2、使用 `@Transactional` 进行声明式事务管理
- 3.3、编程式事务管理
- 3.4、事务传播行为
- X、后记
1、Spring-Jdbc 模块介绍
1.1、Spring-Jdbc 模块概述
Spring JDBC 模块,是一个提供了对 JDBC 访问的高度抽象的模块,它简化了使用 JDBC 进行数据库操作的过程。
Spring JDBC 模块,它包含了一个 JdbcTemplate
类,该类封装了诸如查询、更新、事务处理等常用操作,使得编写数据库交互代码变得更加简洁且不易出错。JdbcTemplate
还能自动处理资源管理和异常翻译,提高了代码的健壮性。
1.2、Spring-Jdbc 模块依赖
Spring-Jdbc 模块的依赖有三个,分别是 Spring-Beans 模块、Spring-Core 模块和 Spring-Tx 模块。
其中 Spring Beans 模块是对 Spring Bean 进行定义,实现 IOC 基础功能的模块。Spring-Core 是 Spring 中的基础模块,它提供了框架运行所必需的核心功能。而 Spring Tx 模块,是 Spring 中处理事务管理的模块。
1.3、Spring-Jdbc 模块作用
Spring-JDBC 的主要作用:
- 简化 JDBC 操作:Spring-JDBC 提供了
JdbcTemplate
类,封装了 JDBC 的核心操作(如连接管理、SQL 执行、结果集处理等),开发者只需关注 SQL 语句和业务逻辑,无需手动处理资源管理(如关闭连接、结果集等)。 - 减少样板代码:传统的 JDBC 代码需要手动处理
Connection
、Statement
、ResultSet
等资源的创建和释放,容易出错且代码冗长。Spring-JDBC 通过模板方法模式,自动处理这些资源,减少了重复代码。 - 异常处理:Spring-JDBC 将 JDBC 的
SQLException
转换为 Spring 的DataAccessException
异常体系,提供了更清晰的异常层次结构,便于开发者处理数据库操作中的错误。 - 事务管理:Spring-JDBC 与 Spring 的事务管理模块无缝集成,支持声明式事务管理(通过注解或 XML 配置),简化了事务控制的实现。
- 支持多种数据库操作:除了基本的 CRUD 操作,Spring-JDBC 还支持批量操作、存储过程调用、复杂结果集映射等功能。
- 与 ORM 框架集成:Spring-JDBC 可以与其他 ORM 框架(如 Hibernate、MyBatis)结合使用,提供更灵活的数据访问方式。
2、Spring-Jdbc 核心组件
JdbcTemplate 为 Spring JDBC 的核心类,提供数据 CRUD 方法。本节介绍对于 JdbcTemplate 的使用。
2.1、配置文件和依赖
使用 Maven,确保在 pom.xml
中正确引入了相关的 Spring JDBC 和数据库连接池的依赖。例如:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.39</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.39</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>
2.2、配置 Spring 容器
首先,确保我们的 Spring 配置文件配置正确,并且已经引入了 Spring 的上下文和 JDBC 配置。例如:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/yourdb"/>
<property name="username" value="yourusername"/>
<property name="password" value="yourpassword"/>
</bean>
<!-- 配置JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置EmpDao -->
<bean id="empDao" class="com.example.EmpDao">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
</beans>
2.3、启动 Spring 容器
在 Spring 项目中,通常使用 ClassPathXmlApplicationContext
来加载配置文件并启动容器。我们可以在 main
方法中使用如下代码启动 Spring 容器:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
// 加载 Spring 配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("spring-bean.xml");
// 获取 EmpDao Bean 并调用方法
EmpDao empDao = (EmpDao) context.getBean("empDao");
// 调用 EmpDao 中的方法
empDao.addEmployee("John Doe", 30);
empDao.deleteEmployee(5);
}
}
2.4、使用 EmpDao
类中的方法
确保我们的 EmpDao
类已经正确配置了增删改查的方法,并且使用了 JdbcTemplate
。例如:
import org.springframework.jdbc.core.JdbcTemplate;
public class EmpDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void addEmployee(String name, int age) {
String sql = "INSERT INTO employee (name, age) VALUES (?, ?)";
jdbcTemplate.update(sql, name, age);
}
public void deleteEmployee(int id) {
String sql = "DELETE FROM employee WHERE id = ?";
jdbcTemplate.update(sql, id);
}
}
3、Spring-Jdbc 事务管理
Spring JDBC 提供了对事务管理的支持,使得数据库操作的事务管理更加简洁和统一。通过 Spring 的事务管理,我们可以在操作数据库时保证事务的一致性和原子性,避免数据的不一致性。
Spring 提供了两种事务管理机制:
- 编程式事务管理:通过代码显式地控制事务的开始、提交、回滚。
- 声明式事务管理:通过配置和注解(
@Transactional
)来实现自动的事务管理,Spring 会自动控制事务的开始、提交、回滚。
3.1、Spring JDBC 事务管理概述
Spring 提供了 DataSourceTransactionManager
来管理 JDBC 事务,它实现了 PlatformTransactionManager
接口,Spring 会通过该类来控制事务的生命周期。
- 事务的状态:通常有
begin
(开始)、commit
(提交)、rollback
(回滚)。 - 传播行为:事务的传播方式,决定了一个方法被调用时,当前事务的状态。
3.2、使用 @Transactional
进行声明式事务管理
最常用的方式是通过 @Transactional
注解实现声明式事务管理。Spring 会在方法执行前开启事务,执行完毕后提交事务。如果出现异常,事务会回滚。
例子:使用 @Transactional
注解
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;
public class EmpDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
// 使用 @Transactional 注解,声明式事务管理
@Transactional
public void addEmployeeAndDepartment(String empName, int empAge, String deptName) {
String addEmployeeSql = "INSERT INTO employee (name, age) VALUES (?, ?)";
jdbcTemplate.update(addEmployeeSql, empName, empAge);
String addDepartmentSql = "INSERT INTO department (name) VALUES (?)";
jdbcTemplate.update(addDepartmentSql, deptName);
// 模拟一个错误,事务应该回滚
if (empAge < 0) {
throw new RuntimeException("Invalid age");
}
}
}
在上面的例子中:
@Transactional
注解表示在addEmployeeAndDepartment
方法执行时,Spring 会自动管理事务。- 如果方法正常执行,事务会提交。
- 如果方法抛出异常,Spring 会自动回滚事务。
配置支持事务管理:
为了让 Spring 管理事务,我们需要在配置文件中启用事务管理器,并且确保 Spring 容器扫描事务管理相关注解。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 配置事务管理器 -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/yourdb"/>
<property name="username" value="yourusername"/>
<property name="password" value="yourpassword"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 开启事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
3.3、编程式事务管理
如果不想使用声明式事务,可以使用编程式事务管理。在这种方式中,我们需要显式地使用 PlatformTransactionManager
来控制事务。
例子:编程式事务管理
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
public class EmpDao {
private JdbcTemplate jdbcTemplate;
private PlatformTransactionManager transactionManager;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public void addEmployeeAndDepartment(String empName, int empAge, String deptName) {
// 创建事务定义
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
try {
String addEmployeeSql = "INSERT INTO employee (name, age) VALUES (?, ?)";
jdbcTemplate.update(addEmployeeSql, empName, empAge);
String addDepartmentSql = "INSERT INTO department (name) VALUES (?)";
jdbcTemplate.update(addDepartmentSql, deptName);
// 模拟一个错误,事务应该回滚
if (empAge < 0) {
throw new RuntimeException("Invalid age");
}
// 提交事务
transactionManager.commit(status);
} catch (Exception e) {
// 回滚事务
transactionManager.rollback(status);
throw e; // 抛出异常
}
}
}
在编程式事务管理中,我们需要手动创建事务定义(DefaultTransactionDefinition
),并使用 PlatformTransactionManager
来开始、提交或回滚事务。
3.4、事务传播行为
事务的传播行为决定了事务在多个方法调用之间如何传播。常见的传播行为有:
PROPAGATION_REQUIRED
:如果当前没有事务,则新建一个事务;如果已有事务,则加入当前事务(默认行为)。PROPAGATION_REQUIRES_NEW
:无论当前是否有事务,都会新建一个事务。PROPAGATION_NESTED
:支持事务嵌套。如果当前事务存在,则会在当前事务内开启一个子事务。
我们可以通过设置 @Transactional
注解的 propagation
属性来控制传播行为,例如:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void addEmployeeAndDepartmentWithNewTransaction(String empName, int empAge, String deptName) {
// 新建事务,独立于外部事务
}
X、后记
通过本文的讲解,我们深入了解了 Spring-JDBC 模块如何通过 JdbcTemplate
类,简化 JDBC 操作,并自动处理数据库连接、事务管理和异常翻译等繁琐任务。Spring-JDBC 不仅减轻了开发者的工作量,还能显著提高代码的可读性和可维护性。无论是常见的增删改查操作,还是复杂的事务控制,Spring-JDBC 都提供了极其简洁和灵活的解决方案。掌握这些核心技术,将为开发者带来更高效、可靠的数据库交互体验。希望大家能将本文中的知识点应用到实际开发中,不断优化和提升自己的技术水平。