一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

SpringBoot分布式事務(wù)的解決方案(JTA+Atomic+多數(shù)據(jù)源)

Android編程精選 ? 來源:blog.csdn.net/jaryle/article/d ? 作者:blog.csdn.net/jaryle/ ? 2022-04-11 11:05 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

首先,到底啥是分布式事務(wù)呢,比如我們?cè)趫?zhí)行一個(gè)業(yè)務(wù)邏輯的時(shí)候有兩步分別操作A數(shù)據(jù)源和B數(shù)據(jù)源,當(dāng)我們?cè)贏數(shù)據(jù)源執(zhí)行數(shù)據(jù)更改后,在B數(shù)據(jù)源執(zhí)行時(shí)出現(xiàn)運(yùn)行時(shí)異常,那么我們必須要讓B數(shù)據(jù)源的操作回滾,并回滾對(duì)A數(shù)據(jù)源的操作;這種情況在支付業(yè)務(wù)時(shí)常常出現(xiàn);比如買票業(yè)務(wù)在最后支付失敗,那之前的操作必須全部回滾,如果之前的操作分布在多個(gè)數(shù)據(jù)源中,那么這就是典型的分布式事務(wù)回滾;

了解了什么是分布式事務(wù),那分布式事務(wù)在java的解決方案就是JTA(即Java Transaction API);springboot官方提供了 Atomikos or Bitronix的解決思路;

其實(shí),大多數(shù)情況下很多公司是使用消息隊(duì)列的方式實(shí)現(xiàn)分布式事務(wù)。

本篇文章重點(diǎn)講解springboot環(huán)境下,整合 Atomikos +mysql+mybatis+tomcat/jetty;

一、項(xiàng)目依賴

pom.xml中添加atomikos的springboot相關(guān)依賴:


<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jta-atomikosartifactId>
dependency>

點(diǎn)進(jìn)去會(huì)發(fā)現(xiàn)里面整合好了:transactions-jms、transactions-jtatransactions-jdbc、javax.transaction-api

二、把數(shù)據(jù)源的相關(guān)配置項(xiàng)單獨(dú)提煉到一個(gè)application.yml中:

注意:

  1. 這回我們的spring.datasource.typecom.alibaba.druid.pool.xa.DruidXADataSource;

  2. spring.jta.transaction-manager-id的值在你的電腦中是唯一的,這個(gè)詳細(xì)請(qǐng)閱讀官方文檔;

ca6a91f8-b943-11ec-aa7f-dac502259ad0.png

完整的yml文件如下:

spring:
datasource:
type:com.alibaba.druid.pool.xa.DruidXADataSource
druid:

systemDB:
name:systemDB
url:jdbc//localhost:3306/springboot-mybatis?useUnicode=true&characterEncoding=utf-8
username:root
password:root
#下面為連接池的補(bǔ)充設(shè)置,應(yīng)用到上面所有數(shù)據(jù)源中
#初始化大小,最小,最大
initialSize:5
minIdle:5
maxActive:20
#配置獲取連接等待超時(shí)的時(shí)間
maxWait:60000
#配置間隔多久才進(jìn)行一次檢測(cè),檢測(cè)需要關(guān)閉的空閑連接,單位是毫秒
timeBetweenEvictionRunsMillis:60000
#配置一個(gè)連接在池中最小生存的時(shí)間,單位是毫秒
minEvictableIdleTimeMillis:30
validationQuery:SELECT1
validationQueryTimeout:10000
testWhileIdle:true
testOnBorrow:false
testOnReturn:false
#打開PSCache,并且指定每個(gè)連接上PSCache的大小
poolPreparedStatements:true
maxPoolPreparedStatementPerConnectionSize:20
filters:stat,wall
#通過connectProperties屬性來打開mergeSql功能;慢SQL記錄
connectionProperties:druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
#合并多個(gè)DruidDataSource的監(jiān)控?cái)?shù)據(jù)
useGlobalDataSourceStat:true

businessDB:
name:businessDB

