Spring配置多数据源

时间:2020-07-17 09:19:46   收藏:0   阅读:72

环境背景

这里以配置两个mysql数据库为展示用例。持久层使用mybatis实现。两个连接分别使用不同的连接池 druid 和 hikari

相关知识

这里介绍了一些相关的知识点,清楚后可以跳过

mybatis和mybatis-spring-boot-starter的关系

在pom依赖上它们是两个不同的依赖文件。

<dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>1.3.2</version>
</dependency>

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>

mybatis-spring-boot-starter类似一个中间件,链接Springboot和mybatis,构建基于Springboot的mybatis应用程序。同时mybatis-spring-boot-starter作为一个集成包是包含mybatis的。

mybatis-spring-boot-starter和spring-boot-starter-jdbc

mybatis-spring-boot-starter作为一个集成包,如果在项目里引入了该依赖那就不需要在显示的依赖spring-boot-starter-jdbc,因为mybatis-spring-boot-starter是包含spring-boot-starter-jdbc的。

mybatis-spring-boot-starter的集成

<?xml version="1.0" encoding="UTF-8"?>
<!--

       Copyright 2015-2018 the original author or authors.

       Licensed under the Apache License, Version 2.0 (the "License");
       you may not use this file except in compliance with the License.
       You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

       Unless required by applicable law or agreed to in writing, software
       distributed under the License is distributed on an "AS IS" BASIS,
       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       See the License for the specific language governing permissions and
       limitations under the License.

-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot</artifactId>
    <version>1.3.2</version>
  </parent>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <name>mybatis-spring-boot-starter</name>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-autoconfigure</artifactId>
    </dependency>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
    </dependency>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
    </dependency>
  </dependencies>
</project>

作为一个集成包,可以看到包含了mybatis、mybatis-spring、spring-boot-starter-jdbc。

Spring自动装配的相关注解

@Autowired

@Qualifire

    /**
     * 得到数据源
     * 定义一个名字为barDataSource的数据源
     *
     * @return
     */
    @Bean("barDataSource")
    public DataSource barDataSource() {
        DataSourceProperties dataSourceProperties = barDataSourceProperties();
        log.info("bar datasource url:{}", dataSourceProperties.getUrl());
        log.info("{}", dataSourceProperties.getType().getName());
        return dataSourceProperties.initializeDataSourceBuilder().build();
    }

    /**
     * 定义一个名字为 barSqlSessionFactory 的SqlSession工厂,实现的时候使用名字为barDataSource的数据源去实现
     * @param dataSource
     * @return
     * @throws Exception
     */
    @Bean("barSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("barDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCATION));
        return bean.getObject();
    }

@Primary

@Resource

@ConfigurationProperties和@PropertySource

@ConfigurationProperties和@PropertySource都是用来读取Spring的配置文件的,有三种配置方式

第一种

技术图片技术图片

package com.lucky.spring.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

/**
 * Created by zhangdd on 2020/7/16
 */
@PropertySource(value = "book.properties",encoding = "utf-8")
@ConfigurationProperties(prefix = "book")
@Component
public class BookConfig {
    private String name;
    private String price;
    private String version;

    public String getName() {
        return name;
    }

    public String getPrice() {
        return price;
    }

    public String getVersion() {
        return version;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public void setVersion(String version) {
        this.version = version;
    }
}

测试用例

@RestController
public class BookController {

    @Autowired
    BookConfig bookConfig;

    @GetMapping("/api/queryBook")
    public String queryBook() {
        StringBuilder builder = new StringBuilder();
        StringBuilder bookInfo = builder.append(bookConfig.getName())
                .append(",")
                .append(bookConfig.getPrice())
                .append(",")
                .append(bookConfig.getVersion());
        return bookInfo.toString();
    }
}

第二种

技术图片技术图片

person.name=张三
person.age=18
    
package com.lucky.spring.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

/**
 * Created by zhangdd on 2020/7/16
 */
@Component
@PropertySource(value = "classpath:config/person.properties",encoding = "utf-8")
@ConfigurationProperties(prefix = "person")
public class PersonConfig {
    private String name;
    private String age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

测试用例

public class PersonController {

    @Autowired
    PersonConfig personConfig;

    @GetMapping("/api/queryPersonInfo")
    public String queryPersonInfo() {
        StringBuilder builder = new StringBuilder();
        builder.append(personConfig.getName())
                .append(",")
                .append(personConfig.getAge());
        return builder.toString();
    }
}
第三种

技术图片
技术图片

car:
  price: 12345678
  name: 奥迪
 
 package com.lucky.spring.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * Created by zhangdd on 2020/7/16
 */
@Component
@ConfigurationProperties(prefix = "car")
public class CarConfig {

    private String price;
    private String name;

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

测试用例

package com.lucky.spring.controller;

import com.lucky.spring.config.CarConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created by zhangdd on 2020/7/16
 */
@RestController
public class CarController {

    @Autowired
    CarConfig carConfig;

    @GetMapping("/api/queryCarInfo")
    public String queryCarInfo() {
        StringBuilder builder = new StringBuilder();
        builder.append(carConfig.getName())
                .append(",")
                .append(carConfig.getPrice());
        return builder.toString();
    }
}


多数据源配置使用

相关依赖配置

基于环境背景信息,mysql数据库,mybatis持久层,三方数据源druid。添加配置信息如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lucky</groupId>
    <artifactId>04spring-multi-datasource</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>8.0.17</version>
                        <scope>runtime</scope>
                    </dependency>
                </dependencies>
                <configuration>
                    <configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
                    <verbose>true</verbose>
                    <overwrite>true</overwrite>
                </configuration>
            </plugin>
        </plugins>

