您的当前位置:首页springboot2.1.2 + hibernate5.2.11配置多数据源

springboot2.1.2 + hibernate5.2.11配置多数据源

来源:锐游网

项目需要用springboot2.1.2+hibernate5.2.11,配置多数据源时候因为dao层用的是公司封装的框架,没有实体没有映射,折腾了几天总算好了,记录一下

配置文件:application-dev.yml

spring:
  datasource:
    driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
    type: com.alibaba.druid.pool.DruidDataSource
    initialSize: 1
    minIdle: 3
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 30000
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    maxPoolPreparedStatementPerConnectionSize: 20
    validationQuery: SELECT 1 FROM DUAL
    # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
    filters: stat,slf4j
    # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
    # 合并多个DruidDataSource的监控数据
    #useGlobalDataSourceStat: true
    source1:
      url: jdbc:sqlserver://xxxx;instanceName=MSSQLSERVER;DatabaseName=xxxx;integratedSecurity=false
      username: xxxx
      password: xxxxxxx
    source2:
      url: jdbc:sqlserver://xxxx;DatabaseName=xxxx;integratedSecurity=false
      username: xxxx
      password: xxxxxxx

DataSourceAspect.java 

@Aspect
@Order(1)
@Component
public class DataSourceAspect {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    // 切入点:service类的方法上(这个包的子包及所有包的里面的以Service结尾的类的任意方法名任意参数的方法,都讲被切到)
    @Pointcut("execution(* com.xxxx.xxxxxx..*Service..*(..))")
    public void dataSourcePointCut(){
        System.out.println("dataSourcePointCut service");
    }

