最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

spring多個事務(wù)管理器踩坑及解決

 更新時間:2022年11月21日 10:23:58   作者:小小少年_  
這篇文章主要介紹了spring多個事務(wù)管理器踩坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

多個事務(wù)管理器踩坑

在項(xiàng)目中使用了兩個事務(wù)管理器,因?yàn)轫?xiàng)目中設(shè)計(jì)到兩個數(shù)據(jù)庫的操作,所以就聲明了兩個事務(wù)管理器;

但是在使用@Transactional注解的時候,沒有手動指定事務(wù)要使用哪個,就有可能會導(dǎo)致事務(wù)不生效

案例

1、在項(xiàng)目中,我用到了A和B兩個數(shù)據(jù)庫,所以,此時就需要聲明兩個事務(wù)管理器,我們假設(shè)命名為:ATransactionManager和BTransactionManager(這兩個事務(wù)管理器,分別對應(yīng)著A和B兩個數(shù)據(jù)庫就)

2、在使用的時候,如果當(dāng)前方法中,都是對A數(shù)據(jù)庫的表進(jìn)行操作,那就需要在@Transactional注解的value屬性上指定ATransactional

這里的aDataSource和bDataSource都是根據(jù)a和b兩個數(shù)據(jù)庫生成的,只需要在配置類中,加上這幾行代碼,spring在啟動的時候,就會把這兩個事務(wù)管理器放入到spring容器中

@Bean
public PlatformTransactionManager aTransactionManager() {
    return new DataSourceTransactionManager(aDataSource());
}

@Bean
public PlatformTransactionManager bTransactionManager() {
    return new DataSourceTransactionManager(bDataSource());
}

配置就完成了,這里,就和添加一個普通的bean對象是一樣的,都會放到spring容器中

我遇到的問題是

我在一個方法上加了事務(wù)注解,但是沒有指定value,實(shí)際上,這個接口中是要去操作a數(shù)據(jù)庫的三張表,但是發(fā)現(xiàn)接口中事務(wù)回滾的時候,并沒有把其他三張表的數(shù)據(jù)都回滾,debug看代碼,也確實(shí)去執(zhí)行了回滾的操作,最后發(fā)現(xiàn)是沒有指定aTransactionManager的原因

源碼解析

我們都知道,事務(wù)的源碼,在

org.springframework.transaction.interceptor.TransactionInterceptor#invoke
?? ?org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction
?? ?
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
//根據(jù)事務(wù)屬性獲取獲取事務(wù)管理器,這里一般是 DataSourceTransactionManager,我們也可以自己去指定事務(wù)管理器
final PlatformTransactionManager tm = determineTransactionManager(txAttr);?? ?

在這個方法中,有兩行代碼,是需要關(guān)注的,上面一行,是根據(jù)當(dāng)前的方法名,獲取對應(yīng)的事務(wù)注解信息,這里有一個前置的知識點(diǎn),需要說明:在spring初始化的過程中,會對方法或者類上對的事務(wù)注解進(jìn)行解析,解析之后,會存到內(nèi)存中,其中

org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(org.springframework.core.annotation.AnnotationAttributes)

在這個方法中,會解析@Transactional注解,并將解析到的配置信息,存儲到RuleBasedTransactionAttribute這個bean中,存儲到這個bean的qualifier字段上,所以,事務(wù)攔截器在解析的時候,是根據(jù)這個qualifier字段的value,來獲取事務(wù)管理器的,這是一個前提知識,需要知道

determineTransactionManager()

我們著重來看這個方法:

/**
 * 這個方法,是來獲取事務(wù)管理器的,如果我們有自己指定,就可以在使用@Transactional注解的時候,通過value,指定我們要使用的事務(wù)管理器
 * Determine the specific transaction manager to use for the given transaction.
 */
