SpringBoot集成多数据源(全网最详细教程之一)

SpringBoot集成多数据源

主从数据源的配置:
1:首先搭建一个SpringBoot的项目工程,这里就不在演示搭建。
2:mysql的数据库中准备两个数据库,db1和db2
3:如下指引,开始进行相关的项目配置

搭建一个SpringBoot的项目,完整的目录结构如下:

SpringBoot集成多数据源(全网最详细教程之一)_第1张图片
引入相关的依赖

<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>3.2.0</version>
		</dependency>
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
			<version>2.5.6</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.20</version>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

进行多数据源的配置
1:在目录下的config下创建:DataSourceConfigOne:主数据源配置类

package org.example.adminmanage.config;

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.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.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;

/**
 * @program: mry
 * @description: 多数据源的配置--主数据源
 * @author: 城南的夏
 * @create: 2020-12-19 18:50
 **/
@Configuration
@MapperScan(basePackages = "org.example.adminmanage.dao.db1",sqlSessionFactoryRef = "db1SqlSessionFactory")
public class DataSourceConfigOne {

    // 表示这个数据源是默认数据源, 这个注解必须要加,因为不加的话spring将分不清楚那个为主数据源(默认数据源)
    @Primary
    @Bean("db1DataSource")
    //读取application.yml中的配置参数映射成为一个对象
    @ConfigurationProperties(prefix = "spring.datasource.db1")
    public DataSource getDataSourceOne() {
        return DataSourceBuilder.create().build();
    }