    @Before("dataSourcePointCut()")
    private void before(JoinPoint joinPoint){
        Object target = joinPoint.getTarget();
        String method = joinPoint.getSignature().getName();
        Class<?> classz = target.getClass();
        Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes();
        try {
            Method m = classz.getMethod(method,parameterTypes);

            // 如果 m 上存在切换数据源的注解,则根据注解内容进行数据源切换
            if (m != null && m.isAnnotationPresent(TargetDataSource.class)){
                TargetDataSource data = m.getAnnotation(TargetDataSource.class);
                JdbcContextHolder.putDataSource(data.value().getName());
                logger.info("》》》》》》》 current thread " + Thread.currentThread().getName() + " add 【 " + data.value().getName() + " 】 to ThreadLocal");
            } else { // 如果不存在,则使用默认数据源
                logger.info("》》》》》》》 use default datasource");
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    // 执行完切面后,将线程共享中的数据源名称清空
    @After("dataSourcePointCut()")
    public void after(JoinPoint joinPoint){
        JdbcContextHolder.removeDataSource();
    }
}

 DataSourceConfig.java

@Configuration
public class DataSourceConfig {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Value("${spring.datasource.source1.url}")
    private String dbUrl;

    @Value("${spring.datasource.source1.username}")
    private String username;

    @Value("${spring.datasource.source1.password}")
    private String password;

    @Value("${spring.datasource.driverClassName}")
    private String driverClassName;

    @Value("${spring.datasource.validationQuery}")
    private String validationQuery;

    @Bean(name="source1")
    public DataSource dataSourceMysql(){
        System.out.println("----------------主配" + dbUrl);
        DruidDataSource datasource = new DruidDataSource();
        datasource.setUrl(dbUrl);
        datasource.setUsername(username);
        datasource.setPassword(password);
        datasource.setDriverClassName(driverClassName);
        datasource.setValidationQuery(validationQuery);
        setDruidOptions(datasource); // 设置druid数据源的属性
        return datasource;
    }

    @Value("${spring.datasource.source2.url}")
    private String oracleUrl;

    @Value("${spring.datasource.source2.username}")
    private String oracleUsername;

    @Value("${spring.datasource.source2.password}")
    private String oraclePassword;

    @Value("${spring.datasource.driverClassName}")
    private String oracleDriverClassName;

    @Value("${spring.datasource.driverClassName}")
    private String oracleValidationQuery;

    @Bean(name="source2")
    public DataSource dataSourceOracle(){
        System.out.println("----------------次配" + oracleUrl);
        DruidDataSource datasource = new DruidDataSource();
        datasource.setUrl(oracleUrl);
        datasource.setUsername(oracleUsername);
        datasource.setPassword(oraclePassword);
        datasource.setDriverClassName(oracleDriverClassName);
        datasource.setValidationQuery(oracleValidationQuery);
        setDruidOptions(datasource); // 设置druid数据源的属性

        return datasource;
    }

    // -----------------------------------------druid config-------------------------------------

    @Value("${spring.datasource.initialSize}")
    private int initialSize;

    @Value("${spring.datasource.minIdle}")
    private int minIdle;

    @Value("${spring.datasource.maxActive}")
    private int maxActive;

    @Value("${spring.datasource.maxWait}")
    private int maxWait;

    @Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
    private int timeBetweenEvictionRunsMillis;

    @Value("${spring.datasource.minEvictableIdleTimeMillis}")
    private int minEvictableIdleTimeMillis;

    @Value("${spring.datasource.testWhileIdle}")
    private boolean testWhileIdle;

    @Value("${spring.datasource.testOnBorrow}")
    private boolean testOnBorrow;

    @Value("${spring.datasource.testOnReturn}")
    private boolean testOnReturn;

    @Value("${spring.datasource.poolPreparedStatements}")
    private boolean poolPreparedStatements;

    @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
    private int maxPoolPreparedStatementPerConnectionSize;

    @Value("${spring.datasource.filters}")
    private String filters;

    @Value("{spring.datasource.connectionProperties}")
    private String connectionProperties;

    private void setDruidOptions(DruidDataSource datasource){
        datasource.setInitialSize(initialSize);
        datasource.setMinIdle(minIdle);
        datasource.setMaxActive(maxActive);
        datasource.setMaxWait(maxWait);
        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        datasource.setTestWhileIdle(testWhileIdle);
        datasource.setTestOnBorrow(testOnBorrow);
        datasource.setTestOnReturn(testOnReturn);
        datasource.setPoolPreparedStatements(poolPreparedStatements);
        datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        try {
            datasource.setFilters(filters);
        } catch (SQLException e) {
            logger.error("druid configuration initialization filter Exception", e);
        }
        datasource.setConnectionProperties(connectionProperties);
    }


    @Bean(name = "dynamicDataSource")
    @Primary  // 优先使用,多数据源
    public DataSource dataSource(){
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        DataSource mysql = dataSourceMysql();
        DataSource oracle = dataSourceOracle();

        //设置默认数据源
        dynamicDataSource.setDefaultTargetDataSource(mysql);

        //配置多个数据源
        Map<Object,Object> map = new HashMap<>();
        map.put(DataSourceType.BJSH.getName(),mysql);
        map.put(DataSourceType.KETTLE.getName(),oracle);
        dynamicDataSource.setTargetDataSources(map);
        return dynamicDataSource;
    }

    // 事务管理
    @Bean
    public PlatformTransactionManager txManager() {
//        return new DataSourceTransactionManager(dataSource());
//注意如果maven引的包是spring-boot-starter-jdbc,则new DataSourceTransactionManager,如果引得是spring-boot-starter-data-jpa ,则new下面这个,这个坑蹲了好久才发现,不然事务不起作用
        JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
        jpaTransactionManager.setDataSource(dataSource());
        return jpaTransactionManager;
    }


    @Bean(name="druidServlet")
    public ServletRegistrationBean druidServlet() {
        ServletRegistrationBean reg = new ServletRegistrationBean();
        reg.setServlet(new StatViewServlet());
        reg.addUrlMappings("/druid/*");
        reg.addInitParameter("allow", ""); // 白名单
        return reg;
    }

    @Bean(name = "filterRegistrationBean")
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        filterRegistrationBean.addInitParameter("profileEnable", "true");
        filterRegistrationBean.addInitParameter("principalCookieName","USER_COOKIE");
        filterRegistrationBean.addInitParameter("principalSessionName","USER_SESSION");
        filterRegistrationBean.addInitParameter("DruidWebStatFilter","/*");
        return filterRegistrationBean;
    }
}

DataSourceType.java

public enum DataSourceType {
    SOURCE1("source1"),
    SOURCE2("source2");

    private String name;

    DataSourceType(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

DynamicDataSource.java 

public class DynamicDataSource extends AbstractRoutingDataSource {

    /** 数据源路由,此方法用于产生要选取的数据源逻辑名称 */
    @Override
    protected Object determineCurrentLookupKey() {
        //从共享线程中获取数据源名称
        return JdbcContextHolder.getDataSource();
    }
}

 

JdbcContextHolder.java
public class JdbcContextHolder {
    /** 本地线程共享对象(保证在同一线程下切换后不要被其他线程修改) */
    private final static ThreadLocal<String> local = new ThreadLocal<>();

    public static void putDataSource(String name){
        local.set(name);
    }

    public static String getDataSource(){
        return local.get();
    }

    public static void removeDataSource(){
        local.remove();
    }
}

TargetDataSource.java

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TargetDataSource {

    DataSourceType value() default DataSourceType.BJSH;
}

DataServiceApplication.java

@EnableTransactionManagement
//配上开启事务管理
@EnableAspectJAutoProxy(exposeProxy = true)
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
//这里需要排除掉自动装载的datasource
@ComponentScan(value = {"com.xxxxxxx.xxxxxxx.*", "com.xxxxxx.*", "com.xxxxx.xxxxx.*"},excludeFilters = @ComponentScan.Filter(type = FilterType.CUSTOM, classes = DruidCinfugExcludeFilter.class))
//引入公司的包,因为公司的包里封装了DruidConfig,所以需要排除掉
public class DataServiceApplication extends SpringBootServletInitializer {

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

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(DataServiceApplication.class);
    }
}

 

参考:

另外一个参考的找不到了

 

因篇幅问题不能全部显示,请点此查看更多更全内容

Top