springboot项目中手动提交事务

这篇具有很好参考价值的文章主要介绍了springboot项目中手动提交事务。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

演示主要代码

@Service 层代码

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

@Service
@Transactional(rollbackFor = Exception.class)
public class XlServiceImpl {
	Logger logger = LoggerFactory.getLogger(this.getClass());
	@Autowired
	private XlMapper xlMapper;
	
	/**
	 * 需求:mi()方法抛出异常,不影响本方法:本方法不回滚!
	 * mi抛出异常后,insert1()正常插入
	 * @param id
	 * @return
	 * @throws Exception
	 */
	public String doInsert() throws Exception {
		xlMapper.insert1();
		mi();
		return "200";
	}
	
	/**
	 * 需求:本方法抛出异常时,回滚
	 * 抛出异常后,insert2()回滚:不插入
	 */
	private void mi() {
		xlMapper.insert2();
		int x = 0;
		int y = 3 / x; // 
	}

}

Mapper接口层代码: insert1()和insert2()的插入SQL

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Update;

public interface XlMapper {

    @Update("UPDATE xl999 SET age=333 WHERE id=#{id}")
	Integer updateById(Integer id);
    
    @Insert("INSERT INTO xl (name,age,create_time) VALUES('dp1',111,NOW())")
    Integer insert1();
    
    @Insert("INSERT INTO xl (name,age,create_time) VALUES('dp2',222,NOW())")
    Integer insert2();
}

controller层代码

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ClassForTest {
	Logger logger = LoggerFactory.getLogger(this.getClass());

	@Autowired
	private XlServiceImpl xlServiceImpl;

	@GetMapping("/dosth")
	public String doSth() throws Exception {
		String affect = "";
		affect = xlServiceImpl.doInsert();
		return affect;
	}
}

数据库表结构及初始数据

springboot手动提交事务,# spring笔记,spring,spring boot,java,手动提交事务,事务

场景/需求/实际效果

  1. 场景
    在spring的声明式事务@Transactional(rollbackFor = Exception.class)的类XlServiceImpl中:
  • 有其中一个方法doInsert()调用另外一个方法mi()
  • doInsert()会调用Mapper接口的insert1()方法向数据库中插入一条数据,然后会调用方法mi()。
  • mi()会调用Mapper接口的insert2()方法向数据库中插入一条数据,然后会抛出异常。
  1. 需求
    insert1()可以正常插入,insert2()回滚,不会插入!

  2. 实际效果
    运行项目,调用方法,结果如下:

  • 页面:
    springboot手动提交事务,# spring笔记,spring,spring boot,java,手动提交事务,事务
  • 程序后台
    springboot手动提交事务,# spring笔记,spring,spring boot,java,手动提交事务,事务
  • 数据库: 与初始数据库数据一致,并没有数据插入——与需求中的 insert1()成功插入不符合。

springboot手动提交事务,# spring笔记,spring,spring boot,java,手动提交事务,事务

解决办法 :在mi方法中手动提交事务

  1. 在@Transactional(rollbackFor = Exception.class)类中注入spring的事务管理器PlatformTransactionManager:
	/**
	 * 引入 (平台)事务管理器,Spring 事务策略的核心。
	 */
	@Autowired
	private PlatformTransactionManager transactionManager;
  1. 在mi方法中手动提交事务/回滚事务
	/**
	 * 需求:本方法抛出异常时,回滚 抛出异常后,insert2()回滚:不插入
	 */
	private void mi() {
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);// 新发起一个事务
		TransactionStatus status = transactionManager.getTransaction(def);// 获得事务状态
		try {
			xlMapper.insert2();
			int x = 0;
			int y = 3 / x;
			// 手动提交事务
			transactionManager.commit(status);
		} catch (Exception e) {
			// 手动回滚事务
			transactionManager.rollback(status);
		}
	}
  1. 运行项目,调用方法,查看效果:
    springboot手动提交事务,# spring笔记,spring,spring boot,java,手动提交事务,事务
  2. 进一步测试:注释掉下面两行,效果虽然是一样的,但是,还是写上最好!!
transactionManager.commit(status);
transactionManager.rollback(status);

mi()的完整代码:

