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

springboot動態(tài)數(shù)據(jù)源+分布式事務的實現(xiàn)

 更新時間:2025年09月12日 10:18:03   作者:wenzheng_du  
本文主要介紹了springboot動態(tài)數(shù)據(jù)源+分布式事務的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

1.引入jta-atomikos

這個springboot 是自帶的。我的springboot版本為2.5.9,數(shù)據(jù)庫為mysql。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jta-atomikos</artifactId>
        </dependency>

2.配置數(shù)據(jù)源(application.yml)

spring:
    # 數(shù)據(jù)源配置
    jta:
        enabled: true
    datasource:
        master:
            # 主庫數(shù)據(jù)源
            url: 
            username: 
            password: 
            driver-class-name: com.mysql.cj.jdbc.Driver
        slave:
            # 從庫數(shù)據(jù)源
            url: 
            username: 
            password: 
            driver-class-name: com.mysql.cj.jdbc.Driver

新建文件 DataSourceConfig ,配置數(shù)據(jù)源及線程池。你有幾個數(shù)據(jù)源就建立幾個XXXDataSource方法,最后放到dynamicDataSource方法中的Map中去。事務管理一定要用JtaTransactionManager。SqlSessionFactory 是可以不用寫的,如果要寫的話,如果你用了mybatis-plus,一定要用MybatisSqlSessionFactoryBean,不然在啟動或者調用Mybatis-plus的方法時,會報找不到bean的錯。

import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.jta.JtaTransactionManager;

import javax.sql.DataSource;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

@Aspect
@Configuration
@EnableTransactionManagement
public class DataSourceConfig {

    @Autowired
    private Environment env;

    @Bean(name = "masterDataSource")
    public DataSource masterDataSource() {
        AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
        ds.setUniqueResourceName("master");
        ds.setXaDataSourceClassName("com.mysql.cj.jdbc.MysqlXADataSource");
        ds.setXaProperties(getXaProperties("master"));
        ds.setMaxPoolSize(10);
        ds.setMinPoolSize(5);
        ds.setBorrowConnectionTimeout(60);
        return ds;
    }

    @Bean(name = "slaveDataSource")
    public DataSource slaveDataSource() {
        AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
        ds.setUniqueResourceName("slave");
        ds.setXaDataSourceClassName("com.mysql.cj.jdbc.MysqlXADataSource");
        ds.setXaProperties(getXaProperties("slave"));
        ds.setMaxPoolSize(10);
        ds.setMinPoolSize(5);
        ds.setBorrowConnectionTimeout(60);
        return ds;
    }

    @Bean
    @Primary
    public DataSource dynamicDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
                                        @Qualifier("slaveDataSource") DataSource slaveDataSource) {
        DynamicDataSource dataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("master", masterDataSource);
        targetDataSources.put("slave", slaveDataSource);
        dataSource.setTargetDataSources(targetDataSources);
        dataSource.setDefaultTargetDataSource(masterDataSource);
        return dataSource;
    }

    @Bean
    public UserTransaction userTransaction() throws SystemException {
        UserTransactionImp userTransactionImp = new UserTransactionImp();
        userTransactionImp.setTransactionTimeout(10000);
        return userTransactionImp;
    }

    @Bean(initMethod = "init", destroyMethod = "close")
    public UserTransactionManager userTransactionManager() {
        UserTransactionManager userTransactionManager = new UserTransactionManager();
        userTransactionManager.setForceShutdown(false);
        return userTransactionManager;
    }

    @Bean
    public PlatformTransactionManager transactionManager(UserTransaction userTransaction,
                                                         UserTransactionManager userTransactionManager) {
        JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();
        jtaTransactionManager.setUserTransaction(userTransaction);
        jtaTransactionManager.setTransactionManager(userTransactionManager);
        return jtaTransactionManager;
    }

    private Properties getXaProperties(String dataSourceType) {
        Properties xaProps = new Properties();
        String username = getPropertyValue("spring.datasource." + dataSourceType + ".username");
        String password = getPropertyValue("spring.datasource." + dataSourceType + ".password");
        String url = getPropertyValue("spring.datasource." + dataSourceType + ".url");
        xaProps.put("user", username);
        xaProps.put("password", password);
        xaProps.put("url", url);
        return xaProps;
    }

    private String getPropertyValue(String str) {
        return env.getProperty(str);
    }

}

