Spring 事务控制

Spring 事务控制介绍

JavaEE 体系进行分层开发,事务控制位于业务层,Spring 提供了分层设计业务层的事务处理解决方案。

Spring 的事务控制都是基于 AOP 的,它既可以使用编程的方式实现,也可以使用配置的方式实现。但是推荐以配置的方式实现

PlatformTransactionManager 接口是提供事务操作的方法,它包含的获取事务状态信息、提交事务、回滚事务等方法。

DataSourceTransactionManager 实现类用于 Spring JdbcTemplate 或 MyBatis 持久化数据。

事务的传播行为

  • REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般用于增删改操作
  • SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。一般用于查操作
  • MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常
  • REQUERS_NEW 新建事务,如果当前在事务中,把当前事务挂起
  • NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
  • NEVER 以非事务方式运行,如果当前存在事务,抛出异常
  • NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作

XML 的 事务控制

本节源码

使用步骤

  • 创建 Spring 的配置文件并导入约束
  • 准备数据库表和实体类
  • 编写持久层接口和实现类
  • 编写业务层接口和实现类
  • 编写配置文件
    • 在配置文件中配置持久层和业务
    • 配置数据源
    • 配置事务相关:
      • 配置事务管理器
      • 配置事务的通知
        • 配置事务的属性
      • 配置 AOP
        • 配置 AOP 切入点表达式
        • 配置切入点表达式和事务通知的对应关系

账户的持久层接口的实现类:AccountDAOImpl.java

  1. package cn.parzulpan.dao;
  2. import cn.parzulpan.domain.Account;
  3. import org.springframework.jdbc.core.BeanPropertyRowMapper;
  4. import org.springframework.jdbc.core.support.JdbcDaoSupport;
  5. import java.util.List;
  6. /**
  7. * @Author : parzulpan
  8. * @Time : 2020-12
  9. * @Desc : 账户的持久层接口的实现类
  10. */
  11. public class AccountDAOImpl extends JdbcDaoSupport implements AccountDAO {
  12. public Account findById(Integer accountId) {
  13. List<Account> accounts = getJdbcTemplate().query("select * from bankAccount where id = ?",
  14. new BeanPropertyRowMapper<Account>(Account.class),
  15. accountId);
  16. return accounts.isEmpty() ? null : accounts.get(0);
  17. }
  18. public Account findByName(String name) {
  19. List<Account> accounts = getJdbcTemplate().query("select * from bankAccount where name = ?",
  20. new BeanPropertyRowMapper<Account>(Account.class),
  21. name);
  22. if (accounts.isEmpty()) {
  23. return null;
  24. }
  25. if (accounts.size() > 1) {
  26. throw new RuntimeException("结果集不唯一");
  27. }
  28. return accounts.get(0);
  29. }
  30. public void update(Account account) {
  31. getJdbcTemplate().update("update bankAccount set name = ?, money = ? where id = ?",
  32. account.getName(), account.getMoney(), account.getId());
  33. }
  34. }

账户的持久层接口的实现类:AccountServiceImpl.java

  1. package cn.parzulpan.service;
  2. import cn.parzulpan.dao.AccountDAO;
  3. import cn.parzulpan.domain.Account;
  4. /**
  5. * @Author : parzulpan
  6. * @Time : 2020-12
  7. * @Desc : 账户的业务层接口的实现类,事务控制应该在业务层
  8. */
  9. public class AccountServiceImpl implements AccountService {
  10. private AccountDAO accountDAO;
  11. public void setAccountDAO(AccountDAO accountDAO) {
  12. this.accountDAO = accountDAO;
  13. }
  14. public Account findById(Integer accountId) {
  15. return accountDAO.findById(accountId);
  16. }
  17. public void transfer(String sourceName, String targetName, Double money) {
  18. System.out.println("开始进行转账...");
  19. Account source = accountDAO.findByName(sourceName);
  20. Account target = accountDAO.findByName(targetName);
  21. source.setMoney(source.getMoney() - money);
  22. target.setMoney(target.getMoney() + money);
  23. accountDAO.update(source);
  24. int i = 1 / 0; // 模拟转账故障
  25. accountDAO.update(target);
  26. System.out.println("转账完成...");
  27. }
  28. }

