Spring事务和事务传播机制

1. Spring中事务的实现

  • 编程式事务(手动写代码操作事务)
  • 声明式事务(利用注解自动开启和提交事务)

2. 编程式事务

import lombok.extern.slf4j.Slf4j;
import mybatis.model.User;
import mybatis.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;//编程式事务(手动写代码操作事务)
@Slf4j
@RestController
@RequestMapping("/trans")
public class TransactionalController {@Autowiredprivate UserService userService;//数据库事务管理器@Autowiredprivate DataSourceTransactionManager dataSourceTransactionManager;//关于事务的一些配置,用默认的即可@Autowiredprivate TransactionDefinition transactionDefinition;@RequestMapping("/addUser")public Integer addUser(String username,String password){//~获取事务TransactionStatus transaction = dataSourceTransactionManager.getTransaction(transactionDefinition);User user = new User(username,password);Integer result = userService.insert(user);log.info("插入操作");//回滚到当时事务的状态
//        dataSourceTransactionManager.rollback(transaction);
//        log.info("回滚操作");//事务的提交dataSourceTransactionManager.commit(transaction);log.info("事务提交");return result;}
}

3. 声明式事务@Transactional

加上@Transactional即可自动处理事务

另外这个注解可以加到方法上也可以加到类上

  • 修饰方法时: 需要注意只能应用到 public 方法上,否则不生效。推荐此种用法。
  • 修饰类时: 表明该注解对该类中所有的 public 方法都生效
import lombok.extern.slf4j.Slf4j;
import mybatis.model.User;
import mybatis.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@Slf4j
@RestController
@RequestMapping("/trans2")
public class TransactionalController2 {@Autowiredprivate UserService userService;@Transactional@RequestMapping("/addUser")public Integer addUser(String username,String password){User user = new User(username,password);Integer result = userService.insert(user);log.info("影响行数:"+result);
//        int a=10/0;   //当发生了异常,事务会自动回滚return result;}
}

3.1. 可能遇到的问题

@Transactional默认只在遇到运行时异常(RuntimeException及其子类)和Error时才会回滚, 其他的(例如IOException)不回滚, 具体可以看异常的分类

@Transactional在异常被捕获的情况下(try-catch),不会进行事务自动回滚

③在测试类里总是会回滚

3.2. @Transactional参数说明

3.2.1. 示例

noRollbackFor

参数设置为@Transactional(noRollbackFor = ArithmeticException.class), 当出现了算术运算异常(ArithmeticException), 例如int a=10/0, 虽然会抛异常, 但并不会回滚

rollbackFor

对于上面的问题@Transactional默认只在遇到运行时异常的时候才回滚, 所以为了所有异常都要回滚, 可以设置@Transactional(rollbackFor = Exception.class)让他所有异常都会回滚.

4. 事务的隔离级别

