栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

详解Spring Boot + Mybatis 实现动态数据源

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

详解Spring Boot + Mybatis 实现动态数据源

动态数据源

在很多具体应用场景的时候,我们需要用到动态数据源的情况,比如多租户的场景,系统登录时需要根据用户信息切换到用户对应的数据库。又比如业务A要访问A数据库,业务B要访问B数据库等,都可以使用动态数据源方案进行解决。接下来,我们就来讲解如何实现动态数据源,以及在过程中剖析动态数据源背后的实现原理。

实现案例

本教程案例基于 Spring Boot + Mybatis + MySQL 实现。

数据库设计

首先需要安装好MySQL数据库,新建数据库 example,创建example表,用来测试数据源,SQL脚本如下:

CREATE TABLE `example` (
 `pk` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
 `message` varchar(100) NOT NULL,
 `create_time` datetime NOT NULL COMMENT '创建时间',
 `modify_time` datetime DEFAULT NULL COMMENT '生效时间',
 PRIMARY KEY (`pk`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='测试用例表'

添加依赖

添加Spring Boot,Spring Aop,Mybatis,MySQL相关依赖。

pom.xml


   org.springframework.boot
   spring-boot-starter-web
  
  
   org.springframework.boot
   spring-boot-starter-test
   test
  
  
   org.mybatis.spring.boot
   mybatis-spring-boot-starter
   1.3.1
  
  
  
   org.springframework.boot
   spring-boot-starter-aop
  
  
   mysql
   mysql-connector-java
   5.1.8
  

自定义配置文件

新建自定义配置文件resource/config/mysql/db.properties,添加数据源:

#数据库设置
spring.datasource.example.jdbc-url=jdbc:mysql://localhost:3306/example?characterEncoding=UTF-8
spring.datasource.example.username=root
spring.datasource.example.password=123456
spring.datasource.example.driver-class-name=com.mysql.jdbc.Driver

启动类

启动类添加 exclude = {DataSourceAutoConfiguration.class}, 以禁用数据源默认自动配置。

数据源默认自动配置会读取 spring.datasource.* 的属性创建数据源,所以要禁用以进行定制。

DynamicDatasourceApplication.java:

package com.main.example.dynamic.datasource;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

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

}

数据源配置类

创建一个数据源配置类,主要做以下几件事情:

1. 配置 dao,model(bean),xml mapper文件的扫描路径。

2. 注入数据源配置属性,创建数据源。

3. 创建一个动态数据源,装入数据源。

4. 将动态数据源设置到SQL会话工厂和事务管理器。

如此,当进行数据库操作时,就会通过我们创建的动态数据源去获取要操作的数据源了。

DbSourceConfig.java:

package com.main.example.config.dao;

import com.main.example.common.DataEnum;
import com.main.example.common.DynamicDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

//数据库配置统一在config/mysql/db.properties中
@Configuration
@PropertySource(value = "classpath:config/mysql/db.properties")
public class DbSourceConfig {
  private String typeAliasesPackage = "com.main.example.bean.**.*";

  @Bean(name = "exampleDataSource")
  @ConfigurationProperties(prefix = "spring.datasource.example")
  public DataSource exampleDataSource() {
    return DataSourceBuilder.create().build();
  }

  
  @Bean(name = "dynamicDataSource")
  public DataSource dynamicDataSource() {
    DynamicDataSource dynamicDataSource = new DynamicDataSource();
    //配置多数据源
    Map dbMap = new HashMap();
    dbMap.put(DataEnum.DbSource.example.getName(), exampleDataSource());
    dynamicDataSource.setTargetDataSources(dbMap);

    // 设置默认数据源
    dynamicDataSource.setDefaultTargetDataSource(exampleDataSource());

    return dynamicDataSource;
  }

  
  @Bean(name = "sqlSessionFactory")
  public SqlSessionFactoryBean sqlSessionFactory() throws Exception {
    SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
    sqlSessionFactory.setDataSource(dynamicDataSource());
    sqlSessionFactory.setTypeAliasesPackage(typeAliasesPackage); //扫描bean
    PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    sqlSessionFactory.setMapperLocations(resolver.getResources("classpath*:mapper
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@documented
public @interface DbSource {
  
  String value();
}

创建一个AOP切面,拦截带 @DataSource 注解的方法,在方法执行前切换至目标数据源,执行完成后恢复到默认数据源。

DynamicDataSourceAspect.java:

package com.main.example.config.dao;

import com.main.example.common.DbSourceContext;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;


@Aspect
@Order(-1) // 该切面应当先于 @Transactional 执行
@Component
public class DynamicDataSourceAspect {
  private static Logger logger = Logger.getLogger(DynamicDataSourceAspect.class);
  
  //@Before("@annotation(dbSource)") 注解在对应方法,拦截有@DbSource的方法
  //注解在类对象,拦截有@DbSource类下所有的方法
  @Before("@within(dbSource)")
  public void switchDataSource(JoinPoint point, DbSource dbSource) {
      // 切换数据源
      DbSourceContext.setDbSource(dbSource.value());
  }

  
  //注解在类对象,拦截有@DbSource类下所有的方法
  @After("@within(dbSource)")
  public void restoreDataSource(JoinPoint point, DbSource dbSource) {
    // 将数据源置为默认数据源
    DbSourceContext.clearDbSource();
  }
}

到这里,动态数据源相关的处理代码就完成了。

编写用户业务代码

接下来编写用户查询业务代码,用来进行测试,Dao层只需添加一个查询接口即可。

ExampleDao.java:

package com.main.example.dao;

import com.main.example.common.DataEnum;
import com.main.example.config.dao.DbSource;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

@Component("exampleDao")
//切换数据源注解,以DataEnum.DbSource中的值为准
@DbSource("example")
public class ExampleDao extends Daobase {
  private static final String MAPPER_NAME_SPACE = "com.main.example.dao.ExampleMapper";

  public List selectAllMessages() {
    return selectList(MAPPER_NAME_SPACE, "selectAllMessages");
  }
}

Controler代码:

TestExampleDao.java:

package com.main.example.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
public class TestExampleDao {
  @Autowired
  ExampleDao exampleDao;

  @RequestMapping(value = "/test/example")
  public List selectAllMessages() {
    try {
      List ldata = exampleDao.selectAllMessages();
      if(ldata == null){System.out.println("*********it is null.***********");return null;}
      for(String d : ldata) {
 System.out.println(d);
      }
      return ldata;
    }catch(Exception e) {
      e.printStackTrace();
    }

    return new ArrayList<>();
  }
}

ExampleMapper.xml代码:




  

测试效果

启动系统,访问 http://localhost:80/test/example">http://localhost:80/test/example,分别测试两个接口,成功返回数据。

 

可能遇到的问题

1.报错:java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName

 

原因:

spring boot从1.X升级到2.X版本之后,一些配置及用法有了变化,如果不小心就会碰到“jdbcUrl is required with driverClassName.”的错误

解决方法:

在1.0 配置数据源的过程中主要是写成:spring.datasource.url 和spring.datasource.driverClassName。

而在2.0升级之后需要变更成:spring.datasource.jdbc-url和spring.datasource.driver-class-name即可解决!

 2.自定义配置文件

自定义配置文件需要在指定配置类上加上@PropertySource标签,例如:

@PropertySource(value = "classpath:config/mysql/db.properties")

若是作用于配置类中的方法,则在方法上加上@ConfigurationProperties,例如:

@ConfigurationProperties(prefix = "spring.datasource.example")

配置项前缀为spring.datasource.example

若是作用于配置类上,则在类上加上@ConfigurationProperties(同上),并且在启动类上加上@EnableConfigurationProperties(XXX.class)

3.多数据源

需要在启动类上取消自动装载数据源,如:

@SpringBootApplication(exclude = {
    DataSourceAutoConfiguration.class
})

以上所述是小编给大家介绍的Spring Boot + Mybatis 实现动态数据源详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对考高分网网站的支持!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/138386.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号