Spring事务管理,xml和注解实现
创始人
2025-05-30 19:58:12

目标:熟悉事务管理的核心接口,能够说出它的3个核心接口及内容

spring-tx-5.2.8.RELEAS依赖包的3个接口

  • PlatformTransactionManager接口:可以根据属性管理事务。
  • TransactionDefinition接口:用于定义事务的属性。
  • TransactionStatus接口:用于界定事务的状态。

1.PlatformTransactionManager接口

PlatformTransactionManager接口主要用于管理事务,该接口中提供了三个管理事物的方法。

 

在实际应用中,Spring事务管理实际是由具体的持久化技术完成的,而
PlatformTransactionManager接口只提供统一的抽象方法。为了应对不同持久化技术的差异性,Spring为他们提供了具体的实现类,例如,Spring为Spring JDBC和MyBatis等依赖于DataSource的持久化技术提供了实现类DataSourceTransactionManager,如此以来,Spring JDBC或MyBatis等持久化技术的事务管理可以由DataSourceTransactionManager类实现,而且Spring 可以通过PlatformTransactionManager接口对这些实现类进行统一管理。

2.TransactionDefinition接口

TransactionDefinition接口中定义了事务描述相关的常量,其中包括了事务的隔离级别、事务的传播行为、事务的超时时间和是否为只读事务。

事务的隔离级别

 

事务的传播行为

事务的传播行为是指处于不同事务中的方法在相互调用时,方法执行期间,事务的维护情况。例如,当一个事务的方法B调用另一个事务的方法A时,可以规定A方法继续在B方法所属的现有事务中运行,也可以规定A方法开启一个新事务,在新事务中运行,B方法所属的现有事务先挂起,等A方法的新事务执行完毕后再恢复。

TransactionDefinition接口中定义的7种事务传播行为

事务的超时时间

事务的超时时间是指事务执行的时间界限,超过这个时间界限,事务将会回滚。TransactionDefinition接口提供了TIMEOUT_DEFAULT常量定义事务的超时时间。 

是否为只读事务

当事务为只读时,该事务不修改任何数据,只读事务有助于提升性能,如果在只读事务中修改数据,会引发异常。TransactionDefinition接口中除了提供事务的隔离级别、事务的传播行为、事务的超时时间和是否为只读事务的常量外,还提供了一系列方法来获取事务的属性。

TransactionDefinition接口常用方法

3.TransactionStatus接口 

TransactionStatus接口主要用于界定事务的状态,通常情况下,编程式事务中使用该接口较多。TransactionStatus接口提供了一系列返回事务状态信息的方法,具体如下。

熟悉事务管理的方式,能够说出Spring事务管理的两种方式分别是什么 

Spring中的事务管理分为两种方式,一种是传统的编程式事务管理,另一种是声明式事务管理。

  • 编程式事务管理:通过编写代码实现的事务管理,包括定义事务的开始、正常执行后的事务提交和异常时的事务回滚。
  • 声明式事务管理:通过AOP技术实现的事务管理,其主要思想是将事务管理作为一个“切面”代码单独编写,然后通过AOP技术将事务管理的“切面”代码植入到业务目标类中。

编写式事务管理有点落后,一般使用第二种,声明式事务管理

实现XML方式的声明式事务

没有配置事务具体实现代码:

这是一开始表中的数据:

 现在模拟zhangsan给lisi转账100元

pom.xml


4.0.0org.example_202303191.0-SNAPSHOT88UTF-8org.springframeworkspring-context5.2.3.RELEASEorg.springframeworkspring-beans5.2.3.RELEASEmysqlmysql-connector-java5.1.47org.springframeworkspring-jdbc5.3.6org.springframeworkspring-tx5.3.6org.springframeworkspring-aspects4.2.4.RELEASE

 AccountDaoImpl:

