IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> springBoot配置多数据源 -> 正文阅读

[Java知识库]springBoot配置多数据源

通过在mapper接口上添加自定数据源注解@DataSource来制定数据源

1.添加切面aspectjweaver依赖

            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.7</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
                <version>1.5.9.RELEASE</version>
            </dependency>

2.启动类添加切面支持注解@EnableAspectJAutoProxy(proxyTargetClass = true)

@Import({DynamicDataSourceConfig.class})

exclude = {DataSourceAutoConfiguration.class} 不加这个会报错,循环依赖问题(查了好久才解决)

import org.linlinjava.litemall.db.datasources.DynamicDataSourceConfig;
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.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@MapperScan("org.linlinjava.litemall.db.dao")
@EnableTransactionManagement
@EnableAspectJAutoProxy(proxyTargetClass = true)
@EnableScheduling
@Import({DynamicDataSourceConfig.class})
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

3自定义注解DataSource.java


import java.lang.annotation.*;

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

数据源名称枚举

/**
 * 增加多数据源,在此配置
 *
 */
public interface DataSourceNames {
    String LITEMALL = "mall";

    String ZOOM = "zoom";

}

动态数据源配置类


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

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

/**
 * 动态数据源
 *
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public DynamicDataSource(DataSource defaultTargetDataSource, Map<String, DataSource> 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();
    }

}

配置多数据源


import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;


import javax.sql.DataSource;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 配置多数据源
 *
 */
@Configuration
public class DynamicDataSourceConfig {

    @Bean
    @ConfigurationProperties("spring.datasource.druid.mall")
    public DataSource liteMallDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("spring.datasource.druid.zoom")
    public DataSource zoomDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public DynamicDataSource dataSource(DataSource liteMallDataSource, DataSource zoomDataSource) {
        Map<String, DataSource> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceNames.LITEMALL, liteMallDataSource);
        targetDataSources.put(DataSourceNames.ZOOM, zoomDataSource);
        return new DynamicDataSource(liteMallDataSource, targetDataSources);
    }

    @Aspect
    @Component
    class DataSourceAspect implements Ordered {
        protected Logger logger = LoggerFactory.getLogger(getClass());

        public DataSourceAspect() {
            System.out.println(0);
        }

        @Pointcut("@within(org.linlinjava.litemall.db.datasources.annotation.DataSource)")
        public void dataSourcePointCut() {
            System.out.println(0);
        }

        @Around("dataSourcePointCut()")
        public Object around(ProceedingJoinPoint point) throws Throwable {

            org.linlinjava.litemall.db.datasources.annotation.DataSource ds = null;

            Class clazz = point.getTarget().getClass();
            ds = (org.linlinjava.litemall.db.datasources.annotation.DataSource) clazz.getAnnotation(org.linlinjava.litemall.db.datasources.annotation.DataSource.class);

            if (ds == null) {
                MethodSignature signature = (MethodSignature) point.getSignature();
                Method method = signature.getMethod();
                ds = method.getAnnotation(org.linlinjava.litemall.db.datasources.annotation.DataSource.class);
            }

            if (ds == null) {
                DynamicDataSource.setDataSource(DataSourceNames.LITEMALL);
                logger.debug("set datasource is " + DataSourceNames.LITEMALL);
            } 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;
        }
    }

}

4.Yaml配置

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      zoom:  #数据源2
        url: xxxxxx/zoom?useUnicode=true&characterEncoding=utf8&useSSL=false
        driver-class-name:  com.mysql.cj.jdbc.Driver
        username: 0000
        password: 00000
        filter:
          slf4j:
            enabled: true
      mall:
        url:  jdbc:xxxxxx/litemall?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&verifyServerCertificate=false&useSSL=false
        driver-class-name:  com.mysql.cj.jdbc.Driver
        username:  00000
        password:  00000
        initial-size:  10
        max-active:  50
        min-idle:  10
        max-wait:  60000
        pool-prepared-statements:  true
        max-pool-prepared-statement-per-connection-size:  20
        validation-query:  SELECT 1 FROM DUAL
        test-on-borrow:  false
        test-on-return:  false
        test-while-idle:  true
        time-between-eviction-runs-millis:  60000
        webStatFilter:
          enabled: true
        statViewServlet:
          enabled: false
        filter:
          stat:
            enabled: false

