当前位置: 首页 > news >正文

Spring 之声明式事务和 Spring Junit 案例应用详解

(感谢您的关注和点赞支持!) 

Spring-test

在前面测试中,每次从spring 容器中获取 bean 都需要实例化 ApplicationContext ,相对麻烦,可以考虑使用 Spring-test 完成测试

Spring Test 是 Spring Framework 提供的一系列测试支持工具,它为开发者提供了在单元测试和集成测试中模拟 Spring 上下文、依赖注入(DI)和事务管理的能力

添加依赖

pom.xml

<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring-version}</version>
</dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.8.2</version>
</dependency>

编写测试类

在 src/test/java 下

编写测试类

需要使用 注解 @SpringJUnitConfig

  • xml 方式:

    @SpringJUnitConfig(locations = "classpath:spring.xml")
    public class SpringTestJunit5{}
  • 注解方式:

    @SpringJUnitConfig(SpringTestJunit5.class)
    @ComponentScan("com.wdzl.anno")
    public class SpringTestJunit5{}
    如果是全注解,则@SpringJUnitConfig 传入配置扫描注解的类

测试配中配置依赖

SpringTestJunit5

@SpringJUnitConfig(locations = "classpath:spring.xml")
public class SpringTestJunit {@Autowiredprivate EmpService empService;@Testpublic void test(){}
}

全注解方式:

@SpringJUnitConfig(SpringTestJunit5.class)
@ComponentScan("com.wdzl.anno")
public class SpringTestJunit5 {@Autowiredprivate BookService bookService;@Testpublic void testAOP(){bookService.save();}
}

三、声明式事务

声明式事务(declarative transaction management)是Spring提供的对程序事务管理的方式之一。 Spring的声明式事务顾名思义就是采用声明的方式来处理事务

编写转账业务代码

package com.wdzl.service;import com.wdzl.dao.IEmpDao;
import com.wdzl.pojo.Emp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.List;@Service
public class EmpService {@Autowiredprivate IEmpDao empDao;public Emp get(Integer empno){return empDao.get(empno);}public List<Emp> queryAll(){return empDao.queryAll();}public void save(Emp emp){empDao.save(emp);}public void update(Emp emp){empDao.update(emp);}/*** 转账* @param fromId  转出账号* @param toId    转入账号* @param money   转账金额*/public void trans(Integer fromId,Integer toId,Float money){Emp fromEmp = get(fromId);Emp toEmp = get(toId);//内存修改fromEmp.setSalary(fromEmp.getSalary()-money);toEmp.setSalary(toEmp.getSalary()+money);// 持久化empDao.update(fromEmp);//假设异常
//        "".substring(9999);empDao.update(toEmp);}
}

写好后,正常测试,看是否在没有异常时能正常转账;

异常时,部分转账;出现不一致情况,并没回滚。

配置事务

两种常用方式

  • xml 配置
  • 注解

xml 配置方式

只需在spring 配置文件中修改

1. 配置事务管理器

依赖数据源,通过控制数据源来完成事务控制

<!--1. 事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/>
</bean>
2 . 配置 advice

注意:在idea中,配置 tx 命名空间时方法,敲入 <tx:advice> 自动提示,但是一定要注意,选择 tx 的命名空间,

不要选择 cache !!!!!!!!!

<tx:advice id="txadvice" transaction-manager="transactionManager"><tx:attributes><tx:method name="tra*" propagation="REQUIRED" /><tx:method name="*" propagation="SUPPORTS"/></tx:attributes>
</tx:advice>
  • propagation 事务的传播行为:
    • REQUIRED : 必须在事务中,如果方法执行时,已经在事务中,则继续使用当前事务;如果没有事务,则重新打开新的事务
    • SUPPORTS : 支持当前事务状态,如果在事务中,则执行当前事务。如果没有,不会新开启事务
    • REQUIRES_NEW : 每次都会重新开启新的事务
3. aop 配置
<aop:config><aop:pointcut id="xx" expression="execution(public * com.wdzl.service..*.*(..))"/><aop:advisor advice-ref="txadvice" pointcut-ref="xx"/>
</aop:config>

注意:上面配置,需要注入前面的 advice 和 切入点 id

4. 测试

通过上面配置,不需要修改任何代码的,直接正常测试调用就可以了

@SpringJUnitConfig(locations = "classpath:spring.xml")
public class SpringTestJunit {@Autowiredprivate EmpService empService;@Testpublic void test(){empService.trans(1,2,500);}
}

注解配置方式

1. 配置事务管理器

在 spring.xml 中配置

<!--1. 事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/>
</bean>
2. 开启声明式事务注解
<!--2.启用声明式事务注解-->
<tx:annotation-driven/>
3. 方法标注注解

在需要事务支持的方法标注注解 @Transactional