新建文件DynamicDataSource,這個類繼承AbstractRoutingDataSource。

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        String dataSourceKey = DataSourceContextHolder.getDataSource();
        if (dataSourceKey == null) {
            return "master"; // 默認數(shù)據(jù)源
        }
        return dataSourceKey;
    }
}

建立一個上下文DataSourceContextHolder文件,用于讀取當前數(shù)據(jù)源。

public class DataSourceContextHolder {

    public static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static void setDataSource(String dataSourceName) {
        threadLocal.set(dataSourceName);
    }

    public static String getDataSource() {
        return threadLocal.get();
    }

    public static void clearDataSource() {
        threadLocal.remove();
    }
}

3.配置注解

這個沒啥好說的,文件名自己定義都可以。注意后面的默認數(shù)據(jù)源參數(shù),配置了的話一定要是你的。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MDS {

    String value() default "master";

}

4.切面

在類上使用上面的自定義注解。然后用切面去切換數(shù)據(jù)源。這里我用了3個判斷,首先會先判斷方法上有沒有自定義注解,其次類上,都沒有就用默認的數(shù)據(jù)源。

import cn.hutool.core.annotation.AnnotationUtil;
import com.rs.common.annotation.MDS;
import com.rs.framework.config.dynamic.DataSourceContextHolder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Order(0)
@Component
public class DataSourceAspect {

    @Before("@within(mds) || @annotation(mds)")
    public void before(JoinPoint joinPoint, MDS mds) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Class<?> targetClass = method.getDeclaringClass();
        Object value = AnnotationUtil.getAnnotationValue(targetClass, MDS.class);
        if(mds != null && mds.value() != null){
            DataSourceContextHolder.setDataSource(mds.value());
        } else if (value != null) {
            DataSourceContextHolder.setDataSource((String) value);
        } else {
            DataSourceContextHolder.setDataSource("master");
        }
    }

    @AfterReturning(pointcut = "@within(mds) ||@annotation(mds)", returning = "returnVal")
    public void afterReturning(JoinPoint joinPoint, MDS mds, Object returnVal) {
        DataSourceContextHolder.clearDataSource();
    }

    @AfterThrowing(pointcut = "@within(mds) ||@annotation(mds)", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, MDS mds, Throwable ex) {
        DataSourceContextHolder.clearDataSource();
    }

}

5.如何使用

一個方法中執(zhí)行不同數(shù)據(jù)源操作。getUserPageList方法使用的是默認數(shù)據(jù)源master,即最后的返回是返回master的查詢結果。updateBusinessStatus方法使用的是從庫數(shù)據(jù)源,在執(zhí)行完sql后我寫了一個異常。

這里需要注意的是,一定要寫@Transactional(rollbackFor = Exception.class),且是寫在方法上?。。e為了省事寫在類上,寫在類上發(fā)生異常不會回滾(親測)。

    @Override
    @Transactional(rollbackFor = Exception.class)
    public IPage<SysUserDto> getUserPageList(SysUser user, Page<SysUser> page) {
        user = new SysUser();
        user.setUserId(29L);
        user.setDelFlag("0");
        sysUserMapper.updateById(user);
        flwProcessService.updateBusinessStatus("1851531692768452608",3);
        return sysUserMapper.getUserPageList(user,page.page());
    }

    @Override
    @MDS("slave")
    @Transactional(rollbackFor = Exception.class)
    public void updateBusinessStatus(String procInstId, Integer businessStatus) {
        flwProcessMapper.update(null,new UpdateWrapper<FlwProcess>().lambda()
                .eq(FlwProcess::getProcInstId,procInstId)
                .set(FlwProcess::getBusinessStatus,businessStatus)
        );
        int i = 1/0;
    }

注意事項