package cn.hdc.dao.impl;import cn.hdc.dao.AccountDao;
import cn.hdc.model.Account;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;import java.util.List;public class AccountDaoImpl implements AccountDao {private JdbcTemplate jdbcTemplate;public JdbcTemplate getJdbcTemplate() {return jdbcTemplate;}public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}@Overridepublic Integer addAccount(Account account) {String sql = "insert into account(username,balance) values(?,?)";Object[] params = new Object[]{account.getUsername(), account.getBalance()};jdbcTemplate.update(sql, params);return jdbcTemplate.update(sql, params);}@Overridepublic Integer deleteAccount(Integer id) {String sql = "delete from account where id = ?";return jdbcTemplate.update(sql, id);}@Overridepublic Integer updateAccount(Account account) {String sql = "update account set username=?,balance=? where id=?";Object[] params = new Object[]{account.getUsername(), account.getBalance(), account.getId()};return jdbcTemplate.update(sql, params);}@Overridepublic Account findAccountById(Integer id) {String sql = "select * from account where id = ?";RowMapper accountRowMapper = new BeanPropertyRowMapper<>(Account.class);Account account = jdbcTemplate.queryForObject(sql, accountRowMapper, id);return jdbcTemplate.queryForObject(sql, accountRowMapper, id);}@Overridepublic List findAll() {String sql = "select * from account";RowMapper accountRowMapper = new BeanPropertyRowMapper<>(Account.class);List list = jdbcTemplate.query(sql, accountRowMapper);return list;}//模拟转账操作@Overridepublic void transfer(String outUser, String inUser, Double money) {//收款jdbcTemplate.update("update account set balance = balance + ? where username = ?", money, inUser);//模拟异常int i = 10 / 0;//付款jdbcTemplate.update("update account set balance = balance - ? where username = ?", money, outUser);}
}

AccountDao接口:

package cn.hdc.dao;import cn.hdc.model.Account;import java.util.List;public interface AccountDao {public Integer addAccount(Account account);public Integer deleteAccount(Integer id);public Integer updateAccount(Account account);public Account findAccountById(Integer id);public List findAll();public void transfer(String outUser, String inUser, Double money);
}

Account实体类:

package cn.hdc.model;public class Account {private Integer id;private String username;private Double balance;@Overridepublic String toString() {return "Account{" +"id=" + id +", username='" + username + '\'' +", balance=" + balance +'}';}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public Double getBalance() {return balance;}public void setBalance(Double balance) {this.balance = balance;}
}

测试类:

import cn.hdc.dao.AccountDao;
import cn.hdc.dao.impl.AccountDaoImpl;
import cn.hdc.model.Account;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;import java.util.List;public class APP {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");AccountDao accountDao = (AccountDao) context.getBean("accountDao");accountDao.transfer("zhangsan", "lisi", 100.0);//        List list = accountDao.findAll();
//        list.forEach(account -> {
//            System.out.println(account);
//        });//        Account account = accountDao.findAccountById(1);
//        System.out.println(account);//        Integer ret = accountDao.deleteAccount(2);
//        if (ret > 0) {
//            System.out.println("删除成功!");
//        } else {
//            System.out.println("删除失败!");
//        }
//        Account account1 = new Account();
//        account1.setId(2);
//        account1.setUsername("zhangsan");
//        account1.setBalance(5000.02153);
//        Integer ret = accountDao.updateAccount(account1);
//        if (ret > 0) {
//            System.out.println("修改成功!");
//        } else {
//            System.out.println("修改失败!");
//        }//        Account account = new Account();
//        account.setUsername("tom");
//        account.setBalance(1000.011);
//        Integer ret = accountDao.addAccount(account);
//        if (ret > 0) {
//            System.out.println("插入成功!");
//        } else {
//            System.out.println("插入失败!");
//        }//        jdbcTemplate.execute("create table account" +
//                "(" +
//                "    id int primary key auto_increment," +
//                "    username varchar(50)," +
//                "    balance double" +
//                ");");
//        System.out.println("account表创建成功!");//        UserDaoImpl userDao = (UserDaoImpl) context.getBean("userDao");//        System.out.println(userDao.getJdbcTemplate());}
}

运行结果:

看一下表数据:

 

 张三的钱没扣!

接下来我们使用事务

具体实现代码:

现在还原一下表

pom.xml


4.0.0org.example_202303191.0-SNAPSHOT88UTF-8org.springframeworkspring-context5.2.3.RELEASEorg.springframeworkspring-beans5.2.3.RELEASEmysqlmysql-connector-java5.1.47org.springframeworkspring-jdbc5.3.6org.springframeworkspring-tx5.3.6org.springframeworkspring-aspects4.2.4.RELEASEorg.aspectjaspectjweaver1.9.6aopallianceaopalliance1.0

 