@Nullable
protected PlatformTransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
	// Do not attempt to lookup tx manager if no tx attributes are set
	if (txAttr == null || this.beanFactory == null) {
		return getTransactionManager();
	}

	// 1.由于在解析事務(wù)注解的時候,將value,放到了qualifier屬性上,所以要這樣獲取,我們只需要知道,這里的qualifier就是事務(wù)注解中的value對應(yīng)的值
	String qualifier = txAttr.getQualifier();
	// 2.如果在@Transaction的value指定事務(wù)管理器,會執(zhí)行這里,其實(shí)就是從spring容器中獲取指定的事務(wù)管理器
	if (StringUtils.hasText(qualifier)) {
		return determineQualifiedTransactionManager(this.beanFactory, qualifier);
	}
	// 3.
	else if (StringUtils.hasText(this.transactionManagerBeanName)) {
		return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
	}
	else {
		// 4.先判斷是否有指定事務(wù)管理器,如果沒有,就獲取默認(rèn)的
		PlatformTransactionManager defaultTransactionManager = getTransactionManager();
		if (defaultTransactionManager == null) {
			// 獲取默認(rèn)的事務(wù)管理器
			defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
			if (defaultTransactionManager == null) {
				//由于我們沒有指定,會從spring容器中按照類型獲取,所以我們只需要往spring容器中注入一個事務(wù)管理器即可,springboot應(yīng)用會默認(rèn)注入一個事務(wù)管理器
				defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
				this.transactionManagerCache.putIfAbsent(
						DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
			}
		}
		return defaultTransactionManager;
	}
}

這個方法,我認(rèn)為,就是這篇博客所有的內(nèi)容了,注釋中的第一點(diǎn)和第二點(diǎn)我搞懂了,第二點(diǎn)如果點(diǎn)進(jìn)去,就會發(fā)現(xiàn),實(shí)際上,調(diào)用的就是beanFactory.getBean(name,type)這個方法,就是根據(jù)我們指定的事務(wù)管理器,從spring容器中獲取我們想要使用的事務(wù)管理器

對于第三點(diǎn),我還沒有搞懂,只是看到是在org.springframework.transaction.interceptor.TransactionInterceptor#readObject中賦的值,所以先暫時跳過

對于第四點(diǎn):其實(shí)簡單來說,就是我們沒有指定要使用的事務(wù)管理器,spring會幫助我們?nèi)ギ?dāng)前spring容器中,根據(jù)類型(PlatformTransactionManager.class)獲取一個默認(rèn)的事務(wù)管理器,對于springboot應(yīng)用來說,無需關(guān)心這一點(diǎn),因?yàn)閟pringboot幫助我們自動注入了一個事務(wù)管理器:DataSourceTransactionManager

所以,上面這個方法,就解釋了,為什么,我在沒有指定事務(wù)管理器的情況下,事務(wù)未生效

springboot自動注入的事務(wù)管理器

在spring自動注入的配置中,幫我們自動注入了這個一個類

org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\

@Configuration
@ConditionalOnClass({ JdbcTemplate.class, PlatformTransactionManager.class })
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceTransactionManagerAutoConfiguration {

	@Configuration
	@ConditionalOnSingleCandidate(DataSource.class)
	static class DataSourceTransactionManagerConfiguration {

		private final DataSource dataSource;

		private final TransactionManagerCustomizers transactionManagerCustomizers;

		DataSourceTransactionManagerConfiguration(DataSource dataSource,
				ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
			this.dataSource = dataSource;
			this.transactionManagerCustomizers = transactionManagerCustomizers
					.getIfAvailable();
		}

		@Bean
		@ConditionalOnMissingBean(PlatformTransactionManager.class)
		public DataSourceTransactionManager transactionManager(
				DataSourceProperties properties) {
			// 根據(jù)DataSource,初始化一個DataSourceTransactionManager對象,然后return;所以,這里就會把初始化的事務(wù)管理器放到spring容器中
			DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(
					this.dataSource);
			if (this.transactionManagerCustomizers != null) {
				this.transactionManagerCustomizers.customize(transactionManager);
			}
			return transactionManager;
		}
	}
}

在這個bean中,就注入了一個事務(wù)管理器,但是有一個前提,就是@ConditionalOnSingleCandidate(DataSource.class),這個注解,百度了一下,大致的意思就是說如果當(dāng)前容器中只有一個DataSource,才會執(zhí)行下面注入的動作

所以,對于springboot應(yīng)用,如果我們在項(xiàng)目中,只有一個DataSource,那spring會幫我們自動注入一個,在使用事務(wù)注解的時候,也就不需要去指定value了

未確認(rèn)點(diǎn)

這里就是有一個點(diǎn)不太明白,在有多個數(shù)據(jù)源的情況下,springboot就不幫我們注入事務(wù)管理器了,但是我在debug的時候,發(fā)現(xiàn),還是取的默認(rèn)的事務(wù)管理器,也就是DataSourceTransactionalManager, 這個點(diǎn)沒太搞懂原因,因?yàn)楦杏X和源碼中自己理解的不太一樣

