ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

springboot数据源切换

2022-01-30 13:31:34  阅读:140  来源: 互联网

标签:springboot 数据源 切换 org import gzt com annotation


 

需求:对不同的数据库进行操作,如读写分离

思想:在对数据库进行操作时,程序会默认去找数据源,从数据源获取一个连接connection,要做的点是在程序调用之前把数据源换了(例如本身默认是写,换成读的数据源),spring boot提供了一个AbstractRoutingDataSource类,翻译过来是抽象路由数据源,这个类可以指定使用的数据源,继承这个抽象类之后需要实现两个方法,一个方法是用来添加数据源的(读写分离就两个数据源,有其他的也可以添加进去),设置默认数据源的,还有一个是指定使用的数据源的。方法添加数据源的时候是以键值对的形式添加到map中,当指定数据源的方法返回的值在map中存在时,就是用这个key对应的数据源,如果不存在,就会使用设置的默认数据源

这里使用aop的方式来进行数据源的动态切换,先看数据源配置(这里两个数据源是读写分离,写在本机上,读在虚拟机上)

application.xml:

server:
port: 9222
spring:
datasource:
  localmysql:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/mytest?useUnicode=true&characterEncoding=utf8
    driverClassName: com.mysql.cj.jdbc.Driver
  remomysql:
    username: root
    password: root
    url: jdbc:mysql://172.21.4.130:3306/mytest?useUnicode=true&characterEncoding=utf8
    driverClassName: com.mysql.cj.jdbc.Driver
  type: com.alibaba.druid.pool.DruidDataSource

数据源配置为bean,加入ioc,供后面切换:

DatabaseResourceConfig

package com.gzt.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

/**
* @Description:
* @Author: guozhengtao
* @Date: 2022/1/29 11:48
*/
@Configuration
public class DatabaseResourceConfig {

@ConfigurationProperties(prefix = "spring.datasource.localmysql")
@Bean(value = "LocalMysql")
public DataSource getlocalDataSource() {
return new DruidDataSource();
}

@ConfigurationProperties(prefix = "spring.datasource.remomysql")
@Bean(value = "RemoMysql")
public DataSource getremoDataSource() {
return new DruidDataSource();
}
}

 

数据源key枚举:DatabaseSelectEnum

package com.gzt.config;

/**
* @Description: 定义一个枚举变量,当枚举变量的值为write是,选择写入的数据库连接,当枚举变量的值为read时,返回读取的数据库连接
* @Author: guozhengtao
* @Date: 2022/1/29 13:30
*/
public enum DatabaseSelectEnum {
/**
* 选择写枚举
* */
Write("write"),
/**
* 选择读枚举
* */
Read("read");

private final String select;

DatabaseSelectEnum(String select) {
this.select = select;
}

public String getSelect() {
return select;
}
}

 

数据源切换适配:DatabaseAdapt

package com.gzt.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
* @Description:
* @Author: guozhengtao
* @Date: 2022/1/29 13:19
*/
@Component
@Primary
public class DatabaseAdapt extends AbstractRoutingDataSource {
/**
* 默认为写的数据库(主数据库)
*/
public static String flag = DatabaseSelectEnum.Write.getSelect();

@Autowired
@Qualifier("LocalMysql")
DataSource localMysql;

@Autowired
@Qualifier("RemoMysql")
DataSource remoMysql;

/**
* 指定数据源的key,这里数据源的key使用了enum
* */
@Override
protected Object determineCurrentLookupKey() {
return flag;
}

/**
* 设置默认数据源和添加所有数据源
*/
@Override
public void afterPropertiesSet() {
//初始化所有数据源
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DatabaseSelectEnum.Write.getSelect(), localMysql);
targetDataSources.put(DatabaseSelectEnum.Read.getSelect(), remoMysql);
super.setTargetDataSources(targetDataSources);

//设置默认数据源,当上面方法返回的key找不到时,使用这里设置的数据源
super.setDefaultTargetDataSource(localMysql);

//属性设置(把上面数据源的设置到父类)
super.afterPropertiesSet();
}
}

到现在为止,数据源相关操作设置完毕,下面切换数据源的两种方式,因为在DatabaseAdapt类中定义了一个变量flag,这个flag是数据源对应的key,有两种方式来进行设置:

  1. 在方法中调用mapper之前先使用

    DatabaseAdapt.flag=DatabaseSelectEnum.Write.getSelect();

    来切换数据源,但这种方式适合单个请求的,如果类里面有多个方法请求,每个方法里都写很麻烦,所以推荐注解的方式,在类上使用注解+aop进行增强

  2. 使用aop的方式在执行方法或者类之前进行切换,主要介绍:

    注解:DatabaseResourcedefine

    package com.gzt.annotation;

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

    /**
    * @Description:
    * @Author: guozhengtao
    * @Date: 2022/1/29 14:37
    */

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DatabaseResourcedefine {
    String value() default "";
    }

    Aop:DatabaseResourceToggle

    package com.gzt.aspect;

    import com.gzt.annotation.DatabaseResourcedefine;
    import com.gzt.config.DatabaseAdapt;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;

    /**
    * @Description:
    * @Author: guozhengtao
    * @Date: 2022/1/29 15:01
    */
    @Aspect
    @Component
    public class DatabaseResourceToggle {
    final Logger logger = LoggerFactory.getLogger(getClass());

    //使用前置通知或者是环绕通知
    @Before("within(com.gzt.controller.*)&&@annotation(databaseResourcedefine)")
    public void before(JoinPoint joinPoint, DatabaseResourcedefine databaseResourcedefine) {
    DatabaseAdapt.flag=databaseResourcedefine.value();
    logger.info(databaseResourcedefine.value());
    }
    }

    目录结构如下:

  

 

主要代码部分:

package com.gzt.service;

import com.gzt.annotation.DatabaseResourcedefine;
import com.gzt.entity.User;
import com.gzt.mapper.TestMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
* @Description:
* @Author: guozhengtao
* @Date: 2022/1/30 13:03
*/
@Service
@DatabaseResourcedefine(value = "read")
public class implTestImpl implements TestService{
  final Logger logger = LoggerFactory.getLogger(getClass());
  @Autowired
  TestMapper testMapper;

  //@DatabaseResourcedefine(value = "read")
  @Override
  public List<User> getUser() {
     //DatabaseAdapt.flag= DatabaseSelectEnum.Write.getSelect();
     List<User> user = testMapper.getUser();
     logger.info(String.valueOf(user));
     return user;
  }

  //@DatabaseResourcedefine(value = "write")
  @Override
  public void setUserInfo(User user) {
     logger.info("获取到用户信息:{}",user);
     //DatabaseAdapt.flag= DatabaseSelectEnum.Write.getSelect();
     testMapper.setUserInfo(user.getName(), user.getAge(), user.getSex());
  }
}

标签:springboot,数据源,切换,org,import,gzt,com,annotation
来源: https://www.cnblogs.com/zhuojiuyibei/p/15856691.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有