文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

SpringBoot+Mybatis plus实现多数据源整合的实践

2024-04-02 19:55

关注

SpringBoot 版本为1.5.10.RELEASE,Mybatis plus 版本为2.1.8。

第一步:填写配置信息:


spring:
  aop:
    proxy-target-class: true
    auto: true
  datasource:
    druid:
      # 数据库 1
      db1:
        url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver
        initialSize: 5
        minIdle: 5
        maxActive: 20
      # 数据库 2
      db2:
        url: jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver
        initialSize: 5
        minIdle: 5
        maxActive: 20

第二步: 数据源配置:


@Configuration
@MapperScan({"com.warm.system.mapper*"})
public class MybatisPlusConfig {

    
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        //paginationInterceptor.setLocalPage(true);// 开启 PageHelper 的支持
        return paginationInterceptor;
    }

    
    @Bean
    public PerformanceInterceptor performanceInterceptor() {
        return new PerformanceInterceptor();
    }

    @Bean(name = "db1")
    @ConfigurationProperties(prefix = "spring.datasource.druid.db1" )
    public DataSource db1 () {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "db2")
    @ConfigurationProperties(prefix = "spring.datasource.druid.db2" )
    public DataSource db2 () {
        return DruidDataSourceBuilder.create().build();
    }
    
    @Bean
    @Primary
    public DataSource multipleDataSource (@Qualifier("db1") DataSource db1,
                                          @Qualifier("db2") DataSource db2 ) {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map< Object, Object > targetDataSources = new HashMap<>();
        targetDataSources.put(DBTypeEnum.db1.getValue(), db1 );
        targetDataSources.put(DBTypeEnum.db2.getValue(), db2);
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(db1);
        return dynamicDataSource;
    }

    @Bean("sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
        sqlSessionFactory.setDataSource(multipleDataSource(db1(),db2()));
        //sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper
    public static void setDbType(DBTypeEnum dbTypeEnum) {
        contextHolder.set(dbTypeEnum.getValue());
    }

    
    public static String getDbType() {
        return (String) contextHolder.get();
    }

    
    public static void clearDbType() {
        contextHolder.remove();
    }
}

public enum DBTypeEnum {
    db1("db1"), db2("db2");
    private String value;