url:jdbc//localhost:3306/springboot-mybatis2?useUnicode=true&characterEncoding=utf-8
username:root
password:root
#下面為連接池的補(bǔ)充設(shè)置,應(yīng)用到上面所有數(shù)據(jù)源中
#初始化大小,最小,最大
initialSize:5
minIdle:5
maxActive:20
#配置獲取連接等待超時(shí)的時(shí)間
maxWait:60000
#配置間隔多久才進(jìn)行一次檢測(cè),檢測(cè)需要關(guān)閉的空閑連接,單位是毫秒
timeBetweenEvictionRunsMillis:60000
#配置一個(gè)連接在池中最小生存的時(shí)間,單位是毫秒
minEvictableIdleTimeMillis:30
validationQuery:SELECT1
validationQueryTimeout:10000
testWhileIdle:true
testOnBorrow:false
testOnReturn:false
#打開PSCache,并且指定每個(gè)連接上PSCache的大小
poolPreparedStatements:true
maxPoolPreparedStatementPerConnectionSize:20
filters:stat,wall
#通過connectProperties屬性來打開mergeSql功能;慢SQL記錄
connectionProperties:druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
#合并多個(gè)DruidDataSource的監(jiān)控?cái)?shù)據(jù)
useGlobalDataSourceStat:true

#jta相關(guān)參數(shù)配置
jta:
log-dir:classpath:tx-logs
transaction-manager-id:txManager
三、在DruidConfig.java中實(shí)現(xiàn)多個(gè)數(shù)據(jù)源的注冊(cè);分布式事務(wù)管理器的注冊(cè);druid的注冊(cè);
packagecom.zjt.config;

importcom.alibaba.druid.filter.stat.StatFilter;
importcom.alibaba.druid.support.http.StatViewServlet;
importcom.alibaba.druid.support.http.WebStatFilter;
importcom.alibaba.druid.wall.WallConfig;
importcom.alibaba.druid.wall.WallFilter;
importcom.atomikos.icatch.jta.UserTransactionImp;
importcom.atomikos.icatch.jta.UserTransactionManager;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
importorg.springframework.boot.web.servlet.FilterRegistrationBean;
importorg.springframework.boot.web.servlet.ServletRegistrationBean;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.context.annotation.Primary;
importorg.springframework.core.env.Environment;
importorg.springframework.transaction.jta.JtaTransactionManager;

importjavax.sql.DataSource;
importjavax.transaction.UserTransaction;
importjava.util.Properties;