    @Primary
    @Bean("db1SqlSessionFactory")
    public SqlSessionFactory db1SqlSessionFactory(@Qualifier("db1DataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        //db1的Mapper文件的位置
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:**/mapper1/*.xml"));
        return bean.getObject();
    }

    @Primary
    @Bean("db1SqlSessionTemplate")
    public SqlSessionTemplate db1SqlSessionTemplate(@Qualifier("db1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

2:在目录下的config下创建:DataSourceConfigTwo:主数据源配置类(参考图一的项目目录结构)

package org.example.adminmanage.config;

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.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;

/**
 * @program: mry
 * @description: 多数据源的配置--次数据源
 * @author: 城南的夏
 * @create: 2020-12-19 18:50
 **/
@Configuration
@MapperScan(basePackages = "org.example.adminmanage.dao.db2",sqlSessionFactoryRef = "db2SqlSessionFactory")
public class DataSourceConfigTwo {

    // 表示这个数据源是默认数据源, 这个注解必须要加,因为不加的话spring将分不清楚那个为主数据源(默认数据源)
    @Bean("db2DataSource")
    //读取application.yml中的配置参数映射成为一个对象
    @ConfigurationProperties(prefix = "spring.datasource.db2")
    public DataSource getDataSourceOne() {
        return DataSourceBuilder.create().build();
    }

    @Bean("db2SqlSessionFactory")
    public SqlSessionFactory db2SqlSessionFactory(@Qualifier("db2DataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        //db1的Mapper文件的位置
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:**/mapper2/*.xml"));
        return bean.getObject();
    }

    @Bean("db2SqlSessionTemplate")
    public SqlSessionTemplate db2SqlSessionTemplate(@Qualifier("db2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

建目录dao层 —(参考图一的项目目录结构)
db1:代码结构

package org.example.adminmanage.dao.db1;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.example.adminmanage.entity.One;

import java.util.List;

/**
 * (One)表数据库访问层
 *
 * @author makejava
 * @since 2020-12-19 19:47:49
 */
public interface OneDao extends BaseMapper<One> {

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    One queryById(Integer id);

    /**
     * 查询指定行数据
     *
     * @param offset 查询起始位置
     * @param limit 查询条数
     * @return 对象列表
     */
    List<One> queryAllByLimit(@Param("offset") int offset, @Param("limit") int limit);


    /**
     * 通过实体作为筛选条件查询
     *
     * @param one 实例对象
     * @return 对象列表
     */
    List<One> queryAll(One one);

    /**
     * 新增数据
     *
     * @param one 实例对象
     * @return 影响行数
     */
    int insert(One one);

    /**
     * 修改数据
     *
     * @param one 实例对象
     * @return 影响行数
     */
    int update(One one);

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 影响行数
     */
    int deleteById(Integer id);


    List<One> query();
}

db2:代码结构 ----(参考图一的项目目录结构)

package org.example.adminmanage.dao.db2;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.example.adminmanage.entity.Two;

import java.util.List;

/**
 * (Two)表数据库访问层
 *
 * @author makejava
 * @since 2020-12-19 19:41:33
 */
//@DS("db2")
public interface TwoDao extends BaseMapper<Two> {

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    Two queryById(Integer id);

    /**
     * 查询指定行数据
     *
     * @param offset 查询起始位置
     * @param limit 查询条数
     * @return 对象列表
     */
    List<Two> queryAllByLimit(@Param("offset") int offset, @Param("limit") int limit);


    /**
     * 通过实体作为筛选条件查询
     *
     * @param two 实例对象
     * @return 对象列表
     */
    List<Two> queryAll(Two two);

    /**
     * 新增数据
     *
     * @param two 实例对象
     * @return 影响行数
     */
    int insert(Two two);

    /**
     * 修改数据
     *
     * @param two 实例对象
     * @return 影响行数
     */
    int update(Two two);

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 影响行数
     */
    int deleteById(Integer id);

    List<Two> query();
}

新建 entity 目录 ----(参考图一的项目目录结构)
One 实体类

package org.example.adminmanage.entity;

import java.io.Serializable;

/**
 * (One)实体类
 *
 * @author makejava
 * @since 2020-12-19 19:47:49
 */
public class One implements Serializable {
    private static final long serialVersionUID = 959029700988159827L;
    
    private Integer id;
    
    private String name;


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

}

Two 实体

package org.example.adminmanage.entity;

import java.io.Serializable;

/**
 * (Two)实体类
 *
 * @author makejava
 * @since 2020-12-19 19:41:33
 */
public class Two implements Serializable {
    private static final long serialVersionUID = 725826958790784302L;
    
    private Integer id;
    
    private String address;


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

}

新建目录service层 ----(参考图一的项目目录结构)

package org.example.adminmanage.service;

import com.baomidou.mybatisplus.extension.service.IService;
import org.example.adminmanage.entity.One;
import java.util.List;

/**
 * (One)表服务接口
 *
 * @author makejava
 * @since 2020-12-19 19:47:49
 */
public interface OneService extends IService<One> {

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    One queryById(Integer id);

    /**
     * 查询多条数据
     *
     * @param offset 查询起始位置
     * @param limit 查询条数
     * @return 对象列表
     */
    List<One> queryAllByLimit(int offset, int limit);

    /**
     * 新增数据
     *
     * @param one 实例对象
     * @return 实例对象
     */
    One insert(One one);

    /**
     * 修改数据
     *
     * @param one 实例对象
     * @return 实例对象
     */
    One update(One one);

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    boolean deleteById(Integer id);


    List<One> queryAll();

}
package org.example.adminmanage.service;

import org.example.adminmanage.entity.Two;
import java.util.List;

/**
 * (Two)表服务接口
 *
 * @author makejava
 * @since 2020-12-19 19:41:33
 */
public interface TwoService {

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    Two queryById(Integer id);

    /**
     * 查询多条数据
     *
     * @param offset 查询起始位置
     * @param limit 查询条数
     * @return 对象列表
     */
    List<Two> queryAllByLimit(int offset, int limit);

    /**
     * 新增数据
     *
     * @param two 实例对象
     * @return 实例对象
     */
    Two insert(Two two);

    /**
     * 修改数据
     *
     * @param two 实例对象
     * @return 实例对象
     */
    Two update(Two two);

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    boolean deleteById(Integer id);

    List<Two> queryAll();
}
package org.example.adminmanage.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.example.adminmanage.entity.One;
import org.example.adminmanage.dao.db1.OneDao;
import org.example.adminmanage.service.OneService;
import org.springframework.stereotype.Service;

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

/**
 * (One)表服务实现类
 *
 * @author makejava
 * @since 2020-12-19 19:47:49
 */
@Service("oneService")
public class OneServiceImpl extends ServiceImpl<OneDao, One> implements OneService {
    @Resource
    private OneDao oneDao;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public One queryById(Integer id) {
        return this.oneDao.queryById(id);
    }

    /**
     * 查询多条数据
     *
     * @param offset 查询起始位置
     * @param limit 查询条数
     * @return 对象列表
     */
    @Override
    public List<One> queryAllByLimit(int offset, int limit) {
        return this.oneDao.queryAllByLimit(offset, limit);
    }

    /**
     * 新增数据
     *
     * @param one 实例对象
     * @return 实例对象
     */
    @Override
    public One insert(One one) {
        this.oneDao.insert(one);
        return one;
    }

    /**
     * 修改数据
     *
     * @param one 实例对象
     * @return 实例对象
     */
    @Override
    public One update(One one) {
        this.oneDao.update(one);
        return this.queryById(one.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer id) {
        return this.oneDao.deleteById(id) > 0;
    }

    @Override
    public List<One> queryAll() {
        return oneDao.query();
    }
}
package org.example.adminmanage.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import org.apache.ibatis.annotations.Select;
import org.example.adminmanage.entity.Two;
import org.example.adminmanage.dao.db2.TwoDao;
import org.example.adminmanage.service.TwoService;
import org.springframework.stereotype.Service;

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

/**
 * (Two)表服务实现类
 *
 * @author makejava
 * @since 2020-12-19 19:41:33
 */
@Service("twoService")
public class TwoServiceImpl implements TwoService {
    @Resource
    private TwoDao twoDao;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public Two queryById(Integer id) {
        return this.twoDao.queryById(id);
    }

    /**
     * 查询多条数据
     *
     * @param offset 查询起始位置
     * @param limit 查询条数
     * @return 对象列表
     */
    @Override
    public List<Two> queryAllByLimit(int offset, int limit) {
        return this.twoDao.queryAllByLimit(offset, limit);
    }

    /**
     * 新增数据
     *
     * @param two 实例对象
     * @return 实例对象
     */
    @Override
    public Two insert(Two two) {
        this.twoDao.insert(two);
        return two;
    }

    /**
     * 修改数据
     *
     * @param two 实例对象
     * @return 实例对象
     */
    @Override
    public Two update(Two two) {
        this.twoDao.update(two);
        return this.queryById(two.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer id) {
        return this.twoDao.deleteById(id) > 0;
    }

    @Override
    @DS("db2")
    @Select("select * from two")
    public List<Two> queryAll() {
        return twoDao.query();
    }
}

mapper文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.adminmanage.dao.db1.OneDao">

    <resultMap id="BaseResultMap" type="org.example.adminmanage.entity.One">
        <!--@Table one-->
        <result property="id" column="id" jdbcType="INTEGER"/>
        <result property="name" column="name" jdbcType="VARCHAR"/>
    </resultMap>

    <!--查询单个-->
    <select id="queryById" resultMap="BaseResultMap">
        select
          id, name
        from one
        where id = #{id}
    </select>

    <!--查询指定行数据-->
    <select id="queryAllByLimit" resultMap="BaseResultMap">
        select
          id, name
        from one
        limit #{offset}, #{limit}
    </select>

    <!--通过实体作为筛选条件查询-->
    <select id="queryAll" resultMap="BaseResultMap">
        select
          id, name
        from one
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="name != null and name != ''">
                and name = #{name}
            </if>
        </where>
    </select>
    <select id="query" resultType="org.example.adminmanage.entity.One">
        select * from one;
    </select>

    <!--新增所有列-->
    <insert id="insert" keyProperty="id" useGeneratedKeys="true">
        insert into one(name)
        values (#{name})
    </insert>

    <!--通过主键修改数据-->
    <update id="update">
        update one
        <set>
            <if test="name != null and name != ''">
                name = #{name},
            </if>
        </set>
        where id = #{id}
    </update>

    <!--通过主键删除-->
    <delete id="deleteById">
        delete from one where id = #{id}
    </delete>

</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.adminmanage.dao.db2.TwoDao">

    <resultMap id="BaseResultMap" type="org.example.adminmanage.entity.Two">
        <!--@Table two-->
        <result property="id" column="id" jdbcType="INTEGER"/>
        <result property="address" column="address" jdbcType="VARCHAR"/>
    </resultMap>

    <!--查询单个-->
    <select id="queryById" resultMap="BaseResultMap">
        select
          id, address
        from two
        where id = #{id}
    </select>

    <!--查询指定行数据-->
    <select id="queryAllByLimit" resultMap="BaseResultMap">
        select
          id, address
        from two
        limit #{offset}, #{limit}
    </select>

    <!--通过实体作为筛选条件查询-->
    <select id="queryAll" resultMap="BaseResultMap">
        select
          id, address
        from two
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="address != null and address != ''">
                and address = #{address}
            </if>
        </where>
    </select>
    <select id="query" resultType="org.example.adminmanage.entity.Two">
        select * from two
    </select>

    <!--新增所有列-->
    <insert id="insert" keyProperty="id" useGeneratedKeys="true">
        insert into two(address)
        values (#{address})
    </insert>

    <!--通过主键修改数据-->
    <update id="update">
        update two
        <set>
            <if test="address != null and address != ''">
                address = #{address},
            </if>
        </set>
        where id = #{id}
    </update>

    <!--通过主键删除-->
    <delete id="deleteById">
        delete from two where id = #{id}
    </delete>

</mapper>

controller层目录代码

package org.example.adminmanage.controller;

import org.example.adminmanage.entity.One;
import org.example.adminmanage.service.OneService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

/**
 * (One)表控制层
 *
 * @author makejava
 * @since 2020-12-19 19:47:49
 */
@RestController
@RequestMapping("one")
public class OneController {
    /**
     * 服务对象
     */
    @Resource
    private OneService oneService;

    /**
     * 通过主键查询单条数据
     *
     * @param id 主键
     * @return 单条数据
     */
    @GetMapping("selectOne")
    public One selectOne(Integer id) {
        return this.oneService.queryById(id);
    }

    @GetMapping("queryOne")
    public List<One> query() {
        return oneService.queryAll();
    }
}
package org.example.adminmanage.controller;

import org.example.adminmanage.entity.Two;
import org.example.adminmanage.service.TwoService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

/**
 * (Two)表控制层
 *
 * @author makejava
 * @since 2020-12-19 19:41:33
 */
@RestController
@RequestMapping("two")
public class TwoController {
    /**
     * 服务对象
     */
    @Resource
    private TwoService twoService;

    /**
     * 通过主键查询单条数据
     *
     * @param id 主键
     * @return 单条数据
     */
    @GetMapping("selectOne")
    public Two selectOne(Integer id) {
        return this.twoService.queryById(id);
    }

    @GetMapping("queryTwo")
    public List<Two> query() {
        return twoService.queryAll();
    }
}

接下来就是yml配置文件中的配置了

server:
  port: 8080
spring:
  datasource:
    db1:
      jdbc-url: jdbc:mysql://localhost:3306/db1?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=GMT%2B8
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver
    db2:
      jdbc-url: jdbc:mysql://localhost:3306/db2?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=GMT%2B8
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver
      durid:
        initial-size: 1
        max-active: 20
        min-idle: 1
        max-wait: 60000
      autoconfigure:
        exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure

以及入口类的配置

SpringBoot集成多数据源(全网最详细教程之一)_第2张图片

DruidDataSourceAutoConfigure会注入一个DataSourceWrapper,其会在原生的spring.datasource下找 url, username, password 等。动态数据源 URL 等配置是在 dynamic 下,因此需要排除,否则会报错。排除方式有两种,一种是上述配置文件排除,还有一种可以在项目启动类排除:

package org.example.adminmanage;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//在入口类的注解上添加如下的参数配置
@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
public class AdminManageApplication {

	public static void main(String[] args) {
		SpringApplication.run(AdminManageApplication.class, args);
	}

}

给使用非默认数据源添加注解@DS
@DS 可以注解在方法上和类上,同时存在方法注解优先于类上注解。
注解在 service 实现或 mapper 接口方法上,不要同时在 service 和 mapper 注解。

SpringBoot集成多数据源(全网最详细教程之一)_第3张图片

这样就完成多数据源的配置了。大家有问题的在下方留言。

你可能感兴趣的:(Spring模块,mybatis,mysql,spring,boot)