    DBTypeEnum(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

public class DynamicDataSource extends AbstractRoutingDataSource {
    
    @Override
    protected Object determineCurrentLookupKey() {
        return DbContextHolder.getDbType();
    }
}

OK!写个单元测试来验证一下:


@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class DataTest {
    @Autowired
    private UserService userService;
    @Autowired
    private OrderService orderService;

    @Test
    public void test() {
        userService.getUserList().stream().forEach(item -> System.out.println(item));
        orderService.getOrderList().stream().forEach(item -> System.out.println(item));
    }
}

如图所示,证明数据源能动态切换了。

这里写图片描述

具体项目结构和代码参考Github。

踩坑记录:

直接调用Mybatis plus 的service方法AOP不会生效,即数据源不会动态切换,解决方法:在自己的service层中封装一下,调用自定义的service方法AOP即能正常生效了,如下所示:


@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Override
    public List<User> getUserList() {
        return selectList(null);
    }
}

application.yml 定义的mybatis plus 配置信息不生效,如:


#MyBatis
mybatis-plus:
  mapper-locations: classpath:/mapper/*/*Mapper.xml
  #实体扫描,多个package用逗号或者分号分隔
  typeAliasesPackage: com.jinhuatuo.edu.sys.entity
  global-config:
    #主键类型  0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
    id-type: 0
    #字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
    field-strategy: 2
    #驼峰下划线转换
    db-column-underline: true
    #刷新mapper 调试神器
    refresh-mapper: true
    #数据库大写下划线转换
    #capital-mode: true
    #序列接口实现类配置
    #key-generator: com.baomidou.springboot.xxx
    #逻辑删除配置
    #logic-delete-value: 0
    #logic-not-delete-value: 1
    #自定义填充策略接口实现
    meta-object-handler: com.jinhuatuo.edu.config.mybatis.MyMetaObjectHandler
    #自定义SQL注入器
    #sql-injector: com.baomidou.springboot.xxx
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: false

解决方法: 所有这些配置在MybatisPlusConfig 类中用代码的方式进行配置,分页插件亦是如此,否则统计列表总数的数据会拿不到,参考代码即可。

在application.yml配置


logging:
  level: debug

控制台也不会打印Mybatis 执行的SQL语句,解决方法:自定义日志输出方案,如在classpath下直接引入日志配置文件如logback-spring.xml即可,同时application.yml无需再配置日志信息。

logback-spring.xml配置参考:


<?xml version="1.0" encoding="UTF-8"?>
<!-- scan:配置文件如果发生改变,将会重新加载,默认值为true -->
<configuration scan="true" scanPeriod="10 seconds">  
    <!-- <include resource="org/springframework/boot/logging/logback/base.xml"/> -->
    <!-- 日志文件路径 -->
    <!-- <springProperty  name="logFilePath" source="logging.path"/> -->
    <property resource="application.yml" />
    <substitutionProperty name="LOG_HOME" value="${logging.path}" />
    <substitutionProperty name="PROJECT_NAME" value="${spring.application.name}" />
    <!--<substitutionProperty name="CUR_NODE" value="${info.node}" />-->

    <!-- 日志数据库路径 -->
    <!-- <springProperty  name="logDbPath" source="spring.datasource.one.url"/>
    <springProperty  name="logDbDriver" source="spring.datasource.one.driver-class-name"/>
    <springProperty  name="logDbUser" source="spring.datasource.one.username"/>
    <springProperty  name="logDbPwd" source="spring.datasource.one.password"/> -->

    <!-- 将日志文件 -->
    <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <append>true</append>
        <encoder>
            <pattern>
                [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n
            </pattern>
            <charset>utf-8</charset>
        </encoder>

        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/${PROJECT_NAME}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>50 MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--最多保留30天log-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
    </appender>
    <!-- 将日志错误文件-->
    <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <append>true</append>
        <encoder>
            <pattern>
                [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n
            </pattern>
            <charset>utf-8</charset>
        </encoder>

        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_HOME}/${PROJECT_NAME}-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>50 MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--最多保留30天log-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
            <!-- <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY </onMismatch> -->
        </filter>
    </appender>
    <!-- 将日志写入控制台 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>
                [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n
            </pattern>
            <!--<charset>utf-8</charset>-->
        </encoder>
    </appender>
    <!-- 将日志写入数据库 -->
    <!-- <appender name="DB-CLASSIC-MYSQL-POOL" class="ch.qos.logback.classic.db.DBAppender">  
        <connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">  
            <dataSource class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
                <driverClassName>${logDbDriver}</driverClassName>  
                <url>${logDbPath}</url>  
                <username>${logDbUser}</username>  
                <password>${logDbPwd}</password>  
            </dataSource>  
        </connectionSource>  
    </appender>  -->
    <!-- spring扩展,分环境配置log信息 -->
    <springProfile name="dev">

        <!-- <logger name="sand.dao" level="DEBUG"/> -->
        <!-- <logger name="org.springframework.web" level="INFO"/> -->
        <logger name="org.springboot.sample" level="TRACE" />
        <logger name="org.springframework.cloud" level="INFO" />
        <logger name="com.netflix" level="INFO"></logger>
        <logger name="org.springframework.boot" level="INFO"></logger>
        <logger name="org.springframework.web" level="INFO"/>
        <logger name="jdbc.sqltiming" level="debug"/>
        <logger name="com.ibatis" level="debug" />
        <logger name="com.ibatis.common.jdbc.SimpleDataSource" level="debug" />
        <logger name="com.ibatis.common.jdbc.ScriptRunner" level="debug" />
        <logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" level="debug" />
        <logger name="java.sql.Connection" level="debug" />
        <logger name="java.sql.Statement" level="debug" />
        <logger name="java.sql.PreparedStatement" level="debug" />
        <logger name="java.sql.ResultSet" level="debug" />
        <logger name="com.warm" level="debug"/>
        <root level="DEBUG">
            <appender-ref ref="console" />
            <appender-ref ref="file" />
        </root>
        <root level="ERROR">
            <appender-ref ref="file_error" />
            <!-- <appender-ref ref="DB-CLASSIC-MYSQL-POOL" /> -->
        </root>
    </springProfile>
    <springProfile name="test">
        <logger name="org.springboot.sample" level="TRACE" />
        <logger name="org.springframework.cloud" level="INFO" />
        <logger name="com.netflix" level="INFO"></logger>
        <logger name="org.springframework.boot" level="INFO"></logger>

        <logger name="org.springframework.web" level="INFO"/>
        <logger name="jdbc.sqltiming" level="debug"/>
        <logger name="com.ibatis" level="debug" />
        <logger name="com.ibatis.common.jdbc.SimpleDataSource" level="debug" />
        <logger name="com.ibatis.common.jdbc.ScriptRunner" level="debug" />
        <logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" level="debug" />
        <logger name="java.sql.Connection" level="debug" />
        <logger name="java.sql.Statement" level="debug" />
        <logger name="java.sql.PreparedStatement" level="debug" />
        <logger name="java.sql.ResultSet" level="debug" />
        <logger name="com.warm" level="DEBUG"/>
        <root level="DEBUG">
            <!-- <appender-ref ref="console" /> -->
            <appender-ref ref="file" />
        </root>
        <root level="ERROR">
            <appender-ref ref="file_error" />
            <!-- <appender-ref ref="DB-CLASSIC-MYSQL-POOL" /> -->
        </root>
    </springProfile>
    <springProfile name="prod">
        <logger name="org.springboot.sample" level="TRACE" />
        <logger name="org.springframework.cloud" level="INFO" />
        <logger name="com.netflix" level="INFO"></logger>
        <logger name="org.springframework.boot" level="INFO"></logger>

        <logger name="org.springframework.web" level="INFO"/>
        <logger name="jdbc.sqltiming" level="debug"/>
        <logger name="com.ibatis" level="debug" />
        <logger name="com.ibatis.common.jdbc.SimpleDataSource" level="debug" />
        <logger name="com.ibatis.common.jdbc.ScriptRunner" level="debug" />
        <logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" level="debug" />
        <logger name="java.sql.Connection" level="debug" />
        <logger name="java.sql.Statement" level="debug" />
        <logger name="java.sql.PreparedStatement" level="debug" />
        <logger name="java.sql.ResultSet" level="debug" />
        <logger name="com.warm" level="info"/>
        <root level="DEBUG">
            <!-- <appender-ref ref="console" /> -->
            <appender-ref ref="file" />
        </root>
        <root level="ERROR">
            <appender-ref ref="file_error" />
            <!-- <appender-ref ref="DB-CLASSIC-MYSQL-POOL" /> -->
        </root>
    </springProfile>
</configuration>

到此这篇关于SpringBoot+Mybatis plus实现多数据源整合的实践的文章就介绍到这了,更多相关SpringBoot+Mybatis plus多数据源内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