結(jié)論

總之,在項(xiàng)目中有多個數(shù)據(jù)源的時候,在事務(wù)注解上,最好標(biāo)明使用哪個事務(wù)管理器

以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring中RedisTemplate的基本使用淺析

    Spring中RedisTemplate的基本使用淺析

    Spring Boot Data(數(shù)據(jù)) Redis中提供了RedisTemplate和StringRedisTemplate,其中StringRedisTemplate是RedisTemplate的子類,兩個方法基本一致。本文介紹了Spring操作Redis的方法,需要的可以參考一下
    2023-02-02
  • Java深入講解SPI的使用

    Java深入講解SPI的使用

    SPI英文全稱為Service Provider Interface,顧名思義,服務(wù)提供者接口,它是jdk提供給“服務(wù)提供廠商”或者“插件開發(fā)者”使用的接口
    2022-06-06
  • MyBatis動態(tài)SQL特性詳解

    MyBatis動態(tài)SQL特性詳解

    動態(tài)SQL可以省略很多拼接SQL的步驟,使用類似于JSTL方式,下面這篇文章主要給大家介紹了關(guān)于Mybatis動態(tài)SQL特性的相關(guān)資料,文字通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-11-11
  • SpringBoot項(xiàng)目如何添加2FA雙因素身份認(rèn)證

    SpringBoot項(xiàng)目如何添加2FA雙因素身份認(rèn)證

    雙因素身份驗(yàn)證2FA是一種安全系統(tǒng),要求用戶提供兩種不同的身份驗(yàn)證方式才能訪問某個系統(tǒng)或服務(wù),國內(nèi)普遍做短信驗(yàn)證碼這種的用的比較少,不過在國外的網(wǎng)站中使用雙因素身份驗(yàn)證的還是很多的,這篇文章主要介紹了SpringBoot項(xiàng)目如何添加2FA雙因素身份認(rèn)證,需要的朋友參考下
    2024-04-04
  • 在Java中如何比較兩個對象淺析

    在Java中如何比較兩個對象淺析

    在工作中我們經(jīng)常會遇到這樣的需求——比較兩個對象是否相等,如果不相等的話,取出不相等的字段,這篇文章主要給大家介紹了關(guān)于在Java中如何比較兩個對象的相關(guān)資料,需要的朋友可以參考下
    2021-11-11
  • Java基本類型與byte數(shù)組之間相互轉(zhuǎn)換方法

    Java基本類型與byte數(shù)組之間相互轉(zhuǎn)換方法

    下面小編就為大家?guī)硪黄狫ava基本類型與byte數(shù)組之間相互轉(zhuǎn)換方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-08-08
  • 詳解Java中clone的寫法

    詳解Java中clone的寫法

    這篇文章主要介紹了Java中clone的寫法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-07-07
  • SpringBoot?內(nèi)置工具類的使用

    SpringBoot?內(nèi)置工具類的使用

    本文主要介紹了SpringBoot?內(nèi)置工具類的使用,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Mybatis-Plus實(shí)現(xiàn)自動生成代碼的操作步驟

    Mybatis-Plus實(shí)現(xiàn)自動生成代碼的操作步驟

    AutoGenerator 是 MyBatis-Plus 的代碼生成器,通過 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各個模塊的代碼,極大的提升了開發(fā)效率,本文將給大家介紹Mybatis-Plus實(shí)現(xiàn)自動生成代碼的操作步驟
    2023-10-10
  • Java大文件分片上傳超詳細(xì)教程(minio版)

    Java大文件分片上傳超詳細(xì)教程(minio版)

    Minio是一個開源的分布式對象存儲系統(tǒng),它允許用戶在存儲服務(wù)上存儲和檢索數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于Java大文件分片上傳(minio版)的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-08-08

最新評論

崇义县| 堆龙德庆县| 西昌市| 信阳市| 仪陇县| 宜良县| 宜阳县| 库车县| 宜春市| 和林格尔县| 龙海市| 富民县| 桑日县| 平泉县| 分宜县| 鹤山市| 眉山市| 中西区| 天镇县| 聊城市| 黄冈市| 长垣县| 四川省| 潼南县| 临沂市| 高青县| 鞍山市| 柳林县| 琼结县| 扶绥县| 永泰县| 饶阳县| 阿克| 色达县| 自治县| 宁强县| 手机| 贺兰县| 石河子市| 吉林省| 朝阳市|