    </build>
    
</project>

连接信息配置

既然是多数据源的配置操作,那就是配置数据源信息了。配置方式有两种:

这里以配置文件中为例说明。

datasource:
  foo:
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://localhost:3306/readinglist?characterEncoding=utf8&useSSL=false
    username: root
    password: 12345678
  bar:
    type: com.zaxxer.hikari.HikariDataSource
    url: jdbc:mysql://localhost:3306/shiro?characterEncoding=utf8&useSSL=false
    username: root
    password: 12345678

使用配置信息

已经对信息进行了配置,下面就是对配置信息的使用了。

foo数据源的配置

package com.lucky.spring.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
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 org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

/**
 * Created by zhangdd on 2020/7/13
 */
@Configuration
@Slf4j
@MapperScan(basePackages = "com.lucky.spring.dao.foo", sqlSessionFactoryRef = "fooSqlSessionFactory")
public class FooDataSourceConfig {


    static final String MAPPER_LOCATION = "classpath:mapper/foo/*.xml";
    //=========foo 数据源相关配置 start==================================================


    @Bean
    @Primary// 该注解是指当有多个相同的bean时,优先使用用@Primary注解的bean
    @ConfigurationProperties("datasource.foo")
    public DataSourceProperties fooDataSourceProperties() {
        return new DataSourceProperties();
    }

    /**
     * 返回 foo 对应的数据源
     *
     * @return
     */
    @Bean("fooDataSource")
    @Primary
    public DataSource fooDataSource() {
        DataSourceProperties dataSourceProperties = fooDataSourceProperties();
        log.info("foo datasource url:{}", dataSourceProperties.getUrl());
        log.info("{}", dataSourceProperties.getType().getName());
        return dataSourceProperties.initializeDataSourceBuilder().build();
    }


    /**
     * 返回foo 对应数据库的会话工厂
     *
     * @param ds
     * @return
     */
    @Bean(name = "fooSqlSessionFactory")
    @Primary
    public SqlSessionFactory sqlSessionFactory(@Qualifier("fooDataSource") DataSource ds) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(ds);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCATION));
        return bean.getObject();
    }

    /**
     * foo 对应的数据库会话模版
     *
     * @param sessionFactory
     * @return
     */
    @Bean("fooSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("fooSqlSessionFactory") SqlSessionFactory sessionFactory) {
        log.info("sessionFactory:{}", sessionFactory.toString());
        return new SqlSessionTemplate(sessionFactory);
    }

    /**
     * 返回 foo 对应的数据库事务
     *
     * @param fooDatasource
     * @return
     */
    @Bean
    @Primary
    public DataSourceTransactionManager fooTxManager(@Qualifier("fooDataSource") DataSource fooDatasource) {
        return new DataSourceTransactionManager(fooDatasource);
    }

    //=========foo 数据源相关配置 end==================================================


}

建议将需要的都创建好,这样方便做一些优化,比如超时时间、最大连接数、事务的处理方式

bar数据源的配置

bar数据源的配置和foo的模式是一样的,代码如下:

package com.lucky.spring.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.annotation.Resource;
import javax.sql.DataSource;

/**
 * Created by zhangdd on 2020/7/13
 */
@Configuration
@Slf4j
@MapperScan(basePackages = "com.lucky.spring.dao.bar", sqlSessionFactoryRef = "barSqlSessionFactory")
public class BarDataSourceConfig {

    static final String MAPPER_LOCATION = "classpath:mapper/bar/*.xml";

    //=========bar 数据源相关配置 start==================================================

    @Bean
    @ConfigurationProperties("datasource.bar")
    public DataSourceProperties barDataSourceProperties() {
        return new DataSourceProperties();
    }

    /**
     * 得到数据源
     *
     * @return
     */
    @Bean("barDataSource")
    public DataSource barDataSource() {
        DataSourceProperties dataSourceProperties = barDataSourceProperties();
        log.info("bar datasource url:{}", dataSourceProperties.getUrl());
        log.info("{}", dataSourceProperties.getType().getName());
        return dataSourceProperties.initializeDataSourceBuilder().build();
    }

    /**
     *
     * @param dataSource
     * @return
     * @throws Exception
     */
    @Bean("barSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("barDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCATION));
        return bean.getObject();
    }


    /**
     * bar 对应的数据库会话模版
     *
     * @param sessionFactory
     * @return
     */
    @Bean("barSqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("barSqlSessionFactory") SqlSessionFactory sessionFactory) {
        return new SqlSessionTemplate(sessionFactory);
    }


    @Bean
    @Resource
    public DataSourceTransactionManager barTxManager(@Qualifier("barDataSource") DataSource barDatasource) {
        return new DataSourceTransactionManager(barDatasource);
    }

    //=========bar 数据源相关配置 end==================================================

}

测试场景

两个数据源foo和bar连接的数据库分别是readinglist和shiro,分别以readinglist数据库例的foo表和tpermission表为例。
技术图片

@RestController
public class MultiDataController {

    @Autowired
    TPermissionMapper permissionMapper;

    @Autowired
    FooMapper fooMapper;

    @GetMapping("/api/getData")
    public MultiDataVo getData() {
        List<TPermission> tPermissions = permissionMapper.queryList();
        List<Foo> foos = fooMapper.queryList();
        MultiDataVo dataVo = new MultiDataVo();
        dataVo.setFoos(foos);
        dataVo.setPermissions(tPermissions);
        return dataVo;
    }
}
package com.lucky.spring.vo;

import com.lucky.spring.model.bar.TPermission;
import com.lucky.spring.model.foo.Foo;
import lombok.Data;

import java.util.List;

/**
 * Created by zhangdd on 2020/7/14
 */
@Data
public class MultiDataVo {
    private List<TPermission> permissions;
    private List<Foo> foos;

}

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!