/**
*Druid配置
*
*
*/
@Configuration
publicclassDruidConfig{
@Bean(name="systemDataSource")
@Primary
@Autowired
publicDataSourcesystemDataSource(Environmentenv){
AtomikosDataSourceBeands=newAtomikosDataSourceBean();
Propertiesprop=build(env,"spring.datasource.druid.systemDB.");
ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");
ds.setUniqueResourceName("systemDB");
ds.setPoolSize(5);
ds.setXaProperties(prop);
returnds;

}

@Autowired
@Bean(name="businessDataSource")
publicAtomikosDataSourceBeanbusinessDataSource(Environmentenv){

AtomikosDataSourceBeands=newAtomikosDataSourceBean();
Propertiesprop=build(env,"spring.datasource.druid.businessDB.");
ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");
ds.setUniqueResourceName("businessDB");
ds.setPoolSize(5);
ds.setXaProperties(prop);

returnds;
}


/**
*注入事物管理器
*@return
*/
@Bean(name="xatx")
publicJtaTransactionManagerregTransactionManager(){
UserTransactionManageruserTransactionManager=newUserTransactionManager();
UserTransactionuserTransaction=newUserTransactionImp();
returnnewJtaTransactionManager(userTransaction,userTransactionManager);
}


privatePropertiesbuild(Environmentenv,Stringprefix){

Propertiesprop=newProperties();
prop.put("url",env.getProperty(prefix+"url"));
prop.put("username",env.getProperty(prefix+"username"));
prop.put("password",env.getProperty(prefix+"password"));
prop.put("driverClassName",env.getProperty(prefix+"driverClassName",""));
prop.put("initialSize",env.getProperty(prefix+"initialSize",Integer.class));
prop.put("maxActive",env.getProperty(prefix+"maxActive",Integer.class));
prop.put("minIdle",env.getProperty(prefix+"minIdle",Integer.class));
prop.put("maxWait",env.getProperty(prefix+"maxWait",Integer.class));
prop.put("poolPreparedStatements",env.getProperty(prefix+"poolPreparedStatements",Boolean.class));

prop.put("maxPoolPreparedStatementPerConnectionSize",
env.getProperty(prefix+"maxPoolPreparedStatementPerConnectionSize",Integer.class));

prop.put("maxPoolPreparedStatementPerConnectionSize",
env.getProperty(prefix+"maxPoolPreparedStatementPerConnectionSize",Integer.class));
prop.put("validationQuery",env.getProperty(prefix+"validationQuery"));
prop.put("validationQueryTimeout",env.getProperty(prefix+"validationQueryTimeout",Integer.class));
prop.put("testOnBorrow",env.getProperty(prefix+"testOnBorrow",Boolean.class));
prop.put("testOnReturn",env.getProperty(prefix+"testOnReturn",Boolean.class));
prop.put("testWhileIdle",env.getProperty(prefix+"testWhileIdle",Boolean.class));
prop.put("timeBetweenEvictionRunsMillis",
env.getProperty(prefix+"timeBetweenEvictionRunsMillis",Integer.class));
prop.put("minEvictableIdleTimeMillis",env.getProperty(prefix+"minEvictableIdleTimeMillis",Integer.class));
prop.put("filters",env.getProperty(prefix+"filters"));

returnprop;
}

@Bean
publicServletRegistrationBeandruidServlet(){
ServletRegistrationBeanservletRegistrationBean=newServletRegistrationBean(newStatViewServlet(),"/druid/*");

//控制臺(tái)管理用戶,加入下面2行進(jìn)入druid后臺(tái)就需要登錄
//servletRegistrationBean.addInitParameter("loginUsername","admin");
//servletRegistrationBean.addInitParameter("loginPassword","admin");
returnservletRegistrationBean;
}

@Bean
publicFilterRegistrationBeanfilterRegistrationBean(){
FilterRegistrationBeanfilterRegistrationBean=newFilterRegistrationBean();
filterRegistrationBean.setFilter(newWebStatFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
filterRegistrationBean.addInitParameter("profileEnable","true");
returnfilterRegistrationBean;
}

@Bean
publicStatFilterstatFilter(){
StatFilterstatFilter=newStatFilter();
statFilter.setLogSlowSql(true);//slowSqlMillis用來配置SQL慢的標(biāo)準(zhǔn),執(zhí)行時(shí)間超過slowSqlMillis的就是慢。
statFilter.setMergeSql(true);//SQL合并配置
statFilter.setSlowSqlMillis(1000);//slowSqlMillis的缺省值為3000,也就是3秒。
returnstatFilter;
}

@Bean
publicWallFilterwallFilter(){
WallFilterwallFilter=newWallFilter();
//允許執(zhí)行多條SQL
WallConfigconfig=newWallConfig();
config.setMultiStatementAllow(true);
wallFilter.setConfig(config);
returnwallFilter;
}

}
四、分別配置每個(gè)數(shù)據(jù)源對(duì)應(yīng)的sqlSessionFactory,以及MapperScan掃描的包:

MybatisDatasourceConfig.java

packagecom.zjt.config;

importcom.zjt.util.MyMapper;
importorg.apache.ibatis.session.SqlSessionFactory;
importorg.mybatis.spring.SqlSessionFactoryBean;
importorg.mybatis.spring.SqlSessionTemplate;
importorg.mybatis.spring.annotation.MapperScan;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.beans.factory.annotation.Qualifier;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.core.io.support.PathMatchingResourcePatternResolver;
importorg.springframework.core.io.support.ResourcePatternResolver;

importjavax.sql.DataSource;

/**
*
*@description
*/
@Configuration
//精確到mapper目錄,以便跟其他數(shù)據(jù)源隔離
@MapperScan(basePackages="com.zjt.mapper",markerInterface=MyMapper.class,sqlSessionFactoryRef="sqlSessionFactory")
publicclassMybatisDatasourceConfig{

@Autowired
@Qualifier("systemDataSource")
privateDataSourceds;

@Bean
publicSqlSessionFactorysqlSessionFactory()throwsException{
SqlSessionFactoryBeanfactoryBean=newSqlSessionFactoryBean();
factoryBean.setDataSource(ds);
//指定mapperxml目錄
ResourcePatternResolverresolver=newPathMatchingResourcePatternResolver();
factoryBean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
returnfactoryBean.getObject();

}

@Bean
publicSqlSessionTemplatesqlSessionTemplate()throwsException{
SqlSessionTemplatetemplate=newSqlSessionTemplate(sqlSessionFactory());//使用上面配置的Factory
returntemplate;
}

//關(guān)于事務(wù)管理器,不管是JPA還是JDBC等都實(shí)現(xiàn)自接口PlatformTransactionManager
//如果你添加的是 spring-boot-starter-jdbc 依賴,框架會(huì)默認(rèn)注入 DataSourceTransactionManager 實(shí)例。
//在Spring容器中,我們手工注解@Bean 將被優(yōu)先加載,框架不會(huì)重新實(shí)例化其他的 PlatformTransactionManager 實(shí)現(xiàn)類。
/*@Bean(name="transactionManager")
@Primary
publicDataSourceTransactionManagermasterTransactionManager(){
//MyBatis自動(dòng)參與到spring事務(wù)管理中,無需額外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的數(shù)據(jù)源
//與DataSourceTransactionManager引用的數(shù)據(jù)源一致即可,否則事務(wù)管理會(huì)不起作用。
returnnewDataSourceTransactionManager(ds);
}*/

}

MybatisDatasource2Config.java

packagecom.zjt.config;

importcom.zjt.util.MyMapper;
importorg.apache.ibatis.session.SqlSessionFactory;
importorg.mybatis.spring.SqlSessionFactoryBean;
importorg.mybatis.spring.SqlSessionTemplate;
importorg.mybatis.spring.annotation.MapperScan;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.beans.factory.annotation.Qualifier;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.core.io.support.PathMatchingResourcePatternResolver;
importorg.springframework.core.io.support.ResourcePatternResolver;

importjavax.sql.DataSource;

/**
*
*@description
*/
@Configuration
//精確到mapper目錄,以便跟其他數(shù)據(jù)源隔離
@MapperScan(basePackages="com.zjt.mapper2",markerInterface=MyMapper.class,sqlSessionFactoryRef="sqlSessionFactory2")
publicclassMybatisDatasource2Config{

@Autowired
@Qualifier("businessDataSource")
privateDataSourceds;

@Bean
publicSqlSessionFactorysqlSessionFactory2()throwsException{
SqlSessionFactoryBeanfactoryBean=newSqlSessionFactoryBean();
factoryBean.setDataSource(ds);
//指定mapperxml目錄
ResourcePatternResolverresolver=newPathMatchingResourcePatternResolver();
factoryBean.setMapperLocations(resolver.getResources("classpath:mapper2/*.xml"));
returnfactoryBean.getObject();

}

@Bean
publicSqlSessionTemplatesqlSessionTemplate2()throwsException{
SqlSessionTemplatetemplate=newSqlSessionTemplate(sqlSessionFactory2());//使用上面配置的Factory
returntemplate;
}

//關(guān)于事務(wù)管理器,不管是JPA還是JDBC等都實(shí)現(xiàn)自接口PlatformTransactionManager
//如果你添加的是 spring-boot-starter-jdbc 依賴,框架會(huì)默認(rèn)注入 DataSourceTransactionManager 實(shí)例。
//在Spring容器中,我們手工注解@Bean 將被優(yōu)先加載,框架不會(huì)重新實(shí)例化其他的 PlatformTransactionManager 實(shí)現(xiàn)類。
/*@Bean(name="transactionManager2")
@Primary
publicDataSourceTransactionManagermasterTransactionManager(){
//MyBatis自動(dòng)參與到spring事務(wù)管理中,無需額外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的數(shù)據(jù)源
//與DataSourceTransactionManager引用的數(shù)據(jù)源一致即可,否則事務(wù)管理會(huì)不起作用。
returnnewDataSourceTransactionManager(ds);
}*/

}

由于我們本例中只使用一個(gè)事務(wù)管理器:xatx,故就不在使用TxAdviceInterceptor.javaTxAdvice2Interceptor.java中配置的事務(wù)管理器了;有需求的童鞋可以自己配置其他的事務(wù)管理器;(見DruidConfig.java中查看)

五、新建分布式業(yè)務(wù)測(cè)試接口JtaTestService.java和實(shí)現(xiàn)類JtaTestServiceImpl.java

其實(shí)就是一個(gè)很簡(jiǎn)單的test01()方法,在該方法中我們分別先后調(diào)用classService.saveOrUpdateTClass(tClass);teacherService.saveOrUpdateTeacher(teacher);

實(shí)現(xiàn)先后操作兩個(gè)數(shù)據(jù)源:然后我們可以自己debug跟蹤事務(wù)的提交時(shí)機(jī),此外,也可以在在兩個(gè)方法全執(zhí)行結(jié)束之后,手動(dòng)制造一個(gè)運(yùn)行時(shí)異常,來檢查分布式事務(wù)是否全部回滾;

注意:

在實(shí)現(xiàn)類的方法中我使用的是:

@Transactional(transactionManager="xatx",propagation=Propagation.REQUIRED,rollbackFor={java.lang.RuntimeException.class})

從而指定了使用哪個(gè)事務(wù)管理器,事務(wù)隔離級(jí)別(一般都用我這個(gè)默認(rèn)的),回滾的條件(一般可以使用Exception),這三個(gè)可以自己根據(jù)業(yè)務(wù)實(shí)際修改;

packagecom.zjt.service3;

importjava.util.Map;

publicinterfaceJtaTestService{

publicMaptest01();

}
packagecom.zjt.service3.impl;


importcom.zjt.entity.TClass;
importcom.zjt.entity.Teacher;
importcom.zjt.service.TClassService;
importcom.zjt.service2.TeacherService;
importcom.zjt.service3.JtaTestService;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.beans.factory.annotation.Qualifier;
importorg.springframework.stereotype.Service;
importorg.springframework.transaction.annotation.Propagation;
importorg.springframework.transaction.annotation.Transactional;

importjava.util.LinkedHashMap;
importjava.util.Map;

@Service("jtaTestServiceImpl")
publicclassJtaTestServiceImplimplementsJtaTestService{

@Autowired
@Qualifier("teacherServiceImpl")
privateTeacherServiceteacherService;
@Autowired
@Qualifier("tclassServiceImpl")
privateTClassServicetclassService;

@Override
@Transactional(transactionManager="xatx",propagation=Propagation.REQUIRED,rollbackFor={java.lang.RuntimeException.class})
publicMap<String,Object>test01(){
LinkedHashMapresultMap=newLinkedHashMap();
TClasstClass=newTClass();
tClass.setName("8888");
tclassService.saveOrUpdateTClass(tClass);

Teacherteacher=newTeacher();
teacher.setName("8888");
teacherService.saveOrUpdateTeacher(teacher);

System.out.println(1/0);

resultMap.put("state","success");
resultMap.put("message","分布式事務(wù)同步成功");
returnresultMap;
}
}
六、建立JtaTestContoller.java,接受一個(gè)來自前端的http請(qǐng)求,觸發(fā)JtaTestService 的test01方法:
packagecom.zjt.web;


importcom.zjt.service3.JtaTestService;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.beans.factory.annotation.Qualifier;
importorg.springframework.stereotype.Controller;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.ResponseBody;

importjava.util.LinkedHashMap;
importjava.util.Map;

@Controller
@RequestMapping("/jtaTest")
publicclassJtaTestContoller{

@Autowired
@Qualifier("jtaTestServiceImpl")
privateJtaTestServicetaTestService;



@ResponseBody
@RequestMapping("/test01")
publicMaptest01(){
LinkedHashMapresultMap=newLinkedHashMap();
try{
returntaTestService.test01();
}catch(Exceptione){
resultMap.put("state","fail");
resultMap.put("message","分布式事務(wù)同步失敗");
returnresultMap;
}
}
}
七、在test.ftl中增加一個(gè)按鈕來測(cè)試;
//分布式事務(wù)測(cè)試
$("#JTATest").click(function(){
    $.ajax({
        type: "POST",
        url: "${basePath!}/jtaTest/test01",
        data: {}    ,
        async: false,
        error: function (request) {
            layer.alert("與服務(wù)器連接失敗/(ㄒoㄒ)/~~");
            return false;
        },
        success: function (data) {
            if (data.state == 'fail') {
                layer.alert(data.message);
                return false;
            }else if(data.state == 'success'){
                layer.alert(data.message);
            }
        }
    });
});
 

八、啟動(dòng)服務(wù),驗(yàn)證結(jié)果:
ca76e2aa-b943-11ec-aa7f-dac502259ad0.png

點(diǎn)擊這個(gè)按鈕,跳轉(zhuǎn)到controller:

ca88376c-b943-11ec-aa7f-dac502259ad0.png

當(dāng)正常執(zhí)行了sql語句之后,我們可以發(fā)現(xiàn)數(shù)據(jù)庫并沒有變化,因?yàn)檎麄€(gè)方法的事務(wù)還沒有走完,當(dāng)我們走到1/0這步時(shí):

