首页 > 其他分享 >SpringBoot多数据源(自定义注解,动态数据源,事务实现)

SpringBoot多数据源(自定义注解,动态数据源,事务实现)

时间:2023-03-27 17:23:48浏览次数:45  
标签:SpringBoot 自定义 数据源 springframework annotation import org public

一、数据库配置文件(这里用的是阿波罗配置中心,也可以是application.yml文件)

#mysql本地数据源1 spring.datasource.db1.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.db1.jdbc-url=jdbc:mysql://127.0.0.1:3306/mysqlDB1?useUnicode=true&zeroDateTimeBehavior=convertToNull&characterEncoding=UTF-8&useSSL=false spring.datasource.db1.username=root spring.datasource.db1.password=123456

#mysql本地数据源2 spring.datasource.db2.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.db2.jdbc-url=jdbc:mysql://127.0.0.1:3306/mysqlDB2?useUnicode=true&zeroDateTimeBehavior=convertToNull&characterEncoding=UTF-8&useSSL=false spring.datasource.db2.username=root spring.datasource.db2.password=123456

#mycat本地数据源 spring.datasource.mycat.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.mycat.jdbc-url=jdbc:mysql://192.168.0.110:3306/mycatDB?useUnicode=true&zeroDateTimeBehavior=convertToNull&characterEncoding=UTF-8&useSSL=false spring.datasource.mycat.username=root spring.datasource.mycat.password=123456

二、java代码功能部分(根据自己的需求配置实现,不需要mycat分表的可以不配置mycat部分)

   1、首先实现数据源配置

import com.xxx.xxx.aop.DataSourceNames;
import com.xxx.xxx.aop.DynamicDataSource;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
 
import javax.sql.DataSource;
import java.util.*;
 
/**
 * 数据源配置
 *
 * @Author Ldpy
 * @Date 2021/11/30 16:50
 * @Version 1.0
 **/
@Configuration
@Component
@MapperScan(basePackages = DataSourceConfig.PACKAGE, sqlSessionFactoryRef = "mysqlSqlSessionFactory")
public class DataSourceConfig {
 
    static final String PACKAGE = "com.xxx.xxx.mapper";
    static final String MAPPER_LOCATION = "classpath*:com/xxx/xxx/mapper/xml/*.xml";
 
    @Bean(name = "mysqlDatasource1")
    @ConfigurationProperties("spring.datasource.db1")
    public DataSource mysqlDataSource1(){
        return DataSourceBuilder.create().build();
    }
 
    @Bean(name = "mysqlDatasource2")
    @ConfigurationProperties("spring.datasource.db2")
    public DataSource mysqlDataSource2(){
        return DataSourceBuilder.create().build();
    }
 
    @Bean(name = "mycatDatasource")
    @ConfigurationProperties("spring.datasource.mycat")
    public DataSource mycatDataSource(){
        return DataSourceBuilder.create().build();
    }
 
    @Primary
    @Bean(name = "mysqlSqlSessionFactory")
    public SqlSessionFactory mysqlSqlSessionFactory(
            @Qualifier("mysqlDatasource1") DataSource mysqlSqlSessionFactory) throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(mysqlSqlSessionFactory);
        sessionFactory.setDataSource(dataSource(mysqlDataSource1(),mysqlDataSource2(),mycatDataSource()));
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources(MAPPER_LOCATION));
        return sessionFactory.getObject();
    }
 
    @Primary
    @Bean("mysqlSqlSessionTemplate")
    public SqlSessionTemplate mysqlSqlSessionTemplate(
            @Qualifier("mysqlSqlSessionFactory") SqlSessionFactory mysqlSqlSessionFactory) {
        return new SqlSessionTemplate(mysqlSqlSessionFactory);
    }
 
    @Bean(name = "dataSource")
    @Primary
    public DynamicDataSource dataSource(@Qualifier("mysqlDatasource1") DataSource mysqlDataSource1, 
                                        @Qualifier("mysqlDatasource2") DataSource mysqlDataSource2, 
                                        @Qualifier("mycatDatasource") DataSource mycatDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceNames.MYSQLDB1, mysqlDataSource1);
        targetDataSources.put(DataSourceNames.MYSQLDB2, mysqlDataSource2);
        targetDataSources.put(DataSourceNames.MYCATDB, mycatDataSource);
        return new DynamicDataSource(mysqlDataSource1, targetDataSources);
    }
 
    /**
     * 注入事务管理器
     * @author Ldpy
     * @return
     */
    @Bean
    public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("dataSource") DataSource ds) {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(ds);
        return dataSourceTransactionManager;
    }
 
    /**
     * 注入事务管理器也可以简单这样写,与上面一个意思
     * @author Ldpy
     * @return
     */
    /*@Bean
    public DataSourceTransactionManager dataSourceTransactionManager(@Qualifier("mysqlDatasource1") DataSource mysqlDataSource1, 
                                        @Qualifier("mysqlDatasource2") DataSource mysqlDataSource2, 
                                        @Qualifier("mycatDatasource") DataSource mycatDataSource) {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource(mysqlDataSource1,mysqlDataSource2,mycatDataSource));
        return dataSourceTransactionManager;
    }*/
 
}

 

 

   2、定义数据源注解常量 