配置文件:bean.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xmlns:context="http://www.springframework.org/schema/context"
  6. xmlns:tx="http://www.springframework.org/schema/tx"
  7. xsi:schemaLocation="http://www.springframework.org/schema/beans
  8. https://www.springframework.org/schema/beans/spring-beans.xsd
  9. http://www.springframework.org/schema/aop
  10. https://www.springframework.org/schema/aop/spring-aop.xsd
  11. http://www.springframework.org/schema/context
  12. https://www.springframework.org/schema/context/spring-context.xsd
  13. http://www.springframework.org/schema/tx
  14. https://www.springframework.org/schema/tx/spring-tx.xsd">
  15. <!-- 配置账户业务层 -->
  16. <bean id="accountService" class="cn.parzulpan.service.AccountServiceImpl">
  17. <property name="accountDAO" ref="accountDAO"/>
  18. </bean>
  19. <!-- 配置账户持久层 -->
  20. <bean id="accountDAO" class="cn.parzulpan.dao.AccountDAOImpl">
  21. <property name="dataSource" ref="dataSource"/>
  22. </bean>
  23. <!-- 配置数据源 -->
  24. <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  25. <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  26. <property name="url" value="jdbc:mysql://localhost:3306/springT?useSSL=false"/>
  27. <property name="username" value="root"/>
  28. <property name="password" value="root"/>
  29. </bean>
  30. <!-- 1. 配置事务管理器 -->
  31. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  32. <property name="dataSource" ref="dataSource"/>
  33. </bean>
  34. <!-- 2. 配置事务的通知 -->
  35. <tx:advice id="txAdvice" transaction-manager="transactionManager">
  36. <!-- 3. 配置事务的属性
  37. 指定是业务核心方法
  38. read-only:是否是只读事务。默认 false,不只读。
  39. isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。
  40. propagation:指定事务的传播行为。
  41. timeout:指定超时时间。默认值为:-1。永不超时。
  42. rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。
  43. 没有默认值,任何异常都回滚。
  44. no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回滚。
  45. 没有默认值,任何异常都回滚。
  46. -->
  47. <tx:attributes>
  48. <tx:method name="*" read-only="false" propagation="REQUIRED"/>
  49. <!-- 查询方法 -->
  50. <tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
  51. </tx:attributes>
  52. </tx:advice>
  53. <!-- 4. 配置 AOP -->
  54. <aop:config>
  55. <!-- 5. 配置 AOP 切入点表达式 -->
  56. <aop:pointcut id="allServiceImplPCR" expression="execution(* cn.parzulpan.service.*.*(..))"/>
  57. <!-- 6. 配置切入点表达式和事务通知的对应关系 -->
  58. <aop:advisor advice-ref="txAdvice" pointcut-ref="allServiceImplPCR"/>
  59. </aop:config>
  60. </beans>

对 账户的业务层 进行单元测试:AccountServiceImplTest.java

  1. package cn.parzulpan.service;
  2. import cn.parzulpan.domain.Account;
  3. import org.junit.Test;
  4. import org.junit.runner.RunWith;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.test.context.ContextConfiguration;
  7. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  8. import static org.junit.Assert.*;
  9. /**
  10. * @Author : parzulpan
  11. * @Time : 2020-12
  12. * @Desc : 对 账户的业务层 进行单元测试
  13. */
  14. @RunWith(SpringJUnit4ClassRunner.class)
  15. @ContextConfiguration(locations = "classpath:bean.xml")
  16. public class AccountServiceImplTest {
  17. @Autowired
  18. private AccountService as;
  19. @Test
  20. public void findById() {
  21. Account account = as.findById(1);
  22. System.out.println(account);
  23. }
  24. @Test
  25. public void transfer() {
  26. as.transfer("aaa", "bbb", 100.0);
  27. }
  28. }

注解 的 事务控制

本节源码

使用步骤

  • 其他同 XML 的 事务控制
  • 编写配置文件
    • 配置事务管理器
    • 开启对注解事务的支持
    • 在需要事务支持的地方使用 @Transactional

账户的持久层接口的实现类:AccountDAOImpl.java

  1. package cn.parzulpan.dao;
  2. import cn.parzulpan.domain.Account;
  3. import org.springframework.jdbc.core.BeanPropertyRowMapper;
  4. import org.springframework.jdbc.core.JdbcTemplate;
  5. import org.springframework.jdbc.core.support.JdbcDaoSupport;
  6. import org.springframework.stereotype.Repository;
  7. import javax.annotation.Resource;
  8. import java.util.List;
  9. /**
  10. * @Author : parzulpan
  11. * @Time : 2020-12
  12. * @Desc : 账户的持久层接口的实现类
  13. */
  14. @Repository("accountDAO")
  15. public class AccountDAOImpl implements AccountDAO {
  16. @Resource(name = "jdbcTemplate")
  17. private JdbcTemplate jdbcTemplate;
  18. public Account findById(Integer accountId) {
  19. List<Account> accounts = jdbcTemplate.query("select * from bankAccount where id = ?",
  20. new BeanPropertyRowMapper<Account>(Account.class),
  21. accountId);
  22. return accounts.isEmpty() ? null : accounts.get(0);
  23. }
  24. public Account findByName(String name) {
  25. List<Account> accounts = jdbcTemplate.query("select * from bankAccount where name = ?",
  26. new BeanPropertyRowMapper<Account>(Account.class),
  27. name);
  28. if (accounts.isEmpty()) {
  29. return null;
  30. }
  31. if (accounts.size() > 1) {
  32. throw new RuntimeException("结果集不唯一");
  33. }
  34. return accounts.get(0);
  35. }
  36. public void update(Account account) {
  37. jdbcTemplate.update("update bankAccount set name = ?, money = ? where id = ?",
  38. account.getName(), account.getMoney(), account.getId());
  39. }
  40. }

