news 2026/5/16 1:22:16

基于注解方式的声明式事务管理(黑马程序员Java EE企业级应用开发教程(Spring+Spring MVC+MyBatis)(第3版)学习笔记)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于注解方式的声明式事务管理(黑马程序员Java EE企业级应用开发教程(Spring+Spring MVC+MyBatis)(第3版)学习笔记)

基于注解方式的声明式事务管理介绍

简单来说就是使用配置文件来完成相关配置步骤繁琐,代码冗余(基于XML相关知识可以查看我的上一篇文章),可读性降低等等缺点,为了 解决这些问题可以使用注解的方法来简化操作

@Transactional注解的相关属性

实例代码

这次代码将基于上一篇文章的基础进行修改,代码会附在文章之后

1.创建配置文件applicationContext-annotation.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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--包扫描--> <context:component-scan base-package="com.noxuwdy"/> <!--配置数据源--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="password" value="123456"/> <property name="username" value="root"/> <property name="url" value="jdbc:mysql://localhost:3306/spring"/> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> </bean> <!--配置事务管理器 关联数据源--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--配置事务注解驱动--> <tx:annotation-driven/> </beans>

注意这里配置事务注解驱动时候要选对,要在"tx"中的annotation-driven

我们可以对比一下使用基于XML的配置文件

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--包扫描--> <context:component-scan base-package="com.noxuwdy"/> <!--数据源配置--> <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/spring"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean> <!--配置事务管理器 关联数据源--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--配置通知,对事务进行增强(通知)--> <!--这里的tx引入的包是tx结尾不是catch--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!--配置事务参数--> <tx:attributes> <!--name 表示管理的方法 * 表示都管 propagation表示传播行为 isolation 表示隔离级别 read-only 表示只读--> <tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/> </tx:attributes> </tx:advice> <!--AOP配置切入点和切面--> <aop:config> <aop:pointcut id="txPointCut" expression="execution(* com.noxuwdy.dao.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/> </aop:config> </beans>

很明显就可以看出来注解方式要简洁很多

2.创建dao层接口(详情见上一篇文章)

package com.noxuwdy.dao; import com.noxuwdy.pojo.Account; import java.util.List; import java.util.Map; public interface AccountDao { //添加单个账户信息 public void addAccount(Account account); //根据ID查找用户信息 public Account queryAccount(int id); //批量添加用户] public void addAccountList(List<Account> list); //查询所有账户 public List<Account> queryAccountList(); //根据id查询账户信息,将信息封装到Map中 public Map<String,Object> queryAccountMap(int id); //修改账户信息 public void updateAccount(Account account); //删除用户 public void deleteAccount(int id); //实现转账业务 public void transfer(String outUser ,String inUser,Double money); }

3.创建dao的实现类并添加注解

package com.noxuwdy.dao; import com.noxuwdy.pojo.Account; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.List; import java.util.Map; @Repository//交给Spring管理 持久层文件标记 public class AccountDaoImpl implements AccountDao{ //添加用户信息 @Autowired private JdbcTemplate jdbcTemplate; @Override public void addAccount(Account account) { String sql = "insert into account(username,balance) values(?,?)"; Object[] obj =new Object[]{account.getUsername(),account.getBalance()}; jdbcTemplate.update(sql,obj); } @Override public Account queryAccount(int id) { String sql = "select id ,username,balance from account where id=?"; Account account = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Account.class), id); return account; } @Override public void addAccountList(List<Account> list) { String sql = "insert into account(username,balance) values(?,?)"; List<Object[]> objs =new ArrayList<>(); for (Account account : list) { objs.add(new Object[]{ account.getUsername(), account.getBalance() }); } //批量完成添加操作 jdbcTemplate.batchUpdate(sql,objs); } @Override public List<Account> queryAccountList() { String sql = "select * from account"; List<Account> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Account.class)); return query ; } @Override public Map<String, Object> queryAccountMap(int id) { String sql = "select * from account where id=?"; Map<String, Object> map = jdbcTemplate.queryForMap(sql, id); return map; } @Override public void updateAccount(Account account) { String sql = "update account set username=?,balance=? where id=?"; Object[] obj =new Object[]{account.getUsername(),account.getBalance(),account.getId()}; jdbcTemplate.update(sql,obj); } @Override public void deleteAccount(int id) { String sql = "delete from account where id=?"; Object[] obj =new Object[]{id}; jdbcTemplate.update(sql,obj); } /** * 实现转账业务 * @param outUser 汇款人 * @param inUser 收款人 * @param money 转账数额 */ @Override @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,readOnly = false) public void transfer(String outUser, String inUser, Double money) { //汇款时 汇款账户余额= 现有金额-转账金额 jdbcTemplate.update("update account set balance=balance-? where username=?",money,outUser); //模拟系统运行时出现突发状态(转账一半出现问题) int i= 1/0; //首款时 收款账户余额 = 现有余额+转账金额 jdbcTemplate.update("update account set balance=balance+? where username=?",money,inUser); } // }

这里只对transfer(转账)方法进行了注解

4.创建测试类

import com.noxuwdy.dao.AccountDao; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; @SpringJUnitConfig(locations = "classpath:applicationContext-annotation.xml") public class TransactionTest { @Autowired private AccountDao accountDao; @Test public void testTransfer() { accountDao.transfer("Noxuswdy","wenjing",100.0); } }

5.进行测试

我们在接口实现类中模拟了出现意外情况终止的代码

所以如果我们代码执行前和执行后数据没有发生变化则进行了事务回滚证明我们的代码没问题

测试前

测试后

可以看到控制台出现了我们预留的模拟错误测试前后也没有变化

至此证明代码没有问题

总结

基于注解方式的声明式事务管理方法,相比XML配置更加简洁高效。通过@Transactional注解实现事务控制,重点演示了转账业务的事务处理。文章详细展示了配置文件的简化过程(applicationContext-annotation.xml)、DAO层实现类的注解使用(特别是transfer方法的@Transactional配置),以及测试验证过程。测试中通过模拟异常验证了事务回滚功能,证明注解方式能有效管理事务。这种方法避免了XML配置的繁琐,提高了代码可读性和开发效率。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/16 1:21:55

通信工程不是修宽带!3条黄金出路,认准这一个最稳

很多通信工程的大学生&#xff0c;从入学开始就被一句话困住&#xff1a;学通信&#xff0c;毕业是不是只能爬基站、装宽带、修手机&#xff1f;真的别再被老思想误导了&#xff01;现在5G全面深耕落地&#xff0c;6G加速研发布局&#xff0c;物联网、车联网、自动驾驶全行业爆…

作者头像 李华
网站建设 2026/5/16 1:21:13

PPTTimer终极指南:Windows演示时间管理的免费开源解决方案

PPTTimer终极指南&#xff1a;Windows演示时间管理的免费开源解决方案 【免费下载链接】ppttimer 一个简易的 PPT 计时器 项目地址: https://gitcode.com/gh_mirrors/pp/ppttimer 在重要的演示、会议或培训中&#xff0c;时间控制往往成为成功的关键。你是否曾在演讲时频…

作者头像 李华
网站建设 2026/5/16 1:17:05

**降本增效两不误:精细化运维助力业务持续增长**

降本增效两不误&#xff1a;精细化运维助力业务持续增长 作者&#xff1a;美玲 FAQ Q1&#xff1a;为什么传统监控工具难以应对跨区域IT架构&#xff1f; 传统工具多为孤立系统&#xff0c;缺乏统一数据模型和分布式采集能力&#xff0c;导致各分支机构监控数据割裂、告警响应滞…

作者头像 李华
网站建设 2026/5/16 1:14:03

基于Arduino的红外收发器板:从原理到实践的万能遥控中枢制作

1. 项目概述&#xff1a;打造你的万能红外遥控中枢红外遥控&#xff0c;这个我们每天用来开关电视、调节空调的技术&#xff0c;背后其实是一套相当精巧的无线通信系统。它利用人眼不可见的红外光脉冲来编码指令&#xff0c;成本低、抗干扰好&#xff0c;是物联网和智能家居项目…

作者头像 李华
网站建设 2026/5/16 1:12:32

GBase 8c 在过程里记流水时要小心自治事务边界

GBase 8c 在过程里记流水时要小心自治事务边界 我最近看 GBase 8c 自治事务资料时&#xff0c;觉得它特别适合拿来讨论一个开发现场经常遇到的问题&#xff1a;业务过程失败了&#xff0c;排障流水也跟着回滚了。等真正去查问题时&#xff0c;只剩应用日志里几行模糊报错&#…

作者头像 李华
网站建设 2026/5/16 1:11:04

RS®Forum远程控制工具:提升测试测量自动化效率

1. R&SForum远程控制工具概述R&SForum是罗德与施瓦茨(Rohde & Schwarz)公司推出的免费仪器远程控制脚本工具&#xff0c;专为测试测量工程师设计。这个工具完美融合了SCPI命令的直接控制与Python脚本的编程灵活性&#xff0c;能够显著提升射频测试、信号分析等场景…

作者头像 李华