/**
	 * 需求:本方法抛出异常时,回滚 抛出异常后,insert2()回滚:不插入
	 */
	private void mi() {
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);// 新发起一个事务
		TransactionStatus status = transactionManager.getTransaction(def);// 获得事务状态
		try {
			xlMapper.insert2();
			int x = 0;
			int y = 3 / x;
			// 手动提交事务
//			transactionManager.commit(status);
		} catch (Exception e) {
			// 手动回滚事务
//			transactionManager.rollback(status);
		}
	}

以上说明:真正起作用的是下面3行:

		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);// 新发起一个事务
		TransactionStatus status = transactionManager.getTransaction(def);// 获得事务状态

而,这3行中又起关键作用的是最后一行 :

TransactionStatus status = transactionManager.getTransaction(def);// 获得事务状态

springboot手动提交事务,# spring笔记,spring,spring boot,java,手动提交事务,事务
通过第2句可知:最后一句是创建一个新事务!而这个新事务会自动完成提交和回滚,所以注释掉 提交和回滚的代码效果是一样的!!
特别注意:

  1. @Transactional(rollbackFor = Exception.class) 方式创建的事务,如果将异常catch后,在catch块中不再抛出异常,是不会触发回滚的!
  2. 但是,在方法中显示手动创建一个事务:
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);// 新发起一个事务
		TransactionStatus status = transactionManager.getTransaction(def);// 获得事务状态

这种手动方式创建的事务,在catch块中可以不用再抛出异常,也可以不用显示的写出:transactionManager.rollback(status); ,会自动进行回滚!

  1. 在方法中手动创建事务时,transactionManager.rollback(status); 最多只能执行一次,如果方法中有2个及以上地方调用的transactionManager.rollback(status); 回滚方法,那么程序就会抛出异常!如下:
    springboot手动提交事务,# spring笔记,spring,spring boot,java,手动提交事务,事务
    springboot手动提交事务,# spring笔记,spring,spring boot,java,手动提交事务,事务

  2. 在方法中如果执行了事务提交:transactionManager.commit(status); 后面再去执行事务回滚transactionManager.rollback(status);,也会报上图的错误 “事务已完成——不要再同一个事务中提交或回滚超过一次”

也就是说,不管是提交事务,还是回滚事务,二者只能有一个执行并且只能执行一次!!!

springboot手动提交事务,# spring笔记,spring,spring boot,java,手动提交事务,事务

Spring的7中事务传播行为

Propagation.REQUIRED 代表当前方法支持当前的事务,且与调用者处于同一事务上下文中,回滚统一回滚(如果当前方法是被其他方法调用的时候,且调用者本身即有事务),如果没有事务,则自己新建事务,
Propagation.SUPPORTS 代表当前方法支持当前的事务,且与调用者处于同一事务上下文中,回滚统一回滚(如果当前方法是被其他方法调用的时候,且调用者本身即有事务),如果没有事务,则该方法在非事务的上下文中执行
Propagation.MANDATORY 代表当前方法支持当前的事务,且与调用者处于同一事务上下文中,回滚统一回滚(如果当前方法是被其他方法调用的时候,且调用者本身即有事务),如果没有事务,则抛出异常
Propagation.REQUIRES_NEW 创建一个新的事务上下文,如果当前方法的调用者已经有了事务,则挂起调用者的事务,这两个事务不处于同一上下文,如果各自发生异常,各自回滚
Propagation.NOT_SUPPORTED 该方法以非事务的状态执行,如果调用该方法的调用者有事务则先挂起调用者的事务
Propagation.NEVER 该方法以非事务的状态执行,如果调用者存在事务,则抛出异常
Propagation.NESTED 如果当前上下文中存在事务,则以嵌套事务执行该方法,也就说,这部分方法是外部方法的一部分,调用者回滚,则该方法回滚,但如果该方法自己发生异常,则自己回滚,不会影响外部事务,如果不存在事务,则与PROPAGATION_REQUIRED一样

springboot手动提交事务,# spring笔记,spring,spring boot,java,手动提交事务,事务文章来源地址https://www.toymoban.com/news/detail-780404.html

