Spring Boot集成Mybatis双数据源

简介: 订阅专栏这里用到了Spring Boot + Mybatis + DynamicDataSource配置动态双数据源,可以动态切换数据源实现数据库的读写分离。添加依赖加入Mybatis启动器,这里添加了Druid连接池、Oracle数据库驱动为例。

这里用到了Spring Boot + Mybatis + DynamicDataSource配置动态双数据源,可以动态切换数据源实现数据库的读写分离。


添加依赖

加入Mybatis启动器,这里添加了Druid连接池、Oracle数据库驱动为例。

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
</dependency>
<dependency>
    <groupId>com.oracle</groupId>
    <artifactId>ojdbc6</artifactId>
</dependency>

添加启动类

@EnableMybatis
@EnableTransactionManagement
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(ServiceApplication.class, args);
    }
}

@EnableMybatis

@EnableTransactionManagement

@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })

public class Application {

   public static void main(String[] args) {

       SpringApplication.run(ServiceApplication.class, args);

   }

}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(MybatisConfig.class)
public @interface EnableMybatis {
}

Mybatis配置类

@Configuration
@MapperScan(basePackages = DSConfig.BASE_PACKAGES)
public class MybatisConfig implements DSConfig {
    @Primary
    @Bean
    public DynamicDataSource dynamicDataSource(@Qualifier(DB_MASTER) DataSource master,
            @Qualifier(DB_SLAVE) DataSource slave) {
        Map<Object, Object> dsMap = new HashMap<>();
        dsMap.put(DB_MASTER, master);
        dsMap.put(DB_MASTER, slave);
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setDefaultTargetDataSource(master);
        dynamicDataSource.setTargetDataSources(dsMap);
        return dynamicDataSource;
    }
    @Bean
    public PlatformTransactionManager transactionManager(DynamicDataSource dynamicDataSource) {
        return new DataSourceTransactionManager(dynamicDataSource);
    }
    @Bean
    public SqlSessionFactory sqlSessionFactory(DynamicDataSource dynamicDataSource)
            throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dynamicDataSource);
        sessionFactory.setMapperLocations(
                ((ResourcePatternResolver) new PathMatchingResourcePatternResolver())
                        .getResources(DSConfig.MAPPER_LOCATIONS));
        return sessionFactory.getObject();
    }
}

DSConfig常量类:

public interface DSConfig {
    String DS_PREFIX = "spring.datasource";
    String DS_ACTIVE = "active";
    String DB_MASTER = "db-master";
    String DB_SLAVE = "db-slave";
    String DRUID = "druid";
    String DRUID_MONITOR_USERNAME = "spring.druid.username";
    String DRUID_MONITOR_PASSWORD = "spring.druid.password";
    String DRUID_MONITOR_URL = "/druid/*";
    String DRUID_FILTER_EXCLUSIONS = "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*";
    String DRUID_FILTER_URL = "/*";
    String BASE_PACKAGES = "com.example.**.mapper";
    String MAPPER_LOCATIONS = "mapper/**/*.xml";
}

连接池配置类

Druid连接池的自动配置类:

@Configuration
@Import({ PropertiesConfig.class })
@ConditionalOnClass(DruidDataSource.class)
@ConditionalOnProperty(prefix = DSConfig.DS_PREFIX, value = DSConfig.DS_ACTIVE, havingValue = DSConfig.DRUID)
public class DruidAutoConfig implements DSConfig {
    private Logger logger = LoggerUtils.getLogger(this);
    @Bean(name = DB_MASTER, initMethod = "init", destroyMethod = "close")
    public DataSource dataSourceMaster(DruidMasterProperties masterProperties) throws SQLException {
        logger.debug("master properties: {}", masterProperties.toString());
        DruidDataSource dds = new DruidDataSource();
        dds.setDriverClassName(masterProperties.getDriverClassName());
        dds.setUrl(masterProperties.getUrl());
        dds.setUsername(masterProperties.getUsername());
        dds.setPassword(masterProperties.getPassword());
        dds.setInitialSize(masterProperties.getInitialSize());
        dds.setMinIdle(masterProperties.getMinIdle());
        dds.setMaxActive(masterProperties.getMaxActive());
        dds.setMaxWait(masterProperties.getMaxWait());
        dds.setTimeBetweenEvictionRunsMillis(masterProperties.getTimeBetweenEvictionRunsMillis());
        dds.setMinEvictableIdleTimeMillis(masterProperties.getMinEvictableIdleTimeMillis());
        dds.setValidationQuery(masterProperties.getValidationQuery());
        dds.setTestOnBorrow(masterProperties.isTestOnBorrow());
        dds.setTestWhileIdle(masterProperties.isTestWhileIdle());
        dds.setTestOnReturn(masterProperties.isTestOnReturn());
        dds.setPoolPreparedStatements(masterProperties.isPoolPreparedStatements());
        dds.setMaxPoolPreparedStatementPerConnectionSize(
                masterProperties.getMaxPoolPreparedStatementPerConnectionSize());
        dds.setFilters(masterProperties.getFilters());
        return dds;
    }
    @Bean(name = DB_SLAVE, initMethod = "init", destroyMethod = "close")
    public DataSource dataSourceSlave(DruidSlaveProperties slaveProperties) throws SQLException {
        logger.debug("slave properties: {}", slaveProperties.toString());
        DruidDataSource dds = new DruidDataSource();
        dds.setDriverClassName(slaveProperties.getDriverClassName());
        dds.setUrl(slaveProperties.getUrl());
        dds.setUsername(slaveProperties.getUsername());
        dds.setPassword(slaveProperties.getPassword());
        dds.setInitialSize(slaveProperties.getInitialSize());
        dds.setMinIdle(slaveProperties.getMinIdle());
        dds.setMaxActive(slaveProperties.getMaxActive());
        dds.setMaxWait(slaveProperties.getMaxWait());
        dds.setTimeBetweenEvictionRunsMillis(slaveProperties.getTimeBetweenEvictionRunsMillis());
        dds.setMinEvictableIdleTimeMillis(slaveProperties.getMinEvictableIdleTimeMillis());
        dds.setValidationQuery(slaveProperties.getValidationQuery());
        dds.setTestOnBorrow(slaveProperties.isTestOnBorrow());
        dds.setTestWhileIdle(slaveProperties.isTestWhileIdle());
        dds.setTestOnReturn(slaveProperties.isTestOnReturn());
        dds.setPoolPreparedStatements(slaveProperties.isPoolPreparedStatements());
        dds.setMaxPoolPreparedStatementPerConnectionSize(
                slaveProperties.getMaxPoolPreparedStatementPerConnectionSize());
        dds.setFilters(slaveProperties.getFilters());
        return dds;
    }
    @Bean
    public ServletRegistrationBean druidServletRegistrationBean(EnvConfig env) {
        String username = env.getStringValue(DSConfig.DRUID_MONITOR_USERNAME);
        String password = env.getStringValue(DSConfig.DRUID_MONITOR_PASSWORD);
        return new ServletRegistrationBean(new DruidStatViewServlet(username, password),
                DSConfig.DRUID_MONITOR_URL);
    }
    @Bean
    public FilterRegistrationBean druidFilterRegistrationBean() {
        WebStatFilter wsf = new WebStatFilter();
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(wsf);
        filterRegistrationBean.setUrlPatterns(Arrays.asList(DSConfig.DRUID_FILTER_URL));
        filterRegistrationBean.setInitParameters(
                Collections.singletonMap("exclusions", DSConfig.DRUID_FILTER_EXCLUSIONS));
        return filterRegistrationBean;
    }
}

根据类路径下有DruidDataSource这个类即有Druid这个jar包和配置文件中spring.datasource.active=druid才开启对Druid连接池的自动配置。

导入的配置文件:

@Configuration
@ComponentScan(basePackages = "com.example.common.config.properties")
public class PropertiesConfig {
}

DruidMasterProperties、DruidSlaveProperties属性文件读取的配置省略。

连接池监控配置类:

public class DruidStatViewServlet extends StatViewServlet {
    private static final long serialVersionUID = 1L;
    private String username;
    private String password;
    @Override
    public String getInitParameter(String name) {
        if ("loginUsername".equals(name)) {
            return username;
        }
        if ("loginPassword".equals(name)) {
            return password;
        }
        return super.getInitParameter(name);
    }
    public DruidStatViewServlet(String username, String password) {
        super();
        this.username = username;
        this.password = password;
    }
    public String getUsername() {
        return username;
    }
    public String getPassword() {
        return password;
    }
}

在META-INF/spring.factories中加入Druid自动配置映射:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.common.config.ds.DruidAutoConfig

切换数据源

切换数据源注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DS {
    String value() default DSConfig.DB_MASTER;
}

动态数据源类:

public class DynamicDataSource extends AbstractRoutingDataSource {
    private final Logger logger = LoggerUtils.getLogger(this);
    @Override
    protected Object determineCurrentLookupKey() {
        logger.debug("当前数据源为{}", DataSourceContextHolder.getDS());
        return DataSourceContextHolder.getDS();
    }
}

动态数据源AOP实现类:

@Aspect
@Component
public class DynamicDataSourceAspect {
    @Before("@annotation(DS)")
    public void beforeSwitchDS(JoinPoint point) {
        Class<?> className = point.getTarget().getClass();
        String methodName = point.getSignature().getName();
        Class<?>[] argClass = ((MethodSignature) point.getSignature()).getParameterTypes();
        String dataSource = DataSourceContextHolder.DEFAULT_DS;
        try {
            Method method = className.getMethod(methodName, argClass);
            if (method.isAnnotationPresent(DS.class)) {
                DS annotation = method.getAnnotation(DS.class);
                dataSource = annotation.value();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        DataSourceContextHolder.setDS(dataSource);
    }
    @After("@annotation(DS)")
    public void afterSwitchDS(JoinPoint point) {
        DataSourceContextHolder.clearDS();
    }
}

绑定当前线程数据源类:

public class DataSourceContextHolder {
    public static final String DEFAULT_DS = DSConfig.DB_MASTER;
    private static final ThreadLocal<String> DS_HOLDER = new ThreadLocal<>();
    public static void setDS(String dbType) {
        DS_HOLDER.set(dbType);
    }
    public static String getDS() {
        return (DS_HOLDER.get());
    }
    public static void clearDS() {
        DS_HOLDER.remove();
    }
}
相关文章
|
27天前
|
数据可视化 Java BI
将 Spring 微服务与 BI 工具集成:最佳实践
本文探讨了 Spring 微服务与商业智能(BI)工具集成的潜力与实践。随着微服务架构和数据分析需求的增长,Spring Boot 和 Spring Cloud 提供了构建可扩展、弹性服务的框架,而 BI 工具则增强了数据可视化与实时分析能力。文章介绍了 Spring 微服务的核心概念、BI 工具在企业中的作用,并深入分析了两者集成带来的优势,如实时数据处理、个性化报告、数据聚合与安全保障。同时,文中还总结了集成过程中的最佳实践,包括事件驱动架构、集中配置管理、数据安全控制、模块化设计与持续优化策略,旨在帮助企业构建高效、智能的数据驱动系统。
将 Spring 微服务与 BI 工具集成:最佳实践
|
3月前
|
XML 人工智能 Java
Spring Boot集成Aviator实现参数校验
Aviator是一个高性能、轻量级的Java表达式求值引擎,适用于动态表达式计算。其特点包括支持多种运算符、函数调用、正则匹配、自动类型转换及嵌套变量访问,性能优异且依赖小。适用于规则引擎、公式计算和动态脚本控制等场景。本文介绍了如何结合Aviator与AOP实现参数校验,并附有代码示例和仓库链接。
178 0
|
3月前
|
安全 Java 数据库
第16课:Spring Boot中集成 Shiro
第16课:Spring Boot中集成 Shiro
570 0
|
3月前
|
消息中间件 存储 Java
第15课: Spring Boot中集成ActiveMQ
第15课: Spring Boot中集成ActiveMQ
341 0
|
4月前
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
458 0
|
29天前
|
监控 Cloud Native Java
Spring Integration 企业集成模式技术详解与实践指南
本文档全面介绍 Spring Integration 框架的核心概念、架构设计和实际应用。作为 Spring 生态系统中的企业集成解决方案,Spring Integration 基于著名的 Enterprise Integration Patterns(EIP)提供了轻量级的消息驱动架构。本文将深入探讨其消息通道、端点、过滤器、转换器等核心组件,以及如何构建可靠的企业集成解决方案。
99 0
|
3月前
|
Java 关系型数据库 数据库连接
Spring Boot项目集成MyBatis Plus操作PostgreSQL全解析
集成 Spring Boot、PostgreSQL 和 MyBatis Plus 的步骤与 MyBatis 类似,只不过在 MyBatis Plus 中提供了更多的便利功能,如自动生成 SQL、分页查询、Wrapper 查询等。
285 3
|
3月前
|
缓存 JSON 前端开发
第07课:Spring Boot集成Thymeleaf模板引擎
第07课:Spring Boot集成Thymeleaf模板引擎
406 0
第07课:Spring Boot集成Thymeleaf模板引擎
|
4月前
|
监控 安全 Java
Java 开发中基于 Spring Boot 3.2 框架集成 MQTT 5.0 协议实现消息推送与订阅功能的技术方案解析
本文介绍基于Spring Boot 3.2集成MQTT 5.0的消息推送与订阅技术方案,涵盖核心技术栈选型(Spring Boot、Eclipse Paho、HiveMQ)、项目搭建与配置、消息发布与订阅服务实现,以及在智能家居控制系统中的应用实例。同时,详细探讨了安全增强(TLS/SSL)、性能优化(异步处理与背压控制)、测试监控及生产环境部署方案,为构建高可用、高性能的消息通信系统提供全面指导。附资源下载链接:[https://pan.quark.cn/s/14fcf913bae6](https://pan.quark.cn/s/14fcf913bae6)。
592 0

热门文章

最新文章