ca9d69c0-b943-11ec-aa7f-dac502259ad0.png

拋出運(yùn)行時(shí)異常,并被spring事務(wù)攔截器攔截,并捕獲異常:

caae8480-b943-11ec-aa7f-dac502259ad0.png

this.completeTransactionAfterThrowing(txInfo, var16);方法中會(huì)將事務(wù)全部回滾:

2204.243logback[http-nio-8080-exec-5]INFOc.a.i.imp.CompositeTransactionImp-rollback()doneoftransaction192.168.1.103.tm0000400006

此時(shí),當(dāng)我們?cè)俅未蜷_數(shù)據(jù)庫驗(yàn)證,依舊沒有變化,證明分布式事務(wù)配置成功;

大家可以基于我的代碼自己練習(xí)一下,自己嘗試著使用多事務(wù)管理器的情況下的靈活配置;

九、后記:

本文源代碼:

https://github.com/zhaojiatao/springboot-zjt-chapter10-springboot-atomikos-mysql-mybatis-druid.git

代碼在tomcat和jetty環(huán)境下均可完成事務(wù)回滾;

在事務(wù)回滾時(shí)可能報(bào)一個(gè)Transactional not active的警告,我google后,老外也說不出這個(gè)具體作用,大部分人認(rèn)為這只是一個(gè)警告,可以忽略;

