当前位置:首页 » 操作系统 » spring多线程数据库

spring多线程数据库

发布时间: 2023-04-03 13:13:20

1. spring的申明事务和多线程的关系

1、会话可以创建多个事务
比如:使用客端连接数据库,这样你就可以执行很多个事务了
2、一个事务只能由一个会话产生
在数据库里的事务,如果在执行的sql都是由会话发起的,哪怕是自动执行的JOB也是由系统会话发起的
3、一个事务可能会产生一个或多个线程
比如RMAN备份,是可以创建多个线程可加快备份速度
4、一个线程在同一时间内只能执行一个事务
而一个线程,在没结束当前事务是无法释放资源来执行第二个事务敏宴碧
事务、会话与线程的关系和区别
我一直没弄明白数据库中的这三个概念之间的关系。
事务:简单理解局势一个业务需求的最小处理单位。
如:从A银行卡转账500元到B银行卡,事务就包括两部分,1、从A卡减掉500元 2、从B卡加上500元
这两个部分只要一个部分出错,就要桥举整体“回滚”,那这就是一个事务
会话:可以包含N个事务
如:你登陆网银之后,可以重复转账祥银步骤2次,第二次转账失败,并不影响你第一次转账成功。
线程:一个事情,一个人干和多个人干的问题
如:比如植树,任务是植树500棵,一个人(线程)干5天,那五个人(线程)干1天。
至于会话和线程的关系,个人理解,植树任务就是一个session
一个会话中可以由多个事务。
线程是操作系统概念。

2. 一篇让你学会 11个Spring 失效场景

其实关于spring事务失效的场景,网络上文章介绍的不少,参差不齐。这里只分享下自己的见解,时长大概10分钟左右,先上个图介绍下。

事务方法需要定义public,非public方法事务会失效。事务拦截器TransactionalInterceptor会在执行方法前进行拦截,通过动态代理方式如果是cglib就是intercept方法或者jdk的invoke方法间接调用类的getTransactionAttribute方法获取配置信息,附上源码图:

进一步的跟踪getTransactionAttribute方法,我们就能看到,spring对于非public修饰的方式,返回的事务对象是null,其中allowPublicMethodsOnly返回的是一个布尔false。

事务底层使用了aop,那么也就是说通过jdk或者是cglib生成代理类,在代理类中实现的事务的功能,如果说方法是final修饰的了,那么就会导致代理类中无法重写该方法,从而导致添加事务失败。同样的如果是static的修饰的话也是无法通过动态代理变成事务方法。

简单来说就是一个方法内部调用另一个方法,但是另一个方式是有事务的,这样也会导致事务失效,因为这个调用的是this对象的方法,而不是另一个方法持有的对象,可以这里理解。

如果想要在方法内部调用另一个方法也有事务的话,就需要新建一个service对象持有。

这样,通过新建一个service方法,将事务添加到新建的service方法里就可以了。说到这里可能小伙伴觉得这样有点麻烦,那么是否有没有其他的方式不新建一个方法呢,答案是可以的,就是注入自己,利用了spring ioc内部的三级缓存的机制,这里注入自己就很好的保证了也不会出现循环依赖:

其实到了这一步,还是发现有点不太雅观,并不是说上面代码有什么问题只是觉得,可以让上面代码更加好看一点,那么有没有呢,答案是有的,是什么呢?这就不得不佩服spring强大完善的支持,那就是AopContext.currentProxy(),这个就是创建代理类,在方法调·调用前后切入,这个代理类对象是保存在ThreadLocal中的,所以通过这个代理类对象调用事务方法就能生效了。

这样看来,代码是不是就优雅多了,哈哈!!!

这里需要明确一个前提,就是使用spring事务的前提,就是对象要被spring管理就需要创建bean实例,在开发中,我们都是通过@Controller,@Service,@Component,@Repository等注解自动的实现依赖注入实例化的功能,但假如说在相应的控制层,业务层,数据层忘记加相应的注解,那么也是会失效的。因为没有交给spring管理,例如:

回想起前几年配置事务管理器时,都会有这样的一段配置:

通过这一段配置也可以知道,其实spring事务就是通过数据库连接事务多线程连接会导致持有的connetion不是同一个,从网上找了一张图,通过这张图进一步理解:

