
在 Java Web 开发中,Spring 框架提供了强大的事务管理功能,能够帮助开发者轻松处理数据库事务。声明式事务是 Spring 事务管理的一种重要方式,它允许我们通过注解或 XML 配置来定义事务,而不需要在业务代码中手动编写事务管理的代码,从而提高了代码的可维护性和可复用性。本文将详细介绍如何使用注解和 XML 配置来实现声明式事务,并给出相应的演示代码。
声明式事务是基于 AOP(面向切面编程)实现的,它将事务管理的逻辑从业务逻辑中分离出来。在 Spring 中,声明式事务可以通过两种方式进行配置:注解和 XML。
注解配置事务是一种更为简洁和直观的方式,通过在方法或类上添加 @Transactional 注解来声明事务。
XML 配置事务则是通过在 Spring 的配置文件中定义事务管理器和事务切面,然后将它们应用到需要事务管理的方法上。
在开始之前,我们需要确保项目中已经引入了 Spring 框架和相关的依赖。这里以 Maven 为例,在 pom.xml 中添加以下依赖:
<dependencies><!-- Spring 核心 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.23</version></dependency><!-- Spring JDBC --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.23</version></dependency><!-- MySQL 驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.26</version></dependency></dependencies>
假设我们有一个简单的 users 表,用于存储用户信息:
CREATE TABLE users (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50) NOT NULL,balance DECIMAL(10, 2) NOT NULL);
创建一个 User 实体类来映射数据库表:
public class User {private Integer id;private String name;private Double balance;// 构造方法、Getter 和 Setter 省略}
创建一个 UserDao 接口和实现类,用于操作 users 表:
import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Repository;@Repositorypublic class UserDao {private JdbcTemplate jdbcTemplate;public UserDao(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}public void updateBalance(int userId, double amount) {String sql = "UPDATE users SET balance = balance +? WHERE id =?";jdbcTemplate.update(sql, amount, userId);}}
创建一个 UserService 类,使用 @Transactional 注解来声明事务:
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;@Servicepublic class UserService {@Autowiredprivate UserDao userDao;@Transactionalpublic void transferMoney(int fromUserId, int toUserId, double amount) {// 扣除转出用户的余额userDao.updateBalance(fromUserId, -amount);// 模拟异常if (amount > 100) {throw new RuntimeException("转账金额不能超过 100");}// 增加转入用户的余额userDao.updateBalance(toUserId, amount);}}
创建一个 Spring 配置类,启用注解事务管理:
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.jdbc.datasource.DriverManagerDataSource;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.sql.DataSource;@Configuration@ComponentScan(basePackages = "com.example")@EnableTransactionManagementpublic class AppConfig {@Beanpublic DataSource dataSource() {DriverManagerDataSource dataSource = new DriverManagerDataSource();dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setUrl("jdbc:mysql://localhost:3306/test");dataSource.setUsername("root");dataSource.setPassword("password");return dataSource;}@Beanpublic JdbcTemplate jdbcTemplate(DataSource dataSource) {return new JdbcTemplate(dataSource);}}
编写一个测试类来验证事务是否正常工作:
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = context.getBean(UserService.class);try {userService.transferMoney(1, 2, 50);System.out.println("转账成功");} catch (Exception e) {System.out.println("转账失败:" + e.getMessage());}context.close();}}
创建一个 applicationContext.xml 配置文件,配置数据源、事务管理器和事务切面:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 数据源 --><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/test"/><property name="username" value="root"/><property name="password" value="password"/></bean><!-- JdbcTemplate --><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"/></bean><!-- 事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><!-- 启用事务注解 --><tx:annotation-driven transaction-manager="transactionManager"/><!-- 扫描组件 --><context:component-scan base-package="com.example"/></beans>
修改测试代码,使用 XML 配置文件来加载 Spring 上下文:
import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Main {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = context.getBean(UserService.class);try {userService.transferMoney(1, 2, 50);System.out.println("转账成功");} catch (Exception e) {System.out.println("转账失败:" + e.getMessage());}((ClassPathXmlApplicationContext) context).close();}}
| 配置方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 注解配置 | 简洁直观,代码侵入性小,易于维护 | 配置信息分散在代码中,不利于统一管理 | 小型项目或对代码简洁性要求较高的项目 |
| XML 配置 | 配置信息集中,便于统一管理和维护 | 配置文件较为繁琐,代码侵入性大 | 大型项目或需要统一管理事务配置的项目 |
声明式事务是 Spring 框架提供的一种强大的事务管理方式,通过注解或 XML 配置可以轻松实现事务的管理。注解配置适合小型项目,而 XML 配置则更适合大型项目。在实际开发中,我们可以根据项目的具体需求选择合适的配置方式。通过本文的示例代码,相信你已经掌握了如何使用注解和 XML 配置来实现声明式事务。