SpringBoot + Mybatis Plus + Druid 配置多数据源

SpringBoot + Mybatis + Druid 配置多数据源: https://www.cnblogs.com/vipsoft/p/15826491.html

启动页去掉 MapperScan

@ComponentScan(basePackages = {"com.vipsoft"})
@SpringBootApplication
@EnableFeignClients(basePackages = {"com.vipsoft.*"})
//@MapperScan({"com.vipsoft.*.mapper","com.vipsoft.security.business.mapper"})  //-- 多数据库,在 DrugidConfig 中扫描
public class CuworAdminApplication {
......
}

注意,Mybatis-plus使用 MybatisSqlSessionFactoryBean ,纯 Mybatis 使用 SqlSessionFactoryBean

yml 配置


spring:
  datasource:
    primary:
      driver-class-name: com.mysql.cj.jdbc.Driver #com.mysql.cj.jdbc.Driver和mysql-connector-java 6 一起用。
    #   数据源基本配置
      url: jdbc:mysql://172.16.0.11:3306/vip_db1?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL
      username: root
      password: 110
      mapper-locations: classpath*:mapper/*.xml    #将MyBatis Mapper xml 放到 jar 包外面,发布时改成 file:mapper/hospital/*.xml
    #   政务云
    secondary:
      # MySQL  java的new Date()时间插入数据库时差差8个小时问题  GMT%2b8
      # driver-class-name: com.mysql.jdbc.Driver #com.mysql.jdbc.Driver和mysql-connector-java 5一起用。      
      driver-class-name: com.mysql.cj.jdbc.Driver #com.mysql.cj.jdbc.Driver和mysql-connector-java 6 一起用。
      url: jdbc:mysql://172.16.0.33:3306/vip_db2?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL
      username: root
      password: 110
      validation-query: select 'x' #用来检测连接是否有效的sql 必须是一个查询语句( mysql中为 select 'x'  oracle中为 select 1 from dual)
      mapper-locations: classpath*:mapper/gov/*Mapper.xml    #将MyBatis Mapper xml 放到 jar 包外面,发布时改成 file:mapper/hospital/*.xml

    type: com.alibaba.druid.pool.DruidDataSource
    #config druid
    #连接池的设置
    druid:
      initial-size: 5 #初始化时建立物理连接的个数
      min-idle: 5  #最小连接池数量
      max-active: 200  #最大连接池数量 maxIdle已经不再使用
      max-wait: 60000 #获取连接时最大等待时间,单位毫秒
      test-while-idle: true #申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
      time-between-eviction-runs-millis: 60000 #既作为检测的间隔时间又作为testWhileIdel执行的依据
      #销毁线程时检测当前连接的最后活动时间和当前时间差大于该值时,关闭当前连接
      min-evictable-idle-time-millis: 30000
      validation-query: select 'x' #用来检测连接是否有效的sql 必须是一个查询语句( mysql中为 select 'x'  oracle中为 select 1 from dual)
      test-on-borrow: false #申请连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
      test-on-return: false  #归还连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
      #exception-sorter: true #当数据库抛出不可恢复的异常时,抛弃该连接
      #pool-prepared-statements: true  #是否缓存preparedStatement,mysql5.5+建议开启
      max-pool-prepared-statement-per-connection-size: 20  #当值大于0时poolPreparedStatements会自动修改为true
      filters: stat,wall #配置扩展插件
      connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500 #通过connectProperties属性来打开mergeSql功能;慢SQL记录
      use-global-data-source-stat: true #合并多个DruidDataSource的监控数据
      #设置访问druid监控页的账号和密码,默认没有--放DrugConfig配置中
      #stat-view-servlet.login-username: admin
      #stat-view-servlet.login-password: admin 

DataSourceConfig


import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
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 javax.sql.DataSource;

@Configuration
public class DataSourceConfig {

    // 主数据源
    @Primary
    @Bean(name = "primaryDataSource")
    @ConfigurationProperties("spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    // 次数据源
    @Bean(name = "secondaryDataSource")
    @ConfigurationProperties("spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DruidDataSourceBuilder.create().build();
    }
}

PrimaryDruidConfig



import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;

import org.mybatis.spring.SqlSessionTemplate;

import javax.sql.DataSource;

/**
 * 自己的数据库
 */