-End-

審核編輯 :李倩
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • API
    API
    +關(guān)注

    關(guān)注

    2

    文章

    1620

    瀏覽量

    64048
  • 分布式
    +關(guān)注

    關(guān)注

    1

    文章

    997

    瀏覽量

    75408
  • 數(shù)據(jù)源
    +關(guān)注

    關(guān)注

    1

    文章

    65

    瀏覽量

    9920
  • SpringBoot
    +關(guān)注

    關(guān)注

    0

    文章

    175

    瀏覽量

    401

原文標(biāo)題:SpringBoot 分布式事務(wù)的解決方案(JTA+Atomic+多數(shù)據(jù)源)

文章出處:【微信號(hào):AndroidPush,微信公眾號(hào):Android編程精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    安科瑞分布式光伏監(jiān)控系統(tǒng):高效、安全、智能的綠色能源解決方案

    ?并網(wǎng)標(biāo)準(zhǔn)如何滿足?運(yùn)維成本如何降低?安科瑞電氣股份有限公司憑借多年行業(yè)經(jīng)驗(yàn),創(chuàng)新推出Acrel-1000DP分布式光伏監(jiān)控系統(tǒng),為光伏電站提供全生命周期解決方案。 一、分布式光伏發(fā)電系統(tǒng)標(biāo)準(zhǔn)規(guī)范 1.并網(wǎng)標(biāo)準(zhǔn)
    的頭像 發(fā)表于 05-08 16:40 ?263次閱讀

    鐵塔基站分布式儲(chǔ)能揭秘!

    的正常運(yùn)轉(zhuǎn)。為了解決這些問題,安科瑞推出了基站鐵塔分布式儲(chǔ)能解決方案,為基站的穩(wěn)定供電提供了可靠的保障。 一、什么是基站鐵塔分布式儲(chǔ)能? 基站鐵塔分布式儲(chǔ)能系統(tǒng)是一種將儲(chǔ)能電池
    的頭像 發(fā)表于 02-12 16:42 ?758次閱讀
    鐵塔基站<b class='flag-5'>分布式</b>儲(chǔ)能揭秘!

    分布式云化數(shù)據(jù)庫有哪些類型

    分布式云化數(shù)據(jù)庫有哪些類型?分布式云化數(shù)據(jù)庫主要類型包括:關(guān)系型分布式數(shù)據(jù)庫、非關(guān)系型分布式數(shù)據(jù)
    的頭像 發(fā)表于 01-15 09:43 ?482次閱讀

    分布式、域控及SOA架構(gòu)車身功能測(cè)試方案

    北匯信息推出分布式、域控以及SOA架構(gòu)的車身功能測(cè)試解決方案,支持在實(shí)驗(yàn)室環(huán)境下完成車身單部件、系統(tǒng)級(jí)功能自動(dòng)化測(cè)試,可以極大地提升車身功能的可靠性和穩(wěn)定性。
    的頭像 發(fā)表于 12-27 09:05 ?2704次閱讀
    <b class='flag-5'>分布式</b>、域控及SOA架構(gòu)車身功能測(cè)試<b class='flag-5'>方案</b>

    HarmonyOS Next 應(yīng)用元服務(wù)開發(fā)-分布式數(shù)據(jù)對(duì)象遷移數(shù)據(jù)文件資產(chǎn)遷移

    向用戶申請(qǐng)授權(quán)。 二、基礎(chǔ)數(shù)據(jù)遷移 使用分布式數(shù)據(jù)對(duì)象,與上述開發(fā)步驟類似,需要在端onContinue()接口中進(jìn)行數(shù)據(jù)保存,并在對(duì)端的
    發(fā)表于 12-24 10:11

    HarmonyOS Next 應(yīng)用元服務(wù)開發(fā)-分布式數(shù)據(jù)對(duì)象遷移數(shù)據(jù)權(quán)限與基礎(chǔ)數(shù)據(jù)

    向用戶申請(qǐng)授權(quán)。 二、基礎(chǔ)數(shù)據(jù)遷移 使用分布式數(shù)據(jù)對(duì)象,與上述開發(fā)步驟類似,需要在端onContinue()接口中進(jìn)行數(shù)據(jù)保存,并在對(duì)端的
    發(fā)表于 12-24 09:40

    Mybatis 攔截器實(shí)現(xiàn)單數(shù)據(jù)源內(nèi)多數(shù)據(jù)庫切換

    作者:京東保險(xiǎn) 王奕龍 物流的分揀業(yè)務(wù)在某些分揀場(chǎng)地只有一個(gè)數(shù)據(jù)源,因?yàn)?b class='flag-5'>數(shù)據(jù)量比較大,將所有數(shù)據(jù)存在一張表內(nèi)查詢速度慢,也為了做不同設(shè)備數(shù)據(jù)的分庫管理,便在這個(gè)
    的頭像 發(fā)表于 12-12 10:23 ?1333次閱讀

    分布式光纖測(cè)溫解決方案

    分布式光纖測(cè)溫解決方案
    的頭像 發(fā)表于 11-12 01:02 ?565次閱讀
    <b class='flag-5'>分布式</b>光纖測(cè)溫<b class='flag-5'>解決方案</b>

    一文講清什么是分布式云化數(shù)據(jù)庫!

    分布式云化數(shù)據(jù)庫是一種先進(jìn)的數(shù)據(jù)管理系統(tǒng),它將傳統(tǒng)的數(shù)據(jù)庫技術(shù)與分布式計(jì)算、云計(jì)算和大數(shù)據(jù)處理技
    的頭像 發(fā)表于 10-14 10:06 ?480次閱讀

    分布式功能安全的創(chuàng)新與突破

    ,獲取完整分布式安全機(jī)制解決方案根據(jù)ISO26262汽車安全完整性等級(jí)(ASIL)體系,汽車上運(yùn)行的所有功能都要根據(jù)潛在風(fēng)險(xiǎn)進(jìn)行等級(jí)認(rèn)證。汽車制造商及其供應(yīng)商必須
    的頭像 發(fā)表于 09-20 08:09 ?518次閱讀
    <b class='flag-5'>分布式</b>功能安全的創(chuàng)新與突破

    基于分布式存儲(chǔ)系統(tǒng)醫(yī)療影像數(shù)據(jù)存儲(chǔ)解決方案

    基于分布式存儲(chǔ)系統(tǒng)醫(yī)療影像數(shù)據(jù)存儲(chǔ)解決方案
    的頭像 發(fā)表于 09-14 09:53 ?691次閱讀
    基于<b class='flag-5'>分布式</b>存儲(chǔ)系統(tǒng)醫(yī)療影像<b class='flag-5'>數(shù)據(jù)</b>存儲(chǔ)<b class='flag-5'>解決方案</b>

    常見的遙感數(shù)據(jù)源有哪些類型

    遙感技術(shù)是一種通過衛(wèi)星、飛機(jī)或其他載體上的傳感器系統(tǒng),從遠(yuǎn)距離收集地球表面信息的技術(shù)。遙感數(shù)據(jù)源的類型非常多樣,它們可以根據(jù)不同的原理、平臺(tái)、傳感器類型、分辨率、光譜范圍等特征進(jìn)行分類。以下是一些
    的頭像 發(fā)表于 09-04 14:33 ?2015次閱讀

    醫(yī)療PACS影像數(shù)據(jù)的極速分布式塊存儲(chǔ)解決方案

    醫(yī)療PACS影像數(shù)據(jù)的極速分布式塊存儲(chǔ)解決方案
    的頭像 發(fā)表于 08-23 10:13 ?745次閱讀
    醫(yī)療PACS影像<b class='flag-5'>數(shù)據(jù)</b>的極速<b class='flag-5'>分布式</b>塊存儲(chǔ)<b class='flag-5'>解決方案</b>

    昊衡科技推出分布式光纖傳感教學(xué)解決方案——OFDR技術(shù)首次走進(jìn)課堂,實(shí)現(xiàn)領(lǐng)域創(chuàng)新

    OFDR作為國(guó)內(nèi)首家實(shí)現(xiàn)OFDR技術(shù)商用化以及OFDR技術(shù)綜合解決方案提供商,武漢昊衡科技推出了OFDR分布式光纖傳感教學(xué)解決方案,讓OFDR走進(jìn)教學(xué)領(lǐng)域,打造技術(shù)走進(jìn)課堂的全新應(yīng)用場(chǎng)景。OFDR
    的頭像 發(fā)表于 08-02 08:18 ?630次閱讀
    昊衡科技推出<b class='flag-5'>分布式</b>光纖傳感教學(xué)<b class='flag-5'>解決方案</b>——OFDR技術(shù)首次走進(jìn)課堂,實(shí)現(xiàn)領(lǐng)域創(chuàng)新

    探秘IO分布式模塊設(shè)計(jì):讓大數(shù)據(jù)處理更高效

    隨著互聯(lián)網(wǎng)的飛速發(fā)展,大數(shù)據(jù)、云計(jì)算、人工智能等技術(shù)逐漸成為時(shí)代的主流。在這個(gè)數(shù)據(jù)爆炸的時(shí)代,如何高效地處理海量數(shù)據(jù)成為企業(yè)面臨的重大挑戰(zhàn)。IO分布式模塊設(shè)計(jì)作為一種有效的
    的頭像 發(fā)表于 07-26 13:54 ?1075次閱讀
    探秘IO<b class='flag-5'>分布式</b>模塊設(shè)計(jì):讓大<b class='flag-5'>數(shù)據(jù)</b>處理更高效