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

技术SpringBoot+Mybatis plus如何实现多数据源整合的实践SpringBoot+Mybatis plus如何实现多数据源整合的实践,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方

SpringBoot Mybatis plus如何实现多数据源整合的实践,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

回弹版本为1.5.10.RELEASE,Mybatis plus版本为2.1.8。

第一步:填写配置信息:

spring:

aop:

代理-目标-类别:路径

auto:true

数据源:

德鲁伊:

#数据库一

db1:

URL : JDBC :我的SQL ://localhost :3306/db1?useUnicode=true字符编码=utf8自动重新连接=true零日期时间行为=converttonulltransformedbitboolean=true

用户名:root

password:root

驱动程序类名称:com.mysql.jdbc.Driver

初始化:5

迷你文件:5

maxActive:20

#数据库2

db2:

URL : JDBC :我的SQL ://localhost :3306/DB2?useUnicode=true字符编码=utf8自动重新连接=true零日期时间行为=converttonulltransformedbitboolean=true

用户名:root

password:root

驱动程序类名称:com.mysql.jdbc.Driver

初始化:5

迷你文件:5

maxActive:20

第二步: 数据源配置:

@配置

@ MapperScan({ ' com。温暖。系统。映射器* ' })

publicclassMybatisPlusConfig{

/**

*mybatis-plus分页插件英国铁路公司

*文档:http://MP。包米杜。combr

*/

@豆

公众的

 PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        //paginationInterceptor.setLocalPage(true);// 开启 PageHelper 的支持
        return paginationInterceptor;
    }
    /**
     * mybatis-plus SQL执行效率插件【生产环境可以关闭】
     */
    @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();
    }
    /**
     * 动态数据源配置
     * @return
     */
    @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/*/*Mapper.xml"));
        MybatisConfiguration configuration = new MybatisConfiguration();
        //configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
        configuration.setJdbcTypeForNull(JdbcType.NULL);
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setCacheEnabled(false);
        sqlSessionFactory.setConfiguration(configuration);
        sqlSessionFactory.setPlugins(new Interceptor[]{ //PerformanceInterceptor(),OptimisticLockerInterceptor()
                paginationInterceptor() //添加分页功能
        });
        sqlSessionFactory.setGlobalConfig(globalConfiguration());
        return sqlSessionFactory.getObject();
    }
    @Bean
    public GlobalConfiguration globalConfiguration() {
        GlobalConfiguration conf = new GlobalConfiguration(new LogicSqlInjector());
        conf.setLogicDeleteValue("-1");
        conf.setLogicNotDeleteValue("1");
        conf.setIdType(0);
        conf.setMetaObjectHandler(new MyMetaObjectHandler());
        conf.setDbColumnUnderline(true);
        conf.setRefresh(true);
        return conf;
    }
}

第三步:利用AOP进行数据源的动态切换:

@Component
@Aspect
@Order(-100) //这是为了保证AOP在事务注解之前生效,Order的值越小,优先级越高
@Slf4j
public class DataSourceSwitchAspect {
    @Pointcut("execution(* com.warm.system.service.db1..*.*(..))")
    private void db1Aspect() {
    }
    @Pointcut("execution(* com.warm.system.service.db2..*.*(..))")
    private void db2Aspect() {
    }
    @Before( "db1Aspect()" )
    public void db1() {
        log.info("切换到db1 数据源...");
        DbContextHolder.setDbType(DBTypeEnum.db1);
    }
    @Before("db2Aspect()" )
    public void db2 () {
        log.info("切换到db2 数据源...");
        DbContextHolder.setDbType(DBTypeEnum.db2);
    }
}
public class DbContextHolder {
    private static final ThreadLocal contextHolder = new ThreadLocal<>();
    /**
     * 设置数据源
     * @param dbTypeEnum
     */
    public static void setDbType(DBTypeEnum dbTypeEnum) {
        contextHolder.set(dbTypeEnum.getValue());
    }
    /**
     * 取得当前数据源
     * @return
     */
    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 {
    /**
     * 取得当前使用哪个数据源
     * @return
     */
    @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));
    }
}

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

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

具体项目结构和代码参考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如何实现多数据源整合的实践的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注行业资讯频道,感谢各位的阅读!

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/42397.html

(0)

相关推荐

  • css3消除锯齿的属性怎么使用(设置消除锯齿方法)

    技术css3消除锯齿的属性怎么使用本篇内容介绍了“css3消除锯齿的属性怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有

    攻略 2021年12月15日
  • 一次曲折的单点集成之旅

    技术一次曲折的单点集成之旅 一次曲折的单点集成之旅原有的系统是mvc 4.6的,要加一个简单的单点系统。经简单比较好,决定选用ids3做service。
    集成的方法直接看官方的示例即可:https://

    礼包 2021年11月22日
  • 贪心-Doing Homework again HDU

    技术贪心-Doing Homework again HDU 贪心-Doing Homework again HDU - 1789题目
    https://vjudge.net/problem/HDU-178

    礼包 2021年11月19日
  • MySQL服务器硬件和操作系统如何调节

    技术MySQL服务器硬件和操作系统如何调节小编给大家分享一下MySQL服务器硬件和操作系统如何调节,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧

    攻略 2021年12月8日
  • C++设备模板怎么声明和定义

    技术C++设备模板怎么声明和定义这篇文章主要讲解了“C++设备模板怎么声明和定义”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++设备模板怎么声明和定义”吧!将片上外设

    攻略 2021年11月30日
  • 浏览器内核分哪几类

    技术浏览器内核分哪几类本篇内容介绍了“浏览器内核分哪几类”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!  浏览器最重要或

    攻略 2021年11月12日