接着附上伪代码结合上面的图进一步理解:

事务add方法中调用了另一个事务doOtherThing,但是事务方法是在另一个线程中调用的,这样就会导致两个方法不在同一个线程中,获取到的数据库链接不一样,是两个不同的事务,一旦doOtherThing发生异常,add方法也是不可能发生回滚的.这里需要解释以下什么是同一个事务,也就是说只有拥有同一个数据库连接才能同时提交和回滚。如果在不同的线程,拿到的数据库连接肯定是不一样的,所以是不同的事务。

这个就没什么好讲的了,也就是innodb和myisam引擎的不同,5版本以前默认是myisam引擎,这个引擎是不支持事务的,5版本以后的innodb是支持事务的。

这个其实可能也是比较容易忽略的,因为我们印象里好像没怎么配置过怎么开启事务,也确实是这样哈,为什么?其实原因很简单,springboot项目通过这个类已经默默的为我们开启了事务。

这个类会加载spring.datasource这个配置文件从而启动事务,如果是非springboot项目就需要自己手动在xml文件中配置事务管理器。

类似这样的从而开启事务。

在使用@Transactional注解时,是可以指定propagation参数的,该参数是用来指定事务的传播特性,其中只有required,requires_new,nested这三种才会创建新事务:

像上面的Propagation.NEVER这种类型的传播特性不支持事务,如果有事务则会抛异常。

像这种手动try...catch了异常,又没有手动抛出,那么sring就会认为程序是异常的就不会回滚了。

捕获了异常又抛出了exception异常,事务同样不会回滚,因为spring事务默认情况下只会回滚RuntimeException(运行时异常)和Error(错误),对于普通的Exception(非运行时异常),不会回滚,网上找了一张图:

这里exception里除了分为运行时异常和非运行时异常(ioException)。

1) 让checked例外也回滚:

在整个方法前加上 @Transactional(rollbackFor=Exception.class)

2) 让unchecked例外不回滚:

@Transactional(notRollbackFor=RunTimeException.class)

3)不需要事务管理的(只查询的)方法:@Transactional(propagation=Propagation.NOT_SUPPORTED)

这里需要提及的一句是,如果是自定义了的异常,比如说我自定义了DALException异常,那么就应该是@Transactional(notRollbackFor=DALException.class),一旦抛出的异常不属于DALException异常,那么事务也是不会生效的。

其实这个就有点像是js里的冒泡事件,可能我只是需要底部,结果外层窗口事件也触发了,联想到事务这里,那么也是一样的,嵌套多个可能只是想回滚对应的事务,就不用把其他事务也回滚了,这个可以通过try...catch来处理,将需要处理回滚的事务放这里面就不会把外层的也会滚了。

3. 平时在spring框架中如何使用多线程

Spring aop 依赖注入的就是单例对象,我们在使用的时候如果有多个相同处理且不怎么耗时的情况下一般会采用for循环直接执行,这样的情况下即使有事务管理也不会影响业务执行下去;但是,大多数的应用比如:系统与系统之间的交互就比较耗时了,此时使用for循环执行业务就不可取了,于行闷是我档扮弯们想用线程来解决这个问题。

另外,附带说明一下:如果是在Spring提供的@Test下测试:如果有多线程处理,需要调用Thread.sleep(3000);实现线程等待,这也是测试多线程模式下所必须的缺清。如果不加线程休眠,不等待多线程执行完毕,很有可能测不出来多线程调用的处理。

4. spring事务失效的几种场景以及原因

spring事务失效场景可能大家在很多文章都看过了,所以今天就水一篇,看大家能不能收获一些不一样的东西。直接进入主题

失效原因: spring事务生效的前提是,service必须是一个bean对象
解决方案: 将service注入spring

失效原因: spring默认只会回滚非检查异常和error异常
解决方案: 配置rollbackFor

失效原因: spring事务只有捕捉到了业务抛出去的异常,才能进行后续的处理,如果业务自己捕获了异常,则事务无法感知
解决方案:
1、将异常原样抛出;
2、设置TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

