aop 多数据源

该博客介绍了如何在Spring Boot中配置多个数据源,并实现动态数据源切换。通过自定义注解@DataSource,可以在方法级别指定数据源。同时,配置了事务管理器以支持不同的数据源,并提供了动态数据源切面来实现在不同数据源之间的事务处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

此方法是在需要使用的地方加上自定义注解@DataSource

根据注解下这个方法的传参 注意: (规定参数命名)

配置文件yml

spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      minimum-idle: 5
      maximum-pool-size: 15
      auto-commit: true
      idle-timeout: 30000
      pool-name: HikariCP
      max-lifetime: 1800000
      connection-timeout: 30000
    ds1:
      jdbc-url: jdbc:mysql://localhost:3306/pubs?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
      username: root
      password: 1234
      driver-class-name: com.mysql.jdbc.Driver
    ds2:
      jdbc-url: jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
      username: root
      password: 1234
      driver-class-name: com.mysql.jdbc.Driver
  
config配置文件

/**
 * 配置Druid 多个数据源和 Druid监控Servlet
 *
 * 所有的数据源配置都在这里 要添加多个的话
 *
 * */
@Configuration
public class DataSourceConfig {

    private static final Logger log = LoggerFactory.getLogger(DataSourceConfig.class);

    //数据源一
    @Bean(name = "dataSource1" )
    @ConfigurationProperties(prefix="spring.datasource.ds1")
    public DataSource dataSource1() {
        return DataSourceBuilder.create().build();
    }

    //数据源二
    @Bean(name = "dataSource2" )
    @ConfigurationProperties(prefix="spring.datasource.ds2")
    public DataSource dataSource2() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "dataSource3" )
    @ConfigurationProperties(prefix="spring.datasource.ds3")
    public DataSource dataSource3() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 记得添加完数据源后要在这里添加到dynamicDataSource中
     * 动态数据源: 通过AOP在不同数据源之间动态切换
     * */
    @Primary
    @Bean(name = "dynamicDataSource")
    public DataSource dynamicDataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource(); //动态数据源配置类
        // 默认数据源
        dynamicDataSource.setDefaultTargetDataSource(dataSource1());
        // 配置多数据源
        Map<Object, Object> dsMap = new HashMap();
        dsMap.put("dataSource1", dataSource1());
        dsMap.put("dataSource2", dataSource2());
        dsMap.put("dataSource3", dataSource3());

        dynamicDataSource.setTargetDataSources(dsMap);
        return dynamicDataSource;
    }

<!-------------------------------mybatis---------------->
   /**
     * 配置@Transactional注解事物
     * @return
     */
    @Bean(name = "dataSourceTransactionManager1")
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource1());
    }
    @Bean(name = "dataSourceTransactionManager2")
    public PlatformTransactionManager transactionManager2() {
        return new DataSourceTransactionManager(dataSource2());
    }
     @Bean(name = "dataSourceTransactionManager3")
    public PlatformTransactionManager transactionManager2() {
        return new DataSourceTransactionManager(dataSource2());
    }
}

//jpa配置事务<!----------------------jpa------------------------->
@Configuration
public class TransactionManagerConfig implements TransactionManagementConfigurer {
    @Resource(name="transactionManager")
    private PlatformTransactionManager txManager;

//	// 创建事务管理器1
//	@Bean(name = "txManager1")
//	public PlatformTransactionManager txManager(DataSource dataSource) {
//		return new DataSourceTransactionManager(dataSource);
//	}

    // 创建事务管理器
    @Bean(name = "transactionManager")
    public PlatformTransactionManager txManager(EntityManagerFactory factory) {
        return new JpaTransactionManager(factory);
    }

    //其返回值代表在拥有多个事务管理器的情况下默认使用的事务管理
    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return txManager;
    }


/**
 * 动态数据源
 * 配置当前数据源源和默认数据源
 * 设置清除数据源等操作
 * */
public class DynamicDataSource extends AbstractRoutingDataSource {

    public static final String DEFAULT_DS = "dataSource1";

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();