AccountDao接口:

package cn.hdc.dao;import cn.hdc.model.Account;import java.util.List;public interface AccountDao {public Integer addAccount(Account account);public Integer deleteAccount(Integer id);public Integer updateAccount(Account account);public Account findAccountById(Integer id);public List findAll();public void transfer(String outUser, String inUser, Double money);
}

AccountDaoImpl

package cn.hdc.dao.impl;import cn.hdc.dao.AccountDao;
import cn.hdc.model.Account;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;import java.util.List;public class AccountDaoImpl implements AccountDao {private JdbcTemplate jdbcTemplate;public JdbcTemplate getJdbcTemplate() {return jdbcTemplate;}public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}@Overridepublic Integer addAccount(Account account) {String sql = "insert into account(username,balance) values(?,?)";Object[] params = new Object[]{account.getUsername(), account.getBalance()};jdbcTemplate.update(sql, params);return jdbcTemplate.update(sql, params);}@Overridepublic Integer deleteAccount(Integer id) {String sql = "delete from account where id = ?";return jdbcTemplate.update(sql, id);}@Overridepublic Integer updateAccount(Account account) {String sql = "update account set username=?,balance=? where id=?";Object[] params = new Object[]{account.getUsername(), account.getBalance(), account.getId()};return jdbcTemplate.update(sql, params);}@Overridepublic Account findAccountById(Integer id) {String sql = "select * from account where id = ?";RowMapper accountRowMapper = new BeanPropertyRowMapper<>(Account.class);Account account = jdbcTemplate.queryForObject(sql, accountRowMapper, id);return jdbcTemplate.queryForObject(sql, accountRowMapper, id);}@Overridepublic List findAll() {String sql = "select * from account";RowMapper accountRowMapper = new BeanPropertyRowMapper<>(Account.class);List list = jdbcTemplate.query(sql, accountRowMapper);return list;}//模拟转账操作@Overridepublic void transfer(String outUser, String inUser, Double money) {//收款jdbcTemplate.update("update account set balance = balance + ? where username = ?", money, inUser);//模拟异常int i = 10 / 0;//付款jdbcTemplate.update("update account set balance = balance - ? where username = ?", money, outUser);}
}

Account实体类:

package cn.hdc.model;public class Account {private Integer id;private String username;private Double balance;@Overridepublic String toString() {return "Account{" +"id=" + id +", username='" + username + '\'' +", balance=" + balance +'}';}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public Double getBalance() {return balance;}public void setBalance(Double balance) {this.balance = balance;}
}

applicationContext.xml



 

测试类:

import cn.hdc.dao.AccountDao;
import cn.hdc.dao.impl.AccountDaoImpl;
import cn.hdc.model.Account;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;import java.util.List;public class APP {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");AccountDao accountDao = (AccountDao) context.getBean("accountDao");accountDao.transfer("zhangsan", "lisi", 100.0);//        List list = accountDao.findAll();
//        list.forEach(account -> {
//            System.out.println(account);
//        });//        Account account = accountDao.findAccountById(1);
//        System.out.println(account);//        Integer ret = accountDao.deleteAccount(2);
//        if (ret > 0) {
//            System.out.println("删除成功!");
//        } else {
//            System.out.println("删除失败!");
//        }
//        Account account1 = new Account();
//        account1.setId(2);
//        account1.setUsername("zhangsan");
//        account1.setBalance(5000.02153);
//        Integer ret = accountDao.updateAccount(account1);
//        if (ret > 0) {
//            System.out.println("修改成功!");
//        } else {
//            System.out.println("修改失败!");
//        }//        Account account = new Account();
//        account.setUsername("tom");
//        account.setBalance(1000.011);
//        Integer ret = accountDao.addAccount(account);
//        if (ret > 0) {
//            System.out.println("插入成功!");
//        } else {
//            System.out.println("插入失败!");
//        }//        jdbcTemplate.execute("create table account" +
//                "(" +
//                "    id int primary key auto_increment," +
//                "    username varchar(50)," +
//                "    balance double" +
//                ");");
//        System.out.println("account表创建成功!");//        UserDaoImpl userDao = (UserDaoImpl) context.getBean("userDao");//        System.out.println(userDao.getJdbcTemplate());}
}