失效原因: spring事务切面的优先级顺序最低,但如果自定义的切面优先级和他一样,且自定义的切面没有正确处理异常,则会同业务自己捕获异常的那种场景一样
解决郑含方案:
1、在切面中将异常原样抛出;
2、在切面中设置TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

失效原因: spring事务默认生效的方法权限都必须为public

解决方案:
1、将方法改为public;
2、修改TansactionAttributeSource,将publicMethodsOnly改为false【这个从源码跟踪得出结论】
3、开启 AspectJ 代理模式【从spring文档得出结论】

具体步骤:

1、在pom引入aspectjrt坐标以及相应插件

2、在启动类上加上如下配置

注: 如果是在idea上运行,则需做如下配置


4、直接用TransactionTemplate

示例:

失效原因: 子容器扫描范围过大,将未加事务配置的serivce扫描进来

解决方案:
1、父子容器个扫个的范围;
2、不用父子容器,所有bean都交给同一容器管理

注: 因为示例是使用springboot,而springboot启动默认没有父子容器,只有一个容器,因此就该场景就演示示例了

失效原因: 因为spring事务亩轿是用动态代理实现,因此如果方法使用了final修饰,则代理类无法对目标方法进行重写,植入事务功能

解决方案:
1、方法不要用final修饰

失效原因: 原因和final一样

解决方案:
1、方法不要用static修饰

失效原因: 本类方法不经过代理,无法进行增强

解决方案:
1、注入自己来调用;
2、使用@EnableAspectJAutoProxy(exposeProxy = true) + AopContext.currentProxy()

失效原因: 因为spring的事务是通过数据库连接来实现,而数据库连接spring是放在threadLocal里面。同一个事务,只能用同一个数据库连接。而多线程场景下,拿到的数据库连接是不一样的,即是属于不同事务

失效原因: 使用的传播特性不支持事迅丛肆务

失效原因: 使用了不支持事务的存储引擎。比如mysql中的MyISAM

注: 因为springboot,他默认已经开启事务管理器。org.springframework.boot.autoconfigure.jdbc.。因此示例略过

失效原因: 当代理类的实例化早于AbstractAutoProxyCreator后置处理器,就无法被AbstractAutoProxyCreator后置处理器增强

本文列举了14种spring事务失效的场景,其实这14种里面有很多都是归根结底都是属于同一类问题引起,比如因为动态代理原因、方法限定符原因、异常类型原因等

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-transaction-invalid-case

5. spring如何解决多线程的数据操作

看你的数据库的隔离级别,还有orm组件的实现

6. spring如何保证并发的同时保证事务

ThreadLocal来处理。
ThreadLocal天生为解决相同变量的访问冲突问题,所以这个对于spring的默认单例bean的多线程访问是一个完美的解决方案。spring也确实是用了ThreadLocal来处理多线程下相同变量并发的线程安全问题。
要想实现jdbc事务,就必须是在同一个连接对象中此正嫌操作,多个连接下事务就会不可控,需要借助分布式事务完成。那spring如何保证数据库清扒事务在同一森手个连接下执行的呢。

7. “Spring”事务失效的场景

1.数据库引擎不支持事务

Spring 事务生效的前提是所连接的数据库要支持事务,如果底层的数据库引擎都不支持事务,则Spring的事务肯定会失效。

例如: MySQL 用的不是 InnoDB 引擎,而是用的 MyISAM 存储引擎。

2.事务方法未被 Spring 容器管理

如果事务方法所在的类没有加载到 Spring IOC 容器中,也就是说,事务方法所在的类没有被 Spring 容器管理,则Spring事务会失效。

例如:你的方法所在类没有加@Component或者@Service注解。

3.方法没有被 public 修饰

如果事务所在的方法没有被 public 修饰,此时 Spring 的事务也会失效。

4.同一类中方法之间直接的调用

例如:如果同一个类中有两个岁毕方法分别为 A 和 B,方法 A 没有添加事务注解,而方法 B 添加了 @Transactional 事务注解,此时方法 A 直接调用方法 B,则方法 B 的事务会失效。

5.未配置事务管理器

如果在项目中没有配置 Spring 的事务管理器,即使使用了 Spring 的事务管理功能,Spring 的事务也不会生效。

