spring boot系列之动态数据源

// 动态数据源配置文件
spring:
    datasource:
        type: com.alibaba.druid.pool.DruidDataSource // druid数据库连接池
        driverClassName: com.mysql.jdbc.Driver
        druid:
            first: 
                 url: jdbc:mysql://localhost:3306/test1
                 username: root
                 password: root
            second: 
                 url: jdbc:mysql://localhost:3306/test2
                 username: root
                 password: root
            initial-size: 10
            max-active: 100
            min-idle: 10
            max-wait: 60000
            // 预缓存设置,PSCache对支持游标的数据库oracle性能提升巨大,jdbc的标准参数用以控制数据源内加载的preparedStatements数量,预缓存的statements属单个connection而不是整个连接池。
            pool-prepared-statements: true
            //单个连接拥有的最大缓存数:要启用PSCache必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些。
            max-pool-prepared-statement-per-connection-size: 20
            time-between-eviction-runs-millis: 60000 // 每1分钟运行一次空闲连接回收线程
            min-evictable-idle-time-millis: 300000 // 池中的连接空闲30分钟后被回收
            validation-query: SELECT 1 FROM DUAL
            test-while-idle: true
            test-on-borrow: false
            test-on-return: false
            stat-view-servlet:
                enabled: true
                url-pattern: /druid/*
                #login-username: admin
                #login-password: admin
            filter:
                stat:
                    log-slow-sql: true
                    slow-sql-millis: 1000 // 慢查询1秒
                    merge-sql: true // 合并sql,增强统计效果
                wall:
                    config:
                        multi-statement-allow: true // 允许一次执行多条sql

/**
 * 动态数据源配置类
 */
@Configuration
public class DynamicDataSourceConfig {
    @Bean
    @ConfigurationProperties("spring.datasource.druid.first")
    public DataSource firstDataSource(){
        return DruidDataSourceBuilder.create().build();
    }
    @Bean
    @ConfigurationProperties("spring.datasource.druid.second")
    public DataSource secondDataSource(){
        return DruidDataSourceBuilder.create().build();
    }
    @Bean
    @Primary
    public DynamicDataSource dataSource(DataSource firstDataSource, DataSource secondDataSource) {
        Map targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceNames.FIRST, firstDataSource);
        targetDataSources.put(DataSourceNames.SECOND, secondDataSource);
        return new DynamicDataSource(firstDataSource, targetDataSources);
    }
}

/**
 * 动态数据源
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    private static final ThreadLocal contextHolder = new ThreadLocal<>();
    public DynamicDataSource(DataSource defaultTargetDataSource, 
                             Map targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(new HashMap<>(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();
    }
}

/**
 * 数据源名称
 */
public interface DataSourceNames {
    String FIRST = "first";
    String SECOND = "second";
}

/**
 * 多数据源注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
    String name() default "";
}

/**
 * 多数据源切面类
 */
@Aspect
@Component
public class DataSourceAspect implements Ordered {
    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Pointcut("@annotation(com.ysguo.datasources.annotation.DataSource)")
    public void dataSourcePointCut() {

    }

    @Around("dataSourcePointCut()")
    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.FIRST);
            logger.debug("set datasource is " + DataSourceNames.FIRST);
        }else {
            DynamicDataSource.setDataSource(ds.name());
            logger.debug("set datasource is " + ds.name());
        }
        try {
            return point.proceed();
        } finally {
            DynamicDataSource.clearDataSource();
            logger.debug("clean datasource");
        }
    }

    @Override
    //多个切面类执行顺序优先级设置:值越小优先级越高
    public int getOrder() {
        return 1;
    }
}
/**
 * 使用@DataSource注解切换数据源
 */
@Service
public class UserInfoServiceImpl implements UserInfoService {
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Override
    @DataSource(name=DataSourceNames.SECOND)
    public List getUserInfoById(Integer userId) {
        return userInfoMapper.getUserInfoById(userId);
    }
}
转载:https://www.jianshu.com/p/88e9d9cce636
 

你可能感兴趣的:(Spring,boot)