运行结果:

 

表中数据没有变化,事务发生了回滚。 

基于注解方式的声明式事务

@Transactional的属性

 

AccountDaoImpl在原来的基础上加上注解

 

applicationContext.xml

 运行结果:

 

表中数据没有发生改变,事务生效

相关内容

热门资讯

KubeSphere All ... KubeSphere All in one安装配置手册 1. 初始化 1.1 配置apt源 # vi...
学习软件测试怎么能缺少练手的软... 你好,我是凡哥。 最近收到许多自学自动化测试的小伙伴私信,学习了理论知识...
【面试题】浅谈css加载是否会... 大厂面试题分享 面试题库前后端面试题库 (面试必备) 推荐:...
直播带货系统开发的关键点、代码... 时下,直播的热度依然不减,而它的产物之一:直播带货系统&#...
一文读懂强化学习! 一.了解强化学习1.1基本概念强化学习是考虑智能体(Agent)与环境&...
Spring Cloud之一:... 目录 环境 Eureka工程的创建步骤 系列目录(持续更新。。。) S...
golang实现守护进程(2) 前言golang实现守护进程,包含功能:1. 守护进程只创建一次2. 平...
url 格式详解 统一资源定位系统(uniform resource locator; url ...
elasticsearch7.... elasticsearch版本:7.17.3 目标:实现对类型为text...
SpringBoot 加载系统... 开发环境: IDEA 2022.1.4+ MyBatis         代码参考:spri...
交换机概念和知识和命令 目录 一、华为交换机基础学习的一些重要概念和知识 二、交换机常用命令大全 三、不常用的交换机命令 ...
什么是 JavaScript ... 本文首发自「慕课网」,想了解更多IT干货内容,程序员圈内热闻࿰...
【C++】C++11——lam... 文章目录一、Lambda表达式引入二、Lambda表达式语法三、Lambda表达式交换两个值四、La...
Java分布式事务(十) 文章目录🔥分布式架构的理论知识_BASE理论🔥分布式事务解决方案_最...
vmware中centos7实... 前言 在开发收银系统SAAS版本时,采用的是centos服务器,经常需要...
计算机图形学 | 可编程渲染管... 计算机图形学 | 可编程渲染管线计算机图形学 | 可编程渲染管线3.1 从固定到可编程图形编程的发展...
linux下安装两个或多个to... 安装jdk,tomcat编辑环境变量profilevi /etc/profile加入以...
selenium的显示等待、隐... 关于selenium有三种等待方式,分别为显示等待、隐式等待、强制等待 1、强制等待 ...
测牛学堂:软件测试接口自动化之... requests库 用postman进行接口测试有一定的限制,我们测试更应该掌握的是用...
day36_jdbc 今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客...
【java基础】Stream流... 文章目录基本介绍流的创建流的各种常见操作forEach方法filter方法map方法peek方法fl...
幂等性通用组件 一、什么是幂等性幂等是一个数学与计算机学概念,在数学中某一元运算为幂等时,...
Nacos服务注册 又是美好的一天呀~ 个人博客地址: huanghong.top 本文预估阅读时长为3...
令人惊艳的ChatGPT项目,... 自从 ChatGPT、Stable Diffusion 发布以来,各种相关开源项目百花...
舆情监测系统有哪些优势,TOO... 舆情监测系统是一种基于大数据技术的舆情分析工具,可以帮助企业、政府等机构实时监控公众对...
【Linux】基础IO流(上) 文章目录1. 预备知识2. 回忆C接口fopenfputsfprintfsnprintf追加方式——...
设计模式(二十七)----行为... 1 概述 如上图,设计一个软件用来进行加减计算。我们第一想法就是使用工具类ÿ...
精心整理前端主流框架学习路径 版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog....
typescript声明 前言 “d.ts”文件用于为 TypeScript 提供有关用 JavaScript 编写的 API...
HashMap源码分析 Java源码系列:下方连接 http://t.csdn.cn/Nwzed 文章目录...