例如:对于 SpringBoot 项目来说,导入了 mybatis 的 starter 依赖后,SpringBoot 会自动注入DataSourceTransactionManager 事务管理器,这样我们就可以直接用 @Transactional 注解使用事务了。

6.事枯行务传播类型不支持事务

如果方法的事务传播类型为不支持事务没雀哗的传播类型,则该方法的事务在 Spring 中会失效。

例如: A 方法的事务传播类型为 NOT_SUPPORTED,不支持事务,此时用带事务的方法 B 去调用 A 方法,则 A 方法的事务失效。

7.进行异常捕捉却没有抛出

比如对某一个新增数据代码段进行 try catch 异常,而 catch 里没有向外抛出异常,此时 spring 事务无法回滚。

8.错误的标注异常类型

如果在 @Transactional 注解中标注的异常类型不是我们抛出的异常类型,则Spring事务的回滚会失效。

例如: Spring 中默认回滚的异常类型为 RuntimeException,如果此时你抛出的异常是 Exception,那么Spring 事务中无法捕获到 Exception 异常,则事务回滚会失效。

9.开启多线程

开启一个线程去执行数据库操作,多线程内的方法将不被 spring 事务控制。

例如:一个带事务的方法 A 中开启线程去执行同类中的一个 insert 方法,即使这个操作失败了,也不会回滚 A 中的其他数据库操作。

注意:如果把 insert 方法提出到一个新的类中,加入事务注解,就能成功的把 insert 方法加入到 spring 事务管理中。但是使用多线程事务的情况下,如果想进行回滚,比较麻烦,因为我们感知不到线程中方法执行的异常。

8. Spring 单例 多例 线程安全等问题,想请教大家

Spring作为一个IOC/DI容器,帮助我们管理了许许多多的“bean”。但其实,Spring并没有确保这些对象的线程安全,需要由开发者自己编写解决线程安全问题的代码。
Spring对每个bean提供了一个scope属性来表示该bean的作用域。它是bean的生命周期。

我们知道在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(如RequestContextHolder、、LocaleContextHolder等)中非线程安全状态采用ThreadLocal进行处冲李理,让它们也成为线程安全的状态,因为有状态的Bean就可以在多线程中共享了。
一般的Web应用划分为展现层、服务层和持久层三个层次,在不同的层中编写对应的逻辑,下层通过接口向上层开放功能调用。在一般情况下,从接收请求到返回响应所经过的所有程序调用都同属于一个线程。
ThreadLocal是解决线程安全问题一个很好的思路,ThreadLocal是一个为线程提供线程局部变量的工具类。它的思想也十分简单,就是为线程提供一个线程私有的变量副本,这样多个线程都可以随意更改自己线程局部的变量,不会影响到其他线程。不过需要注意的是,ThreadLocal提供的只是一个浅拷贝,如果变量是一个引用类型,那么就要考虑它内部的状态是否会被改变,想要解决这个问题可以通过重写ThreadLocal的initialValue()函数来自己实现深拷贝,建议在使用ThreadLocal时一开始就重写该函数。
ThreadLocal通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突辩谈问题。在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
或者说:一个类或者携判碰程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。

9. 如何实现springMVC的多线程并发

实现springMVC的多线程并发:

1、ThreadLocal为解决多线程程序的并发问题提供了一种新的思路

2、对于多线程资源共享的问题,同步机制采用了橘桐“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

热点内容
内置存储卡可以拆吗 发布:2025-05-18 04:16:35 浏览:336
编译原理课时设置 发布:2025-05-18 04:13:28 浏览:378
linux中进入ip地址服务器 发布:2025-05-18 04:11:21 浏览:612
java用什么软件写 发布:2025-05-18 03:56:19 浏览:32
linux配置vim编译c 发布:2025-05-18 03:55:07 浏览:107
砸百鬼脚本 发布:2025-05-18 03:53:34 浏览:945
安卓手机如何拍视频和苹果一样 发布:2025-05-18 03:40:47 浏览:742
为什么安卓手机连不上苹果7热点 发布:2025-05-18 03:40:13 浏览:803
网卡访问 发布:2025-05-18 03:35:04 浏览:511
接收和发送服务器地址 发布:2025-05-18 03:33:48 浏览:372