一個方法不同數(shù)據(jù)源的操作@Transactional(rollbackFor = Exception.class)寫在類上?。?!

一個方法不同數(shù)據(jù)源的操作@Transactional(rollbackFor = Exception.class)寫在類上!?。?/p>

一個方法不同數(shù)據(jù)源的操作@Transactional(rollbackFor = Exception.class)寫在類上?。?!

到此這篇關于springboot動態(tài)數(shù)據(jù)源+分布式事務的實現(xiàn)的文章就介紹到這了,更多相關springboot動態(tài)數(shù)據(jù)源+分布式事務內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Hibernate一級緩存和二級緩存詳解

    Hibernate一級緩存和二級緩存詳解

    今天小編就為大家分享一篇關于Hibernate一級緩存和二級緩存詳解,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • java swing實現(xiàn)簡單的五子棋游戲

    java swing實現(xiàn)簡單的五子棋游戲

    這篇文章主要為大家詳細介紹了java swing實現(xiàn)簡單的五子棋游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • SpringBoot整合Shiro思路(最新超詳細)

    SpringBoot整合Shiro思路(最新超詳細)

    這篇文章主要介紹了SpringBoot整合Shiro思路(最新超詳細),本文內容比較長,通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-03-03
  • java彈幕小游戲1.0版本

    java彈幕小游戲1.0版本

    這篇文章主要為大家詳細介紹了java彈幕小游戲1.0版本,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • Java導入、導出excel用法步驟保姆級教程(附封裝好的工具類)

    Java導入、導出excel用法步驟保姆級教程(附封裝好的工具類)

    這篇文章主要介紹了Java導入、導出excel的相關資料,講解了使用Java和ApachePOI庫將數(shù)據(jù)導出為Excel文件,包括創(chuàng)建工作簿、工作表、行和單元格,設置樣式和字體,合并單元格,添加公式和下拉選擇等功能,需要的朋友可以參考下
    2025-03-03
  • Springboot2.x+ShardingSphere實現(xiàn)分庫分表的示例代碼

    Springboot2.x+ShardingSphere實現(xiàn)分庫分表的示例代碼

    這篇文章主要介紹了Springboot2.x+ShardingSphere實現(xiàn)分庫分表的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-10-10
  • Java實現(xiàn)PDF在線預覽功能(四種方式)

    Java實現(xiàn)PDF在線預覽功能(四種方式)

    這篇文章主要介紹了Java實現(xiàn)PDF在線預覽功能的四種方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Java遍歷Map的方法匯總

    Java遍歷Map的方法匯總

    大家平時在使用Java開發(fā)時,經(jīng)常會遇到遍歷Map對象的問題,本文就給大家介紹幾種Java遍歷Map對象的方法,并簡單分析一下每種方法的效率,需要的朋友可以參考下
    2023-12-12
  • 在Spring Boot中淺嘗內存泄漏的實戰(zhàn)記錄

    在Spring Boot中淺嘗內存泄漏的實戰(zhàn)記錄

    本文給大家分享在Spring Boot中淺嘗內存泄漏的實戰(zhàn)記錄,結合實例代碼給大家介紹的非常詳細,感興趣的朋友一起看看吧
    2025-04-04
  • 關于Java鎖性能提高(鎖升級)機制的總結

    關于Java鎖性能提高(鎖升級)機制的總結

    這篇文章主要介紹了關于Java鎖性能提高(鎖升級)機制的總結,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-05-05

最新評論

东光县| 凭祥市| 永和县| 天水市| 凉山| 淳安县| 抚宁县| 新昌县| 江安县| 邳州市| 松滋市| 镇远县| 辉南县| 星子县| 治县。| 墨江| 扎兰屯市| 宣威市| 巴彦淖尔市| 乃东县| 民勤县| 佛坪县| 博客| 沁源县| 沧源| 乳源| 苏尼特左旗| 从化市| 章丘市| 普陀区| 温泉县| 得荣县| 阿勒泰市| 张掖市| 九龙坡区| 克山县| 云林县| 同德县| 延边| 沂水县| 辽阳市|