到了这里,关于springboot项目中手动提交事务的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 手动创建Spring Boot 2.x项目

    创建SpringBoot可以选择手动 也可以利用官方脚手架, 对于新手来说, 先手动创建是个不错的选择 JDK1.8 或以上 Gradle 4+ or Maven 3.2+ IDE、Eclipse 注意 ,拉包慢的记得配置一下阿里源, 否则浪费时间, 配置阿里源再 Maven快速入门 这篇文章里面有 再说一下以上填写的基本规则吧。 group

    2024年02月08日
    浏览(27)
  • SpringBoot项目中控制线程池、多线程事务提交、回滚的方式

    场景: 1、由于多线程每个线程都是一个异步任务,所以每个线程都是一个单独的事务,通常使用的声明式事务 @Transactional() 是无法控制多线程中事务的 2、所以只能另寻解决方式 解决: 一、基于TransactionStatus集合来控制多线程事务提交(推荐此方式) 1、代码案例

    2024年02月15日
    浏览(51)
  • for循环中循环一次提交一次 insert update 关闭事务 spring springboot mybatis

     在方法上直接加如下注解: 在测试的时候,有时候会希望在for循环中,代码循环一次就提交一次事务。 最简单的方式,就是关闭事务,不需要事务。添加注解如下: 如果说是真的在生产上有这样的需要,每循环一次就提交事务,那就需要手动控制事务了。 需要这几行代码

    2024年02月07日
    浏览(46)
  • Java企业级信息系统开发学习笔记(4.2)Spring Boot项目单元测试、热部署与原理分析

    该文章主要为完成实训任务,详细实现过程及结果见【http://t.csdn.cn/pG623】 1. 添加测试依赖启动器和单元测试 修改pom.xml文件,添加依赖 刷新项目依赖 2. 创建测试类与测试方法 在 src/test/java 里创建 cn.kox.boot 包,创建测试类 TestHelloWorld01 给测试类添加测试启动器注解与Spring

    2024年02月10日
    浏览(52)
  • springboot设置手动事务实战

    1.注入

    2024年02月16日
    浏览(37)
  • 【Spring Boot】Spring Boot项目中如何查看springBoot版本和Spring的版本

    在项目中查看默认版本有两种方式如下 Spring Boot 的最新版本支持情况: 版本 发布时间 停止维护时间 停止商业支持 3.0.x 2022-11-24 2023-11-24 2025-02-24 2.7.x 2022-05-19 2023-11-18 2025-02-18 2.6.x 2021-12-17 2022-11-24 2024-02-24 2.5.x 2021-05-20 已停止 2023-08-24 2.4.x 2020-11-12 已停止 2023-02-23 2.3.x 2020-05-

    2024年02月11日
    浏览(97)
  • Spring Boot 笔记 021 项目部署

    1.1 引入坐标,并双击package打包成jar包 1.2 在服务器上运行jar包 1.3 使用postman测试 2.1 运行配置 2.1.1 命令更改端口 java -jar big-event-1.0-SNAPSHOT.jar --server.port=7777 2.1.2 环境变量更新(略) 2.1.3 外部配置文件,在jar包同目录下配置application.yml文件(略) 3.1 多环境开发(开发,测试

    2024年02月21日
    浏览(36)
  • 手动将Java SpringBoot项目部署到云服务器上(使用docker)

    本文记录一下我作为一个小白如何通过docker手动将java springboot项目部署到云服务器上(以腾讯云的轻量应用服务器为例)。 但是我个人还是推荐安装一个宝塔面板部署 ,真的全程自动化,非常方便,网上有很多相关的教程可以搜搜看。所以我写这个教程其实只想记录一下我

    2024年04月25日
    浏览(43)
  • 【SpringBoot】Spring Boot 项目中整合 MyBatis 和 PageHelper

    目录 前言         步骤 1: 添加依赖 步骤 2: 配置数据源和 MyBatis 步骤 3: 配置 PageHelper 步骤 4: 使用 PageHelper 进行分页查询 IDEA指定端口启动 总结         Spring Boot 与 MyBatis 的整合是 Java 开发中常见的需求,特别是在使用分页插件如 PageHelper 时。PageHelper 是一个针对 MyBat

    2024年04月25日
    浏览(51)
  • springboot Junit单元测试默认事务不提交

    因为以前总觉得Junit单元测试配置比较繁琐,代码功能大多使用main方法或者postman测试,直到最近才使用单元测试,在测试过程中遇到了事务不提交的问题,一直以为是代码问题,后来才直到单元测试 默认不提交事务 ,记录下来,防止以后再次踩坑。 如上,入库操作不会实现

    2024年02月10日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包