Spring事务管理 -- Spring快速入门保姆级教程(五)(1)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS MySQL,高可用系列 2核4GB
简介: Spring事务管理 -- Spring快速入门保姆级教程(五)

前言

为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚,文章中如果有记录错误,欢迎读者朋友们批评指正。

(博客的参考源码可以在我主页的资源里找到,如果在学习的过程中有什么疑问欢迎大家在评论区向我提出)

六、Spring事务

1.Spring事务简介

一个数据库事务是一个被视为单一的工作单元的操作序列。这些操作应该要么完整地执行,要么完全不执行。事务管理是一个重要组成部分,RDBMS 面向企业应用程序,以确保数据完整性和一致性。事务的概念可以描述为具有以下四个关键属性说成是 ACID:

原子性:事务应该当作一个单独单元的操作,这意味着整个序列操作要么是成功,要么是失败的。
一致性:这表示数据库的引用完整性的一致性,表中唯一的主键等。
隔离性:可能同时处理很多有相同的数据集的事务,每个事务应该与其他事务隔离,以防止数据损坏。
持久性:一个事务一旦完成全部操作后,这个事务的结果必须是永久性的,不能因系统故障而从数据库中删除。

一个真正的 RDBMS 数据库系统将为每个事务保证所有的四个属性。使用 SQL 发布到数据库中的事务的简单视图如下:

使用 begin transaction 命令开始事务。
使用 SQL 查询语句执行各种删除、更新或插入操作。
如果所有的操作都成功,则执行提交操作,否则回滚所有操作。

Spring 框架在不同的底层事务管理 APIs 的顶部提供了一个抽象层。Spring 的事务支持旨在通过添加事务能力到 POJOs 来提供给 EJB 事务一个选择方案。Spring 支持编程式和声明式事务管理。EJBs 需要一个应用程序服务器,但 Spring 事务管理可以在不需要应用程序服务器的情况下实现,实现接口及实现类如下:

2.入门案例–模拟银行间转账业务

  1. 案例需求以及实现思路

  1. 环境准备
  • 创建数据库表tbl_account

建表查询语句示例

create database spring_db;
use spring_db;
drop table if exists tbl_account;
create table tbl_account(
  id int primary key auto_increment,
  name varchar(20),
  money varchar(20)
);
INSERT INTO tbl_account VALUES (1, 'Tom', 1000);
INSERT INTO tbl_account VALUES (2, 'Jerry', 1000);

效果

  • 在pom.xml文件中导入坐标
<dependencies>
    //spring框架
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>
    //druid数据源
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.16</version>
    </dependency>
    //mybatisa框架
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.6</version>
    </dependency>
    //数据库连接
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.47</version>
    </dependency>
    //spring操作jdbc
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>
    //spring整合mybatis
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.0</version>
    </dependency>
    //spring整合junit单元测试
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    //单元测试
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>
  </dependencies>
  • 创建spring全局配置文件SpringConfig
@Configuration
 @ComponentScan("com.itheima")
 @PropertySource("classpath:jdbc.properties")
 @Import({JdbcConfig.class,MybatisConfig.class})
 //开启注解式事务驱动
 @EnableTransactionManagement
 public class SpringConfig {
 }
  • 创建数据库信息文件jdbc.properties,填写数据库连接信息
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db?useSSL=false
jdbc.username=root
jdbc.password=root
  • 创建数据库连接配置类JdbcConfig
public class JdbcConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String userName;
    @Value("${jdbc.password}")
    private String password;
    @Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(userName);
        ds.setPassword(password);
        return ds;
    }
    //配置事务管理器,mybatis使用的是jdbc事务
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}
  • 创建mybatis创建SqlSessionFactory Bean 和 Mapper 代理开发映射对象配置文件MybatisConfig
public class MybatisConfig {
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
        SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
        ssfb.setTypeAliasesPackage("org.example.domain");
        ssfb.setDataSource(dataSource);
        return ssfb;
    }
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer msc = new MapperScannerConfigurer();
        msc.setBasePackage("org.example.dao");
        return msc;
    }
}
  • 根据数据库表创建对应的实体类Account
public class Account{
    //此处省略getter、setter和toString方法
    private Integer id;
    private String name;
    private Double money;
}
  • 创建AccontDao接口,用注解的方式定义mapper代理开发业务接口,分别为加钱的操作方法 inmoney 和 减钱的操作 outmoney