账户的持久层接口的实现类:AccountServiceImpl.java

  1. package cn.parzulpan.service;
  2. import cn.parzulpan.dao.AccountDAO;
  3. import cn.parzulpan.domain.Account;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.stereotype.Service;
  6. import org.springframework.transaction.annotation.Propagation;
  7. import org.springframework.transaction.annotation.Transactional;
  8. import javax.annotation.Resource;
  9. /**
  10. * @Author : parzulpan
  11. * @Time : 2020-12
  12. * @Desc : 账户的业务层接口的实现类,事务控制应该在业务层
  13. */
  14. @Service("accountService")
  15. public class AccountServiceImpl implements AccountService {
  16. @Resource(name = "accountDAO")
  17. private AccountDAO accountDAO;
  18. @Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
  19. public Account findById(Integer accountId) {
  20. return accountDAO.findById(accountId);
  21. }
  22. @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
  23. public void transfer(String sourceName, String targetName, Double money) {
  24. System.out.println("开始进行转账...");
  25. Account source = accountDAO.findByName(sourceName);
  26. Account target = accountDAO.findByName(targetName);
  27. source.setMoney(source.getMoney() - money);
  28. target.setMoney(target.getMoney() + money);
  29. accountDAO.update(source);
  30. int i = 1 / 0; // 模拟转账故障
  31. accountDAO.update(target);
  32. System.out.println("转账完成...");
  33. }
  34. }

配置文件:bean.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xmlns:context="http://www.springframework.org/schema/context"
  6. xmlns:tx="http://www.springframework.org/schema/tx"
  7. xsi:schemaLocation="http://www.springframework.org/schema/beans
  8. https://www.springframework.org/schema/beans/spring-beans.xsd
  9. http://www.springframework.org/schema/aop
  10. https://www.springframework.org/schema/aop/spring-aop.xsd
  11. http://www.springframework.org/schema/context
  12. https://www.springframework.org/schema/context/spring-context.xsd
  13. http://www.springframework.org/schema/tx
  14. https://www.springframework.org/schema/tx/spring-tx.xsd">
  15. <context:component-scan base-package="cn.parzulpan"/>
  16. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
  17. <property name="dataSource" ref="dataSource"/>
  18. </bean>
  19. <!-- 配置数据源 -->
  20. <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  21. <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  22. <property name="url" value="jdbc:mysql://localhost:3306/springT?useSSL=false"/>
  23. <property name="username" value="root"/>
  24. <property name="password" value="root"/>
  25. </bean>
  26. <!-- 1. 配置事务管理器 -->
  27. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  28. <property name="dataSource" ref="dataSource"/>
  29. </bean>
  30. <!-- 2. 开启对注解事务的支持 -->
  31. <tx:annotation-driven transaction-manager="transactionManager"/>
  32. <!-- 3. 在需要事务支持的地方使用 @Transactional -->
  33. </beans>

总结和练习

