首页 > 其他分享 >spring事务里面开启线程插入,报错了是否会回滚?

spring事务里面开启线程插入,报错了是否会回滚?

时间:2023-04-12 23:33:52浏览次数:42  
标签:status 回滚 spring element 插入 线程 报错

1.前言

一道非常有意思的面试题目。大概是这样子的,如果在一个事务中,开启线程进行插入更新等操作,如果报错了,事务是否会进行回滚

2.代码

示例1

@RequestMapping("/test/publish/submit")
public String testPublish1() {

	log.info("start...");
	transactionTemplate.execute(new TransactionCallback<String>() {
		@Override
		public String doInTransaction(TransactionStatus status)  {

			TElement element = new TElement();
			element.setfElementId(10L);
			element.setfElementName("111");
			mapper.insertSelective(element);


			element = new TElement();
			element.setfElementId(10L);
			element.setfElementName("222");
			mapper.insertSelective(element);

			return "OK";
		}
	});
	log.info("end...");

	return "ok";
}

示例2

@RequestMapping("/test/publish/submit2")
public String testPublish2() {

	log.info("start...");
	transactionTemplate.execute(new TransactionCallback<String>() {
		@Override
		public String doInTransaction(TransactionStatus status)  {
			es.submit(() -> {
				TElement element = new TElement();
				element.setfElementId(10L);
				element.setfElementName("111");
				mapper.insertSelective(element);
			});

			es.submit(() -> {
				TElement element = new TElement();
				element.setfElementId(10L);
				element.setfElementName("222");
				mapper.insertSelective(element);
			});

			return "OK";
		}
	});
	log.info("end...");

	return "ok";
}

3.结论

示例1

element.setfElementId(10L); 为主键。SQL在第一次插入id=10的时候是没有问题的,在第二次插入id=10的时候,由于主键冲突了,导致报错,然后整个事务都会进行回滚,这是没有问题的。是spring的事务帮助我们来进行回滚等操作的。我们可以看到如下代码,他是对整个result = action.doInTransaction(status);进行了try catch。如果抛异常,就会回滚

@Override
@Nullable
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
	Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");

	if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
		return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
	}
	else {
		TransactionStatus status = this.transactionManager.getTransaction(this);
		T result;
		try {
			result = action.doInTransaction(status);
		}
		catch (RuntimeException | Error ex) {
			// Transactional code threw application exception -> rollback
			rollbackOnException(status, ex);
			throw ex;
		}
		catch (Throwable ex) {
			// Transactional code threw unexpected exception -> rollback
			rollbackOnException(status, ex);
			throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
		}
		this.transactionManager.commit(status);
		return result;
	}
}

示例2

示例2首先是transactionTemplate.execute是一个主main线程。然后在第一个子线程插入了一个数据,第二个子线程也插入了一个数据。那么现在就是有三个线程,一个是main线程,一个是A线程,一个是B线程。
main线程正常执行不报错,A线程正常插入不报错,B线程由于主键冲突报错。
我们可以通过上面action.doInTransaction(status);看出来,他对这块代码进行了try catch。也就是主线程进行了try catch。那么也就是只要主线程没有报错,这个事务就不会被捕获,也就不会回滚了。无论你A,B还是CDEFG子线程出问题了,只要不影响main线程,那事务就不会回滚呢?
因此我们可以得出一个结论,在示例2中,A线程会插入成功,B线程插入失败,事务不会回滚,最终插入成功。这个其实与我们平常的想法所违背了。
因此如果想要主线程抛出异常,得让主线程感知到子线程异常了,主动地去throw异常。比如我们可以设置一个flag,子线程报错了 flag=true。主线程检测到flag为true,就主动抛出一个exception

4.最后

这道面试题非常有意思,起初以为会回滚,没想到不会回滚。查看代码得知,原来是catch住的是主线程,并不是子线程。同样注解式事务类似。因此如果想要事务生效,尽量避免在事务中使用多线程来进行插入更新等操作

标签:status,回滚,spring,element,插入,线程,报错
From: https://www.cnblogs.com/wenbochang/p/17311858.html

相关文章

  • SpringBoot向web容器注入Servlet,Filter及SpringSecurity注册DelegatingFilterProxy
    从SpringSecurity架构图可知SpringSecurity的过滤器与Web容器的过滤器是通过DelegatingFilterProxy接入的。由DelegatingFilterProxy代理了FilterChainProxy,FilterChainProxy包含了SpringSecurity的过滤器链。 那么DelegatingFilterProxy是怎么创建及如何加入到Web容器中? 看......
  • Springmvc常用注解参数与返回值
    1.常用注解1.1.@RequestMapping@RequestMapping注解是一个用来处理请求地址映射的注解,可用于映射一个请求或一个方法,可以用在类或方法上。标注在方法上用于方法上,表示在类的父路径下追加方法上注解中的地址将会访问到该方法@ControllerpublicclassHelloController{......
  • 运行gradle的时候报错有问题
    build.gradle文件内容   taskhello<<{       println'Helloworld!'    }解决方法去掉build.gradle文本中的 <<另外一种报错:CouldnotfindmethodleftShift()forarguments[build_8yh4yhrvtp0jzm7d9zc2f2gyq$_run_closure4@50b42bfc]ontask':bu......
  • Springmvc入门
             1.什么是springmvcSpringWebMVC是一种基于Java的实现了MVC设计模式的、请求驱动类型的、轻量级Web框架。ssm:即springmvc,spring,mybatis  2.项目中加入springmvc支持2.1导入依赖<dependency><groupId>org.springframework</groupI......
  • Springboot三种启动方式
    在https://start.spring.io/上创建一个springboot工程生成的代码中的启动方式咱们暂时定义为默认方式:/***@auther:lawt*@date:2018/12/117*@Description:默认启动方式*/@SpringBootApplicationpublicclassMicroServicesSpringBootApplication{publicstaticv......
  • springboot 中的 classpath 指的是什么路径?
    classpath其本质其实是指项目打包后的classes下的路径,一般用来指代“src/main/resources”下的资源路径。通常会在各种配置文件中使用【classpath】关键字,例如:yml配置文件:WebMvcConfigurer配置类:......
  • springboot整合阿里云OSS实现多线程下文件上传(aop限制文件大小和类型)
    内容涉及:springboot整合阿里云oss自定义注解及aop的使用:对上传文件格式(视频格式、图片格式)、不同类型文件进行大小限制(视频和图片各自自定义大小)线程池使用:阿里云OSS多线程上传文件阿里云OSS分片上传大文件 业务需求需求一:前端传递单个或多个小文件(这里......
  • taro 3.0 官方模板运行报错 插件依赖 "@tarojs/plugin-platform-h5" 加载失败
    taroError:插件依赖"@tarojs/plugin-platform-h5"加载失败,请检查插件配置报错如下,原因:node版本的问题,使用nvm切换node版本就可以了......
  • 解决Spring boot 单元测试,无法读取配置文件问题。
    1.启动类上加上@EnableConfigurationProperties2.springboot版本springboot2.X版本在单元测试中读取不到yml配置文件的值这是个大坑,在项目中写单元测试的时候需要读取一个yml配置文件的值,发现无论如何都读取不到,后来发现了这个坑。改成properties就行了。或者增加@RunWith(Spr......
  • spring引导安装
    1.启动一个spring引导项目2.复制代码3.下载jdk设置环境变量运行报错......