5.测试


import org.junit.Test;
import org.junit.runner.RunWith;
import org.linlinjava.litemall.db.dao.StatMapper;
import org.linlinjava.litemall.db.dao.ZoomMapper;
import org.linlinjava.litemall.db.datasources.DynamicDataSourceConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import javax.annotation.Resource;

@WebAppConfiguration
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
@RunWith(SpringRunner.class)
@SpringBootTest
@Import({DynamicDataSourceConfig.class})
public class DbTest {

    @Autowired
    private ZoomMapper zoomMapper;

    @Test
    public void test() {
        System.out.println(zoomMapper.queryName());
    }

}

6,可能出现的异常

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

zoomMapperService (field org.linlinjava.litemall.db.dao.ZoomMapper org.linlinjava.litemall.db.dao.impl.ZoomMapperService.zoomMapper)

zoomMapper defined in file [F:\workcode\litemall\litemall-db\target\classes\org\linlinjava\litemall\db\dao\ZoomMapper.class]

sqlSessionFactory defined in class path resource [org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.class]
┌─────┐
| dataSource defined in class path resource [org/linlinjava/litemall/db/datasources/DynamicDataSourceConfig.class]
↑ ↓
| firstDataSource defined in class path resource [org/linlinjava/litemall/db/datasources/DynamicDataSourceConfig.class]
↑ ↓
| org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker

循环依赖问题

2yaml配置问题

Caused by: org.yaml.snakeyaml.parser.ParserException: while parsing a block mapping
?in 'reader', line 9, column 5:
? ? ? ? type: com.alibaba.druid.pool.Dru ...?
? ? ? ? ^
expected <block end>, but found '<block mapping start>'
?in 'reader', line 19, column 7:
? ? ? ? ? mall:
? ? ? ? ? ^

?? ?at org.yaml.snakeyaml.parser.ParserImpl$ParseBlockMappingKey.produce(ParserImpl.java:572)
?? ?at org.yaml.snakeyaml.parser.ParserImpl.peekEvent(ParserImpl.java:158)
?? ?at org.yaml.snakeyaml.parser.ParserImpl.checkEvent(ParserImpl.java:148)
?? ?at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:214)
?? ?at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:144)
?? ?at org.yaml.snakeyaml.composer.Composer.composeValueNode(Composer.java:236)
?? ?at org.yaml.snakeyaml.composer.Composer.composeMappingChildren(Composer.java:227)
?? ?at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:215)
?? ?at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:144)
?? ?at org.yaml.snakeyaml.composer.Composer.composeValueNode(Composer.java:236)
?? ?at org.yaml.snakeyaml.composer.Composer.composeMappingChildren(Composer.java:227)
?? ?at org.yaml.snakeyaml.composer.Composer.composeMappingNode(Composer.java:215)
?? ?at org.yaml.snakeyaml.composer.Composer.composeNode(Composer.java:144)
?? ?at org.yaml.snakeyaml.composer.Composer.getNode(Composer.java:85)
?? ?at org.yaml.snakeyaml.constructor.BaseConstructor.getData(BaseConstructor.java:123)
?? ?at org.yaml.snakeyaml.Yaml$1.next(Yaml.java:547)
?? ?at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:160)
?? ?at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:134)
?? ?at org.springframework.boot.env.OriginTrackedYamlLoader.load(OriginTrackedYamlLoader.java:75)
?? ?at org.springframework.boot.env.YamlPropertySourceLoader.load(YamlPropertySourceLoader.java:50)
?? ?at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.loadDocuments(ConfigFileApplicationListener.java:574)
?? ?at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:528)
?? ?... 48 common frames omitted

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-07-03 10:36:15  更:2022-07-03 10:37:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/3 14:18:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码