    @Transactional/*** 转账* @param fromId  转出账号* @param toId    转入账号* @param money   转账金额*/public void trans(Integer fromId,Integer toId,Float money){Emp fromEmp = get(fromId);Emp toEmp = get(toId);//内存修改fromEmp.setSalary(fromEmp.getSalary()-money);toEmp.setSalary(toEmp.getSalary()+money);// 持久化empDao.update(fromEmp);//假设异常
//        "".substring(9999);empDao.update(toEmp);}
}
4. 测试
@SpringJUnitConfig(SpringTestJunit5.class)
@ComponentScan("com.wdzl.anno")
public class SpringTestJunit5 {@Autowiredprivate EmpService empService;@Testpublic void testAOP(){empService.trans(1,2,500);}
}

相关文章:

  • Spring Boot: 使用MongoOperations操作mongodb
  • Vue+SpringBoot打造智慧家政系统
  • 机器学习之无监督学习简介及算法库推荐
  • 学点Java_Day6_基于Copyright和Actions On Save的IDEA自动更新文件最后编辑时间的方法研究(IDEA2021.2及以上)
  • 联想笔记本的声音键没有反应怎么办?
  • Selenium 学习(0.21)——软件测试之单元测试
  • C语言案例01, 输入两个整数,获得两个数加减乘除的值,持续更新中~
  • 【Spring Cloud】微服务通信概述
  • 【C语言】结构体内存对齐问题
  • <JavaEE> 了解网络层协议 -- IP协议
  • 从零到一构建短链接系统(八)
  • 通过jsDelivr实现Github的图床CDN加速
  • Rust常用库之序列化和反序列化库serde(使用 Serde 处理json)
  • Visual Studio 2022下配置 OpenMP 多线程编程环境与运行
  • java.lang.ClassNotFoundException: kotlin.jvm.internal.Intrinsics
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • 2018一半小结一波
  • 78. Subsets
  • android高仿小视频、应用锁、3种存储库、QQ小红点动画、仿支付宝图表等源码...
  • css的样式优先级
  • ECMAScript 6 学习之路 ( 四 ) String 字符串扩展
  • es6(二):字符串的扩展
  • k8s如何管理Pod
  • laravel5.5 视图共享数据
  • macOS 中 shell 创建文件夹及文件并 VS Code 打开
  • miaov-React 最佳入门
  • Node + FFmpeg 实现Canvas动画导出视频
  • Spark学习笔记之相关记录
  • 今年的LC3大会没了?
  • 聊聊directory traversal attack
  • 应用生命周期终极 DevOps 工具包
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • #define
  • #多叉树深度遍历_结合深度学习的视频编码方法--帧内预测
  • $GOPATH/go.mod exists but should not goland
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (done) 两个矩阵 “相似” 是什么意思?
  • (翻译)terry crowley: 写给程序员
  • (分布式缓存)Redis哨兵
  • (机器学习-深度学习快速入门)第三章机器学习-第二节:机器学习模型之线性回归
  • *_zh_CN.properties 国际化资源文件 struts 防乱码等
  • *++p:p先自+,然后*p,最终为3 ++*p:先*p,即arr[0]=1,然后再++,最终为2 *p++:值为arr[0],即1,该语句执行完毕后,p指向arr[1]
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)
  • .NET 2.0中新增的一些TryGet,TryParse等方法
  • .NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(准备篇)
  • .NET 常见的偏门问题
  • .net 验证控件和javaScript的冲突问题
  • .net 怎么循环得到数组里的值_关于js数组
  • .net反编译工具
  • .net项目IIS、VS 附加进程调试
  • .net专家(高海东的专栏)
  • /etc/shadow字段详解
  • @kafkalistener消费不到消息_消息队列对战之RabbitMq 大战 kafka
  • @Transactional 详解