public interface AccountDao {
    @Update("update tbl_account set money = money + #{money} where name = #{name}")
    void inMoney(@Param("name") String name, @Param("money") Double money);
    @Update("update tbl_account set money = money - #{money} where name = #{name}")
    void outMoney(@Param("name") String name, @Param("money") Double money);
}
  • 创建业务层接口AccountService,定义转账操作方法transfer
public interface AccountService {
    /**
     * 转账操作
     * @param out 传出方
     * @param in 转入方
     * @param money 金额
     */
    //配置当前接口方法具有事务
    @Transactional
    public void transfer(String out,String in ,Double money) ;
}
  • 创建业务层接口 AccountService 的实现类AccountServiceImpl,调用数据层功能的加钱和减钱方法 inmoney 和 outmoney
@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao accountDao;
    public void transfer(String out,String in ,Double money) {
        //减钱
        accountDao.outMoney(out,money);
        //加钱
        accountDao.inMoney(in,money);
    }
}
  • 编写测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
    @Autowired
    private AccountService accountService;
    @Test
    public void testTransfer() throws IOException {
        //Tom 向 Jerry 转100元
        accountService.transfer("Tom","Jerry",100D);
    }
}
  • 程序运行结果

  • 文件结构参考

  1. 入门案例分析
  • 入门案例完成了简单的模拟转账操作,此时我们在转账接口的实现类AccountServiceImpl减钱和加钱的操作中间添加一行模拟业务运行异常的代码,此时我们希望业务异常,终止操作,即数据库的账户余额不变。
  • 添加了模拟异常的代码及运行结果


  • 通过观察数据库中的表格数据我们发现异常前面的减钱操作运行了,而异常后面的加钱操作没有运行,导致整体业务功能失败。我们可以通过开启Spring事务来解决这个问题。
  1. 小结
  • Spring注解式事务通常添加在业务层接口中而不会添加到业务层实现类中,降低耦合
  • 注解式事务可以添加到业务方法上表示当前方法开启事务,也可以添加到接口上表示当前接口所有方法开启事务
  • 事务管理器需要根据实现技术进行选择,mybatis使用的是jdbc事务

3.开启Spring事务的一般步骤

  1. @Transactional注解配置对应的接口方法具有事务
@Transactional
    public void transfer(String out,String in ,Double money) ;
}
  1. 配置事务管理器,mybatis使用的是jdbc事务
public class JdbcConfig {
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}
  1. @EnableTransactionManagement注解开启注解式事务驱动
@EnableTransactionManagement
public class SpringConfig {
}

此时在存在模拟异常的情况下再次运行模拟测试类,数据库中的数据不变,业务功能运行正常,Spring事务开启成功。


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
3月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
625 3
|
30天前
|
监控 Java 数据库连接
《深入理解Spring》事务管理——数据一致性的守护者
Spring事务管理确保数据一致性,支持声明式与编程式两种方式。通过@Transactional注解简化配置,提供传播行为、隔离级别、回滚规则等灵活控制,结合ACID特性保障业务逻辑可靠执行。
|
2月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
490 5
|
4月前
|
Java Linux 网络安全
Linux云端服务器上部署Spring Boot应用的教程。
此流程涉及Linux命令行操作、系统服务管理及网络安全知识,需要管理员权限以进行配置和服务管理。务必在一个测试环境中验证所有步骤,确保一切配置正确无误后,再将应用部署到生产环境中。也可以使用如Ansible、Chef等配置管理工具来自动化部署过程,提升效率和可靠性。
492 13
|
5月前
|
安全 Java 数据库
Spring Boot 框架深入学习示例教程详解
本教程深入讲解Spring Boot框架,先介绍其基础概念与优势,如自动配置、独立运行等。通过搭建项目、配置数据库等步骤展示技术方案,并结合RESTful API开发实例帮助学习。内容涵盖环境搭建、核心组件应用(Spring MVC、Spring Data JPA、Spring Security)及示例项目——在线书店系统,助你掌握Spring Boot开发全流程。代码资源可从[链接](https://pan.quark.cn/s/14fcf913bae6)获取。
663 2
|
设计模式 Java 数据库连接
Spring(一)——【快速入门、配置文件、依赖注入以及API】
Spring(一)——【快速入门、配置文件、依赖注入以及API】
Spring(一)——【快速入门、配置文件、依赖注入以及API】
|
4月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
843 0
|
1月前
|
JavaScript Java Maven
【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
SpringBoot专栏第二章,从本章开始正式进入SpringBoot的WEB阶段开发,本章先带你认识yaml配置文件和资源的路径配置原理,以方便在后面的文章中打下基础
243 3