/**
 * 数据源注解常量
 *
 * @Author Ldpy
 * @Date 2021/11/30 16:55
 * @Version 1.0
 **/
public interface DataSourceNames {
    String MYSQLDB1 = "mysqlDB1";
    String MYSQLDB2 = "mysqlDB2";
    String MYCATDB = "mycatDB";
}

 

 

   3、定义数据源注解 

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
/**
 * 数据源注解
 *
 * @Author Ldpy
 * @Date 2021/11/30 16:55
 * @Version 1.0
 **/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface DataSource {
 
    String dataSourceName() default DataSourceNames.MYSQLDB1;
 
}

 

 

   4、实现数据源注解 

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
 
import java.lang.reflect.Method;
 
/**
 * 数据源注解切面实现
 *
 * @Author Ldpy
 * @Date 2021/11/30 16:58
 * @Version 1.0
 **/
@Component
@Aspect
@Order(0)
public class DataSourceSection {
 
    @Pointcut("@annotation(com.xxx.xxx.aop.DataSource)")
    public void pointCut() {
    }
 
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
 
        DataSource ds = method.getAnnotation(DataSource.class);
        if(ds == null){
            DynamicDataSource.setDataSource(DataSourceNames.MYSQLDB1);
        }else {
            DynamicDataSource.setDataSource(ds.dataSourceName());
        }
 
        try {
            return point.proceed();
        } finally {
            DynamicDataSource.clearDataSource();
        }
    }
 
}

 

 

    5、动态数据源实现

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
 
import javax.sql.DataSource;
import java.util.Map;
 
/**
 * 动态数据源
 *
 * @Author Ldpy
 * @Date 2021/11/30 16:50
 * @Version 1.0
 **/
public class DynamicDataSource extends AbstractRoutingDataSource {
 
    // 用来保存数据源与获取数据源
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
 
    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(targetDataSources);
        super.afterPropertiesSet();
    }
 
    @Override
    protected Object determineCurrentLookupKey() {
        return getDataSource();
    }
 
    public static void setDataSource(String dataSource) {
        contextHolder.set(dataSource);
    }
 
    public static String getDataSource() {
        return contextHolder.get();
    }
 
    public static void clearDataSource() {
        contextHolder.remove();
    }
 
}

 

 

三、测试部分

    1、编写启动类(注意添加@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class })屏蔽springboot的数据源自动配置)

import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.scheduling.annotation.EnableScheduling;
 
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class })
@EnableScheduling
@EnableApolloConfig
@MapperScan("com.xxx.xxx.mysql.mapper*")
public class MyApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
 
}

 

 

    2、常规测试

import com.xxx.xxx.mysql.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import java.util.List;
import java.util.Map;
 
 
/**
 * @Description 测试
 * @Author Ldpy
 * @Date 2021/11/30
 */
@RestController
@RequestMapping("/test")
public class TestController {
 
    @Autowired
    private TestService testService;
 
    /**
     * 查询
     *
     * @Author Ldpy
     * @Date 2021/11/30
     */
    @PostMapping("manualOperation")
    public List<Map<String, Object>> manualOperation(String table, String imei) {
        return testService.manualOperation(table, imei);
    }
 
    /**
     * 修改
     *
     * @Author Ldpy
     * @Date 2021/11/30
     */
    @PostMapping("manualUpdate")
    public Map<String, Object> manualUpdate(String table, String imei) {
        return testService.manualUpdate(table, imei);
    }
 
}
 

四、遇到的问题

    1、数据库连接问题:(dataSource or dataSourceClassName or jdbcUrl is required.)MySQL版本不同,jdbc-url 和 driver-class-name 的写法不同,需要注意;

    2、事务不生效:首先考虑MySQL引擎,InnoDB 引擎支持事务,而 MyISAM 引擎不支持事务,期次看下是否在配置数据源时忘记注入事务管理器。

来源于:(52条消息) SpringBoot多数据源(自定义注解,动态数据源,事务实现)_springboot多数据源注解_Ldpy的博客-CSDN博客,感谢分享

标签:SpringBoot,自定义,数据源,springframework,annotation,import,org,public
From: https://www.cnblogs.com/goPush/p/17262244.html

相关文章