【Spring】Spring 事务控制的更多相关文章

  1. 13 Spring 的事务控制

    1.事务的概念 理解事务之前,先讲一个你日常生活中最常干的事:取钱.  比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱.这两个步骤必 ...

  2. 04 Spring:01.Spring框架简介&&02.程序间耦合&&03.Spring的 IOC 和 DI&&08.面向切面编程 AOP&&10.Spring中事务控制

    spring共四天 第一天:spring框架的概述以及spring中基于XML的IOC配置 第二天:spring中基于注解的IOC和ioc的案例 第三天:spring中的aop和基于XML以及注解的A ...

  3. spring的事务控制

    1.事务介绍 (1)特性:ACID Atomicity(原子性):事务中的所有操作要么全做要么全不做 Consistency(一致性):事务执行的结果使得数据库从一个一致性状态转移到另一个一致性状态 ...

  4. 阶段3 2.Spring_10.Spring中事务控制_9 spring编程式事务控制1-了解

    编程式的事物控制,使用的情况非常少,主要作为了解 新建项目 首先导入包坐标 复制代码 这里默认值配置了Service.dao和连接池其他的内容都没有配置 也就说现在是没有事物支持的.运行测试文件 有错 ...

  5. 阶段3 2.Spring_10.Spring中事务控制_8 spring基于纯注解的声明式事务控制

    新建项目 把之前项目src下的内容全部复制过来 pom.xml内复制过来 开始配置 新建一个config的包,然后再新建配置文件类SpringConfiguration @Configuration这 ...

  6. 阶段3 2.Spring_10.Spring中事务控制_6 spring基于XML的声明式事务控制-配置步骤

    环境搭建 新建工程 把对应的依赖复制过来 src下内容复制 配置spring中的声明事物 找到bean.xml开始配置 配置事物管理器 里面需要注入DataSource 2-配置事物通知 需要先导入事 ...

  7. 阶段3 2.Spring_10.Spring中事务控制_5 spring事务控制的代码准备

    创建一个工程,只搭建环境不做配置.等配置的时候把这个项目相关的代码再复制到新项目里面 jar包的打包方式 导入包 事务控制也是基于AOP的.所以这里导入aspectjweaver 复制jdbcTemp ...

  8. 阶段3 2.Spring_10.Spring中事务控制_4 spring中事务控制的一组API

    分析aop的 xml 的代码.更直观一些 事务提交和回滚就是我们重复的代码 spring业余事务管理器,我们拿过来直接用就可以 提交和回滚的后面直接调用释放.所以释放资源之类就是多余的 在绑定连接到线 ...

  9. 阶段3 2.Spring_10.Spring中事务控制_1 基于XML的AOP实现事务控制

    新建项目 首先把依赖复制进来 aop必须引入.aspectjweaver 复制src下的所有内容 复制到我们的新项目里面 factory文件夹删掉 删除后测试类必然就报错 配置文件 beanFacto ...

  10. Spring的事务控制-基于注解的方式

    模拟转账操作,即Jone减少500,tom增加500 如果有疑问请访问spring事务控制-基于xml方式 1.创建数据表 2.创建Account实体类 public class Account { ...

随机推荐

  1. Pytorch训练时显存分配过程探究

    对于显存不充足的炼丹研究者来说,弄清楚Pytorch显存的分配机制是很有必要的.下面直接通过实验来推出Pytorch显存的分配过程. 实验实验代码如下: import torch from torch ...

  2. P5857 「SWTR-03」Matrix

    原本自己有一个思路的,推了半天不太确定看了下题解,发现到后面完全不知道他代码在写些什么(我太弱了),所以打算自己理一下. 题解 首先我们可以肯定的一点就是,我们可以发现,一个矩阵的形态只和他横着和竖着 ...

  3. win 7 MongoDB 下载安装

    准备: 1.mongodb-win32-x86_64-2008plus-ssl-3.4.3-signed.msi 官方下载 2.1.建立数据存放目录 F:\MongoDB\ 2.建立日志文件      ...

  4. webstorm2017.02版本如何使用material theme

    本想废话一番,表达对material theme的喜欢.还是直接说方法吧~ file-settings-Plugins-Browse repositories-搜索 material theme -选 ...

  5. OGG报错:Cannot load ICU resource bundle 'ggMessage', error code 2 - No such file or directory

    [oracle@dgdb1 ~]$ ggsci Oracle GoldenGate Command Interpreter for OracleVersion 11.2.1.0.3 14400833 ...

  6. Flink怎么做到精确一次的?

    使用 分布式快照机制 和 两阶段提交 两阶段提交 在 Flink 中两阶段提交的实现方法被封装到了 TwoPhaseCommitSinkFunction 这个抽象类中,我们只需要实现其中的beginT ...

  7. ssm的pom配置

    <!--引入ssm依赖--> <!--常量和版本号 --> <properties> <!-- 文件编码 --> <project.build.s ...

  8. SpringBoot执行原理

    目录 [Toc] 一.执行原理: 每个Spring Boot项目都有一个主程序启动类,在主程序启动类中有一个启动项目的main()方法, 在该方法中通过执行SpringApplication.run( ...

  9. GitHub 上的大佬们打完招呼,会聊些什么?

    你好 GitHub!每一位开源爱好者的好朋友「HelloGitHub」 大家好,今儿 HG 有幸邀请到:Lanking 一位亚马逊 AI 软件工程师.开源爱好者和贡献者.他是亚马逊开源的 Java 深 ...

  10. Hive动态分区详解

    目录 动态分区调整 注意 动态分区插入 动静分区结合 例子 动态分区调整 动态分区属性:设置为true表示开启动态分区功能(默认为false)hive.exec.dynamic.partition=t ...