    // 设置数据源名
    public static void setDataSource(String dataSource) {
        contextHolder.set(dataSource);
    }

    //获取数据源
    public static String getDataSource() {
        return contextHolder.get();
    }
    //清除数据源
    public static void clearDataSource() {
        contextHolder.remove();
    }

    //当前数据源
    @Override
    protected Object determineCurrentLookupKey() {
        return getDataSource();
    }

//自定义接口
/**
 * 多数据源注解默认pcv
 */
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
    String value() default "dataSource1";
}

//动态数据源切面
@Aspect
@Component
public class DynamicDataSourceAspect {

    @Autowired
    HttpSession session;

    @Before("@annotation(DataSource)")
    public void beforeSwitchDS(JoinPoint point) {
        //获得当前访问的class
        Class<?> className = point.getTarget().getClass();
        //获得访问的方法名
        String methodName = point.getSignature().getName();
        //得到方法的参数的类型
        Class[] argClass = ((MethodSignature) point.getSignature()).getParameterTypes();
        String dataSource = DynamicDataSource.DEFAULT_DS;
        try {
            // 得到访问的方法对象
            Method method = className.getMethod(methodName, argClass);
            // 判断是否存在@DataSource注解
            if (method.isAnnotationPresent(DataSource.class)) {
                DataSource annotation = method.getAnnotation(DataSource.class);

                //1.这里获取到所有的参数值的数组
                Object[] args = point.getArgs();
                Signature signature = point.getSignature();
                MethodSignature methodSignature = (MethodSignature) signature;
                //2.最关键的一步:通过这获取到方法的所有参数名称的字符串数组
                String[] parameterNames = methodSignature.getParameterNames();

                Map<String, Object> aopParams = getAopParams(args, parameterNames);//得到参数的键值对

                dataSource =  Optional.ofNullable(aopParams.get("dataSource"))
                        .flatMap(m->Optional.ofNullable(DataSourceEnum.getValueByCode(m.toString()))).orElse(dataSource);
               //第二种
                /*if (aopParams.containsKey("dataSource")) {
                    if (StringUtils.isEmpty(aopParams.get("dataSource"))) {
                        dataSource = annotation.value();
                    } else {
                        //枚举中是否有这个值
                        if (StringUtils.isEmpty(DataSourceEnum.getValueByCode(aopParams.get("dataSource").toString()))) {
                            dataSource = annotation.value();
                        } else {
                            dataSource = DataSourceEnum.getValueByCode(aopParams.get("dataSource").toString());
                        }
                    }
                } else {
                    dataSource = annotation.value();
                }*/
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 切换数据源
        DynamicDataSource.setDataSource(dataSource);
    }

    @After("@annotation(DataSource)")
    public void afterSwitchDS(JoinPoint point) {
        DynamicDataSource.clearDataSource();
    }

    /**
     * @Description: 方法是aop拦截方法得到方法中的变量和值  返回一个map
     * @param: args :所有的value集合   item 所有的key集合
     * @return: Map<String, Object>
     * @auther: 汪亚平
     * @date: 2020/10/16 10:19
     */
    public static Map<String, Object> getAopParams(Object[] args, String[] item) {
        Map<String, Object> map = new HashMap<>();
        for (int i = 0; i < item.length; i++) {
            map.put(item[i], args[i]);
        }
        return map;
    }

使用mybatisplus进行操作
如果使用了@Transactional 添加事物 记得添加是哪个事物

public class DemoServiceImpl extends ServiceImpl<Demo, Student> implements DemoService{

    @DataSource
    @Override
    @Transactional(rollbackFor = Exception.class, transactionManager = "dataSourceTransactionManager2")
    public void saveStudent(List<Student> student,String dataSource) {
        //System.out.println(student.toString());
        System.out.println(list().toString()+"-------"+dataSource);
        saveBatch(student);
    }

    @DataSource
    @Override
    public List<Student> queryList(String dataSource) {
        System.out.println(list().toString()+"----------"+dataSource);
        return list();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值