@Configuration
@MapperScan(basePackages = {"com.vipsoft.*.mapper","com.vipsoft.security.business.mapper"}, sqlSessionFactoryRef = "primarySqlSessionFactory")
public class PrimaryDruidConfig {

    @Autowired
    @Qualifier("primaryDataSource")
    private DataSource primaryDataSource;
   
    @Autowired
    private MybatisPlusMetaObjectHandler metaObjectHandler;

    @Bean
    @Primary
    public SqlSessionFactory primarySqlSessionFactory() throws Exception {
        MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
        factoryBean.setDataSource(primaryDataSource);
        factoryBean.setMapperLocations(
                new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml")
        );

        // 配置 MyBatis-Plus 全局配置 -- 一定要加,否则 MybatisPlusMetaObjectHandler 实现的  MetaObjectHandler ,否则自动填充 时间人员,就无校了
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setMetaObjectHandler(metaObjectHandler); // 设置自动填充处理器

        // 将全局配置设置到工厂Bean
        factoryBean.setGlobalConfig(globalConfig);

        //向Mybatis过滤器链中添加拦截器
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        factoryBean.setPlugins(interceptor);
        return factoryBean.getObject();
    }

    @Bean
    @Primary
    public SqlSessionTemplate primarySqlSessionTemplate() throws Exception {
        SqlSessionTemplate template = new SqlSessionTemplate(primarySqlSessionFactory());
        return template;
    }

    @Bean
    @Primary
    public DataSourceTransactionManager primaryTransactionManager() {
        return new DataSourceTransactionManager(primaryDataSource);
    }
}

注意
在你的 PrimaryDruidConfig 配置中:

  1. 虽然你正确实现了 MetaObjectHandler 并添加了 @Component 注解
  2. 但没有将 MetaObjectHandler 设置到 MyBatis-Plus 的 GlobalConfig
  3. 导致 getGlobalConfig(configuration).getMetaObjectHandler() 返回 null

关键修改点

  1. 注入 MetaObjectHandler

    @Autowired
    private MetaObjectHandler metaObjectHandler;
    
  2. 创建并配置 GlobalConfig

    GlobalConfig globalConfig = new GlobalConfig();
    globalConfig.setMetaObjectHandler(metaObjectHandler);
    factoryBean.setGlobalConfig(globalConfig);
    

补充说明

  1. 确保你的 MetaObjectHandler 实现类:

    • @Component@Service 等 Spring 管理注解
    • 实现方法正确(如 insertFillupdateFill
  2. 实体类字段必须有正确的注解:

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    
    @TableField(fill = FieldFill.UPDATE)
    private LocalDateTime updateTime;
    
  3. 如果是多数据源环境,每个数据源都需要单独配置 GlobalConfig

这样修改后,自动填充功能应该能正常工作了。

SecondaryDruidConfig


import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

/**
 * 第三方数据库
 */
@Configuration
@MapperScan(basePackages = {"com.vipsoft.admin.gov.mapper"}, sqlSessionFactoryRef = "secondarySqlSessionFactory")
public class SecondaryDruidConfig {

    @Autowired
    @Qualifier("secondaryDataSource")
    private DataSource secondaryDataSource;

    @Bean
    public SqlSessionFactory secondarySqlSessionFactory() throws Exception {
        MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
        factoryBean.setDataSource(secondaryDataSource);
//        factoryBean.setMapperLocations(
//                new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml")
//        );
        return factoryBean.getObject();
    }

    @Bean
    public SqlSessionTemplate secondarySqlSessionTemplate() throws Exception {
        SqlSessionTemplate template = new SqlSessionTemplate(secondarySqlSessionFactory());
        return template;
    }

    @Bean
    public DataSourceTransactionManager secondaryTransactionManager() {
        return new DataSourceTransactionManager(secondaryDataSource);
    }

}

测试


@Service
public class GovUserServiceImpl extends ServiceImpl<GovUserMapper, GovUserInfo> implements IGovUserService {

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


    @Autowired
    private ISysDepartmentService departmentService;

    @Autowired
    private GovUserMapper govUserMapper;
 
    @Override
    public List<String> syncUser() {
        List<String> result = new ArrayList<>();
        # primaryDataSource
        List<SysDepartment> deptList = departmentService.list();
        # secondaryDataSource
        List<GovUserInfo> list = this.list();

        return result;
    }
} 
posted @ 2025-04-24 15:53  VipSoft  阅读(311)  评论(0)    收藏  举报