• spring boot 配置多数据源


    记录一下spring boot集成mybatis plus,配置 alibaba druid 多数据源的步骤。

    1. 引用mybatis plus,aop,mysql依赖

    <dependency>
       <groupId>com.baomidou</groupId>
       <artifactId>mybatis-plus-boot-starter</artifactId>
       <version>${mybatis.plus.version}</version>
    </dependency>
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>${mysql.driver.version}</version>
    </dependency>

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

    2. 生成entity,mapper (略过)

    3. 配置mapperlocation,application.yml 配置druid多数据源

    server:
      port: 18801
    
    
    mybatis-plus:
      mapper-locations: classpath:mapper/**.xml
      global-config:
        db-config:
          id-type: auto
          field-strategy: not_empty
          column-underline: true
          logic-delete-value: 0
          logic-not-delete-value: 1
          db-type: mysql
        refresh: false
      configuration:
        map-underscore-to-camel-case: true
        cache-enabled: false
    
    druid:
      type: com.alibaba.druid.pool.DruidDataSource
      master:
          url: jdbc:mysql://数据库ip:3306/数据库名称?useUnicode=true&characterEncoding=UTF-8&useSSL=false
          driver-class-name: com.mysql.jdbc.Driver
          username: 数据库账号
          password: 数据库密码
      slave:
          url: jdbc:mysql://数据库ip:3306/数据库名称?useUnicode=true&characterEncoding=UTF-8&useSSL=false
          driver-class-name: com.mysql.jdbc.Driver
          username: 数据库账号
          password: 数据库密码

    4.编写database.config

      4.1注入masterDatasource bean和slaveDatasource Bean

    package com.ming.project.config.database;
    
    import com.alibaba.druid.support.http.StatViewServlet;
    import lombok.Data;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.jdbc.DataSourceBuilder;
    import org.springframework.boot.web.servlet.ServletRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import javax.sql.DataSource;
    import java.sql.SQLException;
    
    
    @Slf4j
    @Configuration
    @EnableTransactionManagement
    public class DataSourceConfiguration {
    
        @Value("${druid.type}")
        private Class<? extends DataSource> dataSourceType;
    
        @Bean(name = "masterDataSource")
        @Primary
        @ConfigurationProperties(prefix = "druid.master")
        public DataSource masterDataSource() throws SQLException {
            DataSource masterDataSource = DataSourceBuilder.create().type(dataSourceType).build();
            log.info("------------------master datasource-------------");
            return masterDataSource;
        }
    
        @Bean(name = "slaveDataSource")
        @ConfigurationProperties(prefix = "druid.slave")
        public DataSource slaveDataSource() throws SQLException {
            DataSource salveDataSource = DataSourceBuilder.create().type(dataSourceType).build();
            log.info("------------------slave datasource-------------");
            return salveDataSource;
        }
    
        @Bean
        public ServletRegistrationBean druidServlet() {
            ServletRegistrationBean reg = new ServletRegistrationBean();
            reg.setServlet(new StatViewServlet());
            reg.addUrlMappings("/druid/*");
            reg.addInitParameter("allow","localhost");
            reg.addInitParameter("deny","/deny");
            return reg;
        }
    }

      4.2 masterDataSource bean、slaveDataSource bean  和 sqlsessionfactory 产生关联,通过AbstractRoutingDataSource,编写实现类集成AbstractRoutingDataSource重写determineCurrentLookupKey方法,返回DatasourceContextHolder持有的数据源    

    package com.ming.project.config.database;
    
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.springframework.boot.autoconfigure.AutoConfigureAfter;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    import javax.annotation.Resource;
    import javax.sql.DataSource;
    import java.util.HashMap;
    
    @Configuration
    @AutoConfigureAfter(DataSourceConfiguration.class)
    public class MybatisPlusConfig {
    
        @Resource(name = "masterDataSource")
        private DataSource masterDataSource;
    
        @Resource(name = "slaveDataSource")
        private DataSource slaveDataSource;
    
        @Bean(name = "sqlSessionFactory")
        public SqlSessionFactory sqlSessionFactory () throws Exception {
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            sqlSessionFactoryBean.setDataSource(roudRobbinDataSourceProxy());
            return sqlSessionFactoryBean.getObject();
        }
    
        public AbstractRoutingDataSource roudRobbinDataSourceProxy() {
            ReadWriteRoutingDataSource proxy = new ReadWriteRoutingDataSource();
            HashMap<Object, Object> map = new HashMap<>();
            map.put(DatabaseContextHolder.DataBaseType.MASTER,masterDataSource);
            map.put(DatabaseContextHolder.DataBaseType.SLAVE,slaveDataSource);
            proxy.setTargetDataSources(map);
            proxy.setDefaultTargetDataSource(masterDataSource);
            return proxy;
        }
    }
    package com.ming.project.config.database;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    import org.springframework.stereotype.Component;
    
    public class ReadWriteRoutingDataSource extends AbstractRoutingDataSource {
        @Override
        protected Object determineCurrentLookupKey() {
            return DatabaseContextHolder.getDataBaseType();
        }
    }

      4.3 DatasourceContextHolder封装threadlocal,管理数据源类型

    package com.ming.project.config.database;
    public class DatabaseContextHolder {
    
        public enum DataBaseType {
            MASTER, SLAVE;
        }
    
        private static final ThreadLocal<DataBaseType> contextHolder = new ThreadLocal<>();
    
        public static void setDataBaseType(DataBaseType dataBaseType) {
            contextHolder.set(dataBaseType);
        }
    
        public static DataBaseType getDataBaseType() {
            return contextHolder.get() == null ? DataBaseType.MASTER : contextHolder.get();
        }
    
        public static void clear() {
            contextHolder.remove();
        }
    
    }

       4.4 编写aspect,对annotation进行拦截

    package com.ming.project.config.database;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    
    @Target({ElementType.METHOD,ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ReadOnlyConnection {
    }
    package com.ming.project.config.database;
    
    import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.springframework.core.Ordered;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    public class ReadOnlyConnectionInceptor implements Ordered {
    
        @Around("@annotation(readOnlyConnection)")
        public Object proceed(ProceedingJoinPoint proceedingJoinPoint, ReadOnlyConnection readOnlyConnection) throws Throwable {
            DatabaseContextHolder.setDataBaseType(DatabaseContextHolder.DataBaseType.SLAVE);
            Object result = proceedingJoinPoint.proceed();
            return result;
        }
    
        @Override
        public int getOrder() {
            return 0;
        }
    }

    5. 对使用只读数据源的service方法增加注解(略过)

    总结:多数据源的套路是先在yml中配置多个连接源,接着在配置类中,把多个数据源datasource注入到容器中。mybatis plus通过SqlsessionFactory管理数据源连接数据库,所以要把数据源和SqlSessionFactory关联起来,SqlSessionFactory可以设置AbstractRoutingDataSource类型的数据源,AbstractRoutingDataSource可以把多个数据源放入其中,通过一个map结构,然后通过determineCurrentLookupKey方法返回map的key,找到具体要是用的数据源。所以自己要写一个类ReadWriteRoutingDataSource实现AbstractRoutingDataSource,重写determineCurrentLookupKey方法,至此,多数据源的配置就完成了。但是要使用,怎么使用呢,方法是自定义注解,通过aop的方式拦截有这个注解的方法,在方法执行前设置一下数据源。为了让多个线程使用的数据源隔离,用到了ThreadLocal来管理数据源类型,这里写了一个DatabaseContextHolder做了封装。 好了,现在从配置多数据源到使用都已经完成了。

    有需要demo源码的童鞋可以点击这里下载:demo源码

  • 相关阅读:
    20110228 12:20 .net httpHandler和httpModule
    Microsoft CRM 2011清除缓存
    Sql Server Reporing Service / Windows Azure SQL Reporting应用程序开发
    终于来Cnblogs开博啦!~
    瑞星与360事件依我之看
    xml 基础 学习
    程序员的人生
    C# 发送邮件 .net SendEmail 源码
    Repeater 嵌套 绑定数据,嵌套的Repeater无法绑定的问题
    从maya中 导入物体 到Uniyt3D 规范 整理
  • 原文地址:https://www.cnblogs.com/cs-js/p/13599324.html
Copyright © 2020-2023  润新知