  • 脏读: 一个事务读取到了另一个事务修改的数据之后,后一个事务又进行了回滚操作,从而导致第一个事务读取的数据是错误的。
  • 不可重复读: 一个事务两次查询得到的结果不同,因为在两次查询中间,有另一个事务把数据修改了。
  • 幻读: 一个事务两次查询中得到的结果集不同,因为在两次查询中另一个事务有新增了一部分数据。

4.1. Spring事务的隔离级别

@Transactional注解里设置

5. 事务的传播机制

5.1. Spring事务的传播机制

5.1.1. 示例

如果C事务执行失败,B事务执行成功, 那么B和A最终是否能够成功?

不同的事务传播机制, 结果是不同的

5.1.1.1. REQUIRED

Propagation.REQUIRED: 默认的事务传播级别,它表示如果当前存在事务,则加入该事务,如果

当前没有事务,则创建一个新的事务。

对于上面的例子, B,C被加入到A事务, 如果C事务执行失败, 代表整个事务失败, 则会回滚

5.1.1.2. SUPPORTS

Propagation.SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的

方式继续运行。

如果A不是事务, B是事务, 那么B事务会取消

5.1.1.3. MANDATORY

Propagation.MANDATORY: (mandatory: 强制性) 如果当前存在事务, 则加入该事务;如果当前没有事务, 则抛出异常

5.1.1.4. REQUIRES_NEW

Propagation.REQUIRES_NEW: 表示创建一个新的事务,如果当前存在事务,则把当前事务挂

起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部方法会新开

启自己的事务,且开启的事务相互独立,互不干扰。

5.1.1.5. NOT_SUPPORTED

Propagation.NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起

5.1.1.6. NEVER

Propagation.NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。

5.1.1.7. NESTED

Propagation.NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如

果当前没有事务,则该取值等价于 PROPAGATION_REQUIRED。

6. 使用演示

数据库准备

drop table if exists userlog;create table userlog(id int primary key auto_increment,username varchar(100) not null,createtime datetime default now(),updatetime datetime default now()
) default charset 'utf8mb4';

6.1. 支持当前事务(required)

新建UserLog类方便传参数

import lombok.Data;
import java.util.Date;@Datapublic class UserLog {private Integer id;private String username;private Date createtime;private Date updatetime;public UserLog() {}public UserLog(String username) {this.username = username;}}

定义UserLogMapper接口

import mybatis.model.UserLog;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface UserLogMapper {@Insert("insert into userlog (username) values (#{username})")public Integer insertLog(UserLog userLog);
}

实现UserLogService

import mybatis.mapper.UserLogMapper;
import mybatis.model.UserLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserLogService {@Autowiredprivate UserLogMapper userLogMapper;@Transactional(propagation = Propagation.REQUIRED)public Integer insertLog(UserLog userLog){return userLogMapper.insertLog(userLog);}
}

定义Controller, 记得给addUser方法加上@Transactional, 还有UserLogService和UserService都加上@Transactional, 这样就可以演示Propagation.REQUIRED: 默认的事务传播级别,它表示如果当前存在事务,则加入该事务,如果当前没有事务,则创建一个新的事务. 当UserLogService和UserService和Controller都有@Transactional, 会默认把UserLogService和UserService事务合并到Controller的事务

import mybatis.model.User;
import mybatis.model.UserLog;
import mybatis.service.UserLogService;
import mybatis.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/trans3")
public class TransactionalController3 {@Autowiredprivate UserService userService;@Autowiredprivate UserLogService userLogService;@Transactional@RequestMapping("/addUser")public boolean addUser(String username,String password){//1.插入用户表User user = new User(username,password);userService.insert(user);//2.插入日志表UserLog userLog = new UserLog(username);userLogService.insertLog(userLog);return true;}
}

当我们主动让UserLogService和UserService其中一个出现异常, 那么网页会返回错误码500, 然后另外一个操作并不会成功, 而是会事务回滚

6.2. requires_new

当我们把UserLogService和UserService的@Transactional都设置为@Transactional(propagation = Propagation.REQUIRES_NEW). 即创建一个新的事务,如果当前存在事务,则把当前事务挂起, 不用他的事务, 用自己新的事务.

让UserLogService出现异常, 此时, 网页错误码500, userInfo成功被插入数据, 但userLog没有被插入内容

6.3. never

UserService设置一个@Transactional(propagation = Propagation.NEVER), 会报错, 因为不该有事务却发现了一个事务, 结果是数据库并没有被插入数据

6.4. nested

UserLogService和UserService都改成@Transactional(propagation = Propagation.NESTED). 两个都成功都成功, 其中一个失败, 都失败.

当我们将异常捕获, 并用下面的方法回滚, 那么没错的会插入到数据库, 出现异常的不会插入.

try {int a=1/0;
}catch (Exception e){TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}

嵌套事务, 允许部分回滚. 而required只能全部回滚, 同样的情况, 两个都不能插入成功. (required表示如果当前存在事务,则加入该事务, 相当于把这个回滚也整体加入到了上层事务里, 导致全部回滚)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/99005.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

认识Redis

1. 前置操作 以下内容基于CentOS 1.1. 安装 yum -y install redis 1.2. 启动 redis-server /etc/redis.conf & 1.3. 打开 redis-cli 1.4. 停止 redis-cli shutdown 1.5. 设置远程连接 修改 /etc/redis/redis.conf 修改 bind 127.0.0.1为 bind 0.0.0.0 1.6. 使用…

docker优点简介和yum方式安装

一.docker简介 二.docker的优点 1.交付和部署速度快 2.高效虚拟化 3.迁移性和扩展性强 4.管理简单 三.docker的基本概念 1.镜像 2.容器 3.仓库 四.docker的安装部署 (1)点击容器 ​(2)选择docker-ce,根据相…

OAuth2.0一 Spring Security OAuth2.0

这里主讲OAuth2.0 学习OAuth2前提: 掌握Spring Security Spring Security学习 一 OAuth2.0介绍 OAuth(Open Authorization)是一个关于授权(authorization)的开放网络标准,允许用户授权第三方应用访问他们…

Docker容器:docker镜像的创建及dockerfile

Docker容器:docker镜像的创建及dockerfile案例 一.docker镜像的三种创建方法 创建镜像有三种方法:基于现有镜像创建、基于本地模板创建及基于dockerfile创建 1.基于现有镜像创建 1.1 启动镜像 #首先启动一个镜像,在容器里做修改 docker …

诚迈科技荣膺小米“最佳供应商奖”

近日,诚迈科技受邀参加小米战略合作伙伴HBR总结会。诚迈科技以尽职尽责的合作态度、精益求精的交付质量荣膺小米公司颁发的最佳供应商奖,其性能测试团队荣获优秀团队奖。 诚迈科技与小米在手机终端方向一直保持着密切的合作关系,涉及系统框架…

JUC学习笔记(一)

1. JUC概述及回顾 1.1. JUC是什么? 在 Java 5.0 提供了 java.util.concurrent(简称JUC)包,在此包中增加了在并发编程中很常用的工具类。此包包括了几个小的、已标准化的可扩展框架,并提供一些功能实用的类,没有这些类&#xff0…

LeetCode算法递归类—二叉树的右视图

目录 199. 二叉树的右视图 题解: 目标: 思路: 过程: 代码: 运行结果: 给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所…

SpringBoot的日志信息及Lombok的常用注解

文章目录 一. 日志的介绍1. 什么是日志2. 日志的作用 二. 日志的使用1. 日志格式说明2. 自定义日志的输出3. 日志级别4. 日志级别的配置5. 日志持久化6. 更简单的输出日志-Lomok7. Lombok框架实现原理以及其他常见注解 一. 日志的介绍 1. 什么是日志 日志是我们程序重要组成部…

深度学习入门-3-计算机视觉-图像分类

1.概述 图像分类是根据图像的语义信息对不同类别图像进行区分,是计算机视觉的核心,是物体检测、图像分割、物体跟踪、行为分析、人脸识别等其他高层次视觉任务的基础。图像分类在许多领域都有着广泛的应用,如:安防领域的人脸识别…

企业微信电脑端开启chrome调试

首先: Mac端调试开启的快捷键:control shift command d Window端调试开启的快捷键: control shift alt d 这边以Mac为例,我们可以在电脑顶部看到调试的入口: 然后我们点击 『浏览器、webView相关』菜单,勾选上…

fastadmin 下拉多级分类

要实现下图效果 一、先创建数据表 二、在目标的controll中引入use fast\Tree; public function _initialize() {parent::_initialize();$this->model new \app\admin\model\zxdc\Categorys;$tree Tree::instance();$tree->init(collection($this->model->order(…

React请求机制优化思路 | 京东云技术团队

说起数据加载的机制,有一个绕不开的话题就是前端性能,很多电商门户的首页其实都会做一些垂直的定制优化,比如让请求在页面最早加载,或者在前一个页面就进行预加载等等。随着react18的发布,请求机制这一块也是被不断谈起…

vue + vue-office 实现多种文件(docx、excel、pdf)的预览

支持多种文件( docx、excel、pdf)预览的vue组件库,支持vue2/3。也支持非Vue框架的预览。 github: 《仓库地址》 演 示: 《演示效果》 功能特色 一站式:提供docx、pdf、excel多种文档的在线预览方案,有它就够了简单&#xff1a…

⛳ Java 网络编程

目录 ⛳ Java 网络编程🎨 一、TCP / IP 协议👣 二、IP 和 端口号🎁 三、TCP 网络层编程🎨 3.1、Socket⭐ 3.2、基于Socket的TCP编程 🏭 四、UDP网络编程🐾 五、URL编程 ⛳ Java 网络编程 🎨 一…

SpringBoot + Vue 微人事项目(第三天)

左边导航菜单制作 element ui添加到Home 把侧栏的标签里面的代码拷贝到标签里面&#xff0c;显示效果如下 左侧导航栏的效果代码 <el-aside width"200px"><el-menu><el-submenu index"1"><template slot"title"><i…

NOIP2014普及组,提高组 比例简化 飞扬的小鸟 答案

比例简化 说明 在社交媒体上&#xff0c;经常会看到针对某一个观点同意与否的民意调查以及结果。例如&#xff0c;对某一观点表示支持的有1498 人&#xff0c;反对的有 902人&#xff0c;那么赞同与反对的比例可以简单的记为1498:902。 不过&#xff0c;如果把调查结果就以这种…

迈向未来的大门:人脸识别技术的突破与应用

迈向未来的大门&#xff1a;人脸识别技术的突破与应用 人脸识别&#xff1a;人脸识别的工作流程人脸识别的作用人脸识别技术的突破与应用 在深度学习人脸识别之前我们要先知道人脸识别是什么。 人脸识别&#xff1a; 人脸识别是一种基于人脸图像或视频进行身份验证或识别的技术…

【数据挖掘】使用 Python 分析公共数据【01/10】

一、说明 本文讨论了如何使用 Python 使用 Pandas 库分析官方 COVID-19 病例数据。您将看到如何从实际数据集中收集见解&#xff0c;发现乍一看可能不那么明显的信息。特别是&#xff0c;本文中提供的示例说明了如何获取有关疾病在不同国家/地区传播速度的信息。 二、准备您的…

【Linux】Centos安装 mariadb 并授权远程登陆

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

无涯教程-Perl - splice函数

描述 此函数从LENGTH元素的OFFSET元素中删除ARRAY元素,如果指定,则用LIST替换删除的元素。如果省略LENGTH,则从OFFSET开始删除所有内容。 语法 以下是此函数的简单语法- splice ARRAY, OFFSET, LENGTH, LISTsplice ARRAY, OFFSET, LENGTHsplice ARRAY, OFFSET返回值 该函数…