Spring Boot从入门到精通(五)多数据源配置实现及源码分析

栏目: IT技术 · 发布时间: 4年前

内容简介:多数据源配置在项目软件中是比较常见的开发需求,Spring和Spring Boot中对此都有相应的解决方案可供大家参考。在Spring Boot中,如MyBatis、JdbcTemplate以及Jpa都可以配置多数据源。本文在前一篇“Spring Boot从入门到精通(四)连接MySQL数据库(附源码)”文章中项目源码的基础上,来实现Spring Boot集成MyBatis和使用JdbcTemplate两种方式配置多数据源。Spring Boot集成MyBatis和使用JdbcTemplate配置公共文件

多数据源配置在项目软件中是比较常见的开发需求,Spring和Spring Boot中对此都有相应的解决方案可供大家参考。在Spring Boot中,如MyBatis、JdbcTemplate以及Jpa都可以配置多数据源。

本文在前一篇“Spring Boot从入门到精通(四)连接 MySQL 数据库(附源码)”文章中项目源码的基础上,来实现Spring Boot集成MyBatis和使用JdbcTemplate两种方式配置多数据源。

Spring Boot集成MyBatis和使用JdbcTemplate配置公共文件

1、配置数据源application.properties文件

假定有两个数据源来配置实现,分别对应的名字是oneDataSource和twoDataSource。

在application.properties文件中配置数据源信息如下:

spring.datasource.one.url=jdbc:mysql://123.57.47.154:3306/springboot1
spring.datasource.one.username=root
spring.datasource.one.password=wangyoodb
spring.datasource.one.driverClassName=com.mysql.cj.jdbc.Driver

spring.datasource.two.url=jdbc:mysql://123.57.47.154:3306/springboot2
spring.datasource.two.username=root
spring.datasource.two.password=wangyoodb
spring.datasource.two.driverClassName=com.mysql.cj.jdbc.Driver

2、数据源配置 java 类文件

通过上一步操作,利用关键词one和two对数据源进行区分,只是简单增加这些信息是无法被Spring Boot自动加载的,需要增加代码来实现加载DataSource,下面小编手动配置DataSourceConfig,用来提供DataSource Bean。

数据源一:新增命名DataSourceOneConfig的java类文件,具体代码如下:

package com.yoodb.study.demo03.datasource;

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;

@Configuration
@MapperScan(basePackages = "com.yoodb.study.demo03.mapper.one", sqlSessionFactoryRef = "oneSqlSessionFactory")
public class DataSourceOneConfig {
    @Bean(name = "oneDataSource")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.one")
    public DataSource getDateSourceOne() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "oneSqlSessionFactory")
    @Primary
    public SqlSessionFactory oneSqlSessionFactory(@Qualifier("oneDataSource") DataSource datasource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(datasource);
        bean.setMapperLocations(
                new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/one/*.xml"));
        return bean.getObject();
    }
    //
    @Bean("oneSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate onesqlsessiontemplate(
            @Qualifier("oneSqlSessionFactory") SqlSessionFactory sessionfactory) {
        return new SqlSessionTemplate(sessionfactory);
    }
}

数据源二:新增命名DataSourceTwoConfig的java类文件,具体代码如下:

package com.yoodb.study.demo03.datasource;

import com.zaxxer.hikari.HikariDataSource;
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.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;

@Configuration
@MapperScan(basePackages = "com.yoodb.study.demo03.mapper.two", sqlSessionFactoryRef = "twoSqlSessionFactory")
public class DataSourceTwoConfig {
    @Bean(name = "twoDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.two")
    public DataSource getDateSourceTwo(DataSourceProperties properties) {
        return DataSourceBuilder.create(properties.getClassLoader())
                .type(HikariDataSource.class)
                .driverClassName(properties.determineDriverClassName())
                .url(properties.determineUrl())
                .username(properties.determineUsername())
                .password(properties.determinePassword())
                .build();
    }
    @Bean(name = "twoSqlSessionFactory")
    public SqlSessionFactory twoSqlSessionFactory(@Qualifier("twoDataSource") DataSource datasource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(datasource);
        bean.setMapperLocations(
                new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/two/*.xml"));
        return bean.getObject();
    }
    @Bean("twoSqlSessionTemplate")
    public SqlSessionTemplate twosqlsessiontemplate(
            @Qualifier("twoSqlSessionFactory") SqlSessionFactory sessionfactory) {
        return new SqlSessionTemplate(sessionfactory);
    }
}

在上述代码中使用的注解含义可以参考之前写过“Spring Boot从入门到精通(三)常用注解含义及用法分析总结”的文章(见微信公众号“Java精选”),具体使用注解含义如下:

@Configuration

用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。

@MapperScan

指定要扫描mapper类包的路径,配置mybatis的接口存放位置。

@Bean

用于告诉方法产生一个Bean对象,然后这个Bean对象交给Spring管理。

@ConfigurationProperties

是Spring Boot提供的类型安全的属性绑定,以第一个Bean为例,@ConfigurationProperties(prefix = “spring.datasource.one”)表示使用spring.datasource.one前缀的数据库配置去创建一个DataSource。

@Primary

可以理解为默认优先选择,不可以同时设置多个,必须增加此注解用于区分主数据库(默认数据库)。

@Qualifier

来达到注入某个特指bean的作用,表示查找Spring容器中指定名字的对象。

注意:

bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(“***”)) mapper的xml形式文件位置必须要配置,不然项目会报no statement错误信息。

3、实体类文件

新增实体类文件,两个数据源公用一个实体类,具体代码如下:

package com.yoodb.study.demo03.bean;

public class BootUser {
    private String id;
    private String name;
    private String detail;

    public String getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getDetail() {
        return detail;
    }

    public void setDetail(String detail) {
        this.detail = detail;
    }
}

集成Mybatis

1、新增mapper xml文件

数据源一:在src/main/resources/mapper/one(不存在文件加新建)创建BootUserOneMapper.xml文件,具体配置信息如下:

<?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="com.yoodb.study.demo03.mapper.one.BootUserOneMapper" >
    <resultMap id="BaseResultMap" type="com.yoodb.study.demo03.bean.BootUser" >
        <id column="id" property="id" jdbcType="VARCHAR" />
        <result column="user_name" property="name" jdbcType="VARCHAR" />
        <result column="detail" property="detail" jdbcType="VARCHAR" />
    </resultMap>

    <select id="selectAll" resultMap="BaseResultMap">
    select
         id, user_name, detail
    from boot_user order by detail asc
    </select>
</mapper>

数据源二:在src/main/resources/mapper/two(不存在文件加新建)创建BootUserTwoMapper.xml文件,具体配置信息如下:

<?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="com.yoodb.study.demo03.mapper.two.BootUserTwoMapper" >
    <resultMap id="BaseResultMap" type="com.yoodb.study.demo03.bean.BootUser" >
        <id column="id" property="id" jdbcType="VARCHAR" />
        <result column="user_name" property="name" jdbcType="VARCHAR" />
        <result column="detail" property="detail" jdbcType="VARCHAR" />
    </resultMap>

    <select id="selectAll" resultMap="BaseResultMap">
    select
         id, user_name, detail
    from boot_user order by detail asc
    </select>
</mapper>

2、新增mapper接口类文件

数据源一:mapper接口类文件,具体代码如下:

package com.yoodb.study.demo03.mapper.one;
import com.yoodb.study.demo03.bean.BootUser;
import java.util.List;
public interface BootUserOneMapper {
  List<BootUser> selectAll();
}

数据源二:mapper接口类文件,具体代码如下:

package com.yoodb.study.demo03.mapper.two;
import com.yoodb.study.demo03.bean.BootUser;
import java.util.List;
public interface BootUserTwoMapper {
  List<BootUser> selectAll();
}

3、创建service类文件

新增文件名BootUserService类文件,具体代码如下:

package com.yoodb.study.demo03.service;

import com.yoodb.study.demo03.bean.BootUser;
import com.yoodb.study.demo03.mapper.one.BootUserOneMapper;
import com.yoodb.study.demo03.mapper.two.BootUserTwoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class BootUserService {
    
    @Autowired
    private BootUserOneMapper onemapper;

    @Autowired
    private BootUserTwoMapper twomapper;

    public List<BootUser> getUsers(){
        List<BootUser> listone = onemapper.selectAll();
        List<BootUser> listtwo = twomapper.selectAll();
        listone.addAll(listtwo);
        return listone;
    }
}

4、创建controller类文件

新增文件名BootUserController类文件,具体代码如下:

package com.yoodb.study.demo03;

import java.util.List;

import com.yoodb.study.demo03.bean.BootUser;
import com.yoodb.study.demo03.service.BootUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/myt")
public class BootUserController {
    @Autowired
    private BootUserService service;

    @RequestMapping("/getUsers")
    public List<BootUser> getUsers() {
        List<BootUser> list = service.getUsers();
        return list;
    }

}

mapper的接口、xml文件及实体文件、service层、controller层创建完成后,目录如图:

Spring Boot从入门到精通(五)多数据源配置实现及源码分析

5、项目启动

以上操作完成后,项目启动过程中控制台报错,错误信息如下:

### Error querying database. Cause: org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "BOOT_USER" not found; SQL statement:
select
id, user_name, detail
from boot_user order by detail asc [42102-200]
### The error may exist in file [F:\project\study\springboot-study-demo03\target\classes\mapper\one\BootUserOneMapper.xml]
### The error may involve com.yoodb.study.demo03.mapper.one.BootUserOneMapper.selectAll
### The error occurred while executing a query
### SQL: select id, user_name, detail from boot_user order by detail asc
### Cause: org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "BOOT_USER" not found; SQL statement:

问题分析:目前Spring Boot最新版本不会将application.properties文件加载到classes目录下,导致无法读取到application.properties文件信息,从而在项目访问的时候控制台报上述错误信息。

解决方法:就是在pom.xml文件中增加如下配置信息:

<resources>
    <resource>
        <!-- 指定resources插件处理哪个目录下的资源文件 -->
        <directory>src/main/resources</directory>
        <includes>
            <include>**/**</include>
        </includes>
    </resource>
</resources>

上述问题解决完后系统可以正常启动,但是在通过浏览器访问时还是会报错。

访问地址:

http://localhost:8080/myt/getUsers

错误信息如下:

### Error querying database. Cause: java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.
### The error may exist in file [F:\project\study\springboot-study-demo03\target\classes\mapper\one\BootUserOneMapper.xml]
### The error may involve com.yoodb.study.demo03.mapper.BootUserOneMapper.selectAll
### The error occurred while executing a query
### Cause: java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.] with root cause
java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.

问题分析:

1)在Spring Boot 1.* 版本中配置数据源是spring.datasource.url和spring.datasource.driverClassName;

2)在Spring Boot 2.* 版本中配置数据源是spring.datasource.jdbc-url和spring.datasource.driver-class-name;

3)Spring Boot项目中(本文是基于Spring Boot 2.3.0.M2 版本)由于无法读取到application.properties文件中“driver-class-name”和“jdbc-url”两个参数导致项目报错。

解决方法:

将application.properties文件中spring.datasource..url和spring.datasource..driverClassName分别替换成spring.datasource..jdbc-url和spring.datasource..driver-class-name。

*Spring Boot源码分析:

1)spring.datasource.*.url替换成spring.datasource.*.jdbcUrl也没有任何问题。

源码org.springframework.boot.jdbc包中DatabaseDriver.class文件反编译后,发现url参数必须以“jdbc”开始,具体源码如下:

public static DatabaseDriver fromJdbcUrl(String url) {
    if (StringUtils.hasLength(url)) {
        Assert.isTrue(url.startsWith("jdbc"), "URL must start with 'jdbc'");
        String urlWithoutPrefix = url.substring("jdbc".length()).toLowerCase(Locale.ENGLISH);
        DatabaseDriver[] var2 = values();
        int var3 = var2.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            DatabaseDriver driver = var2[var4];
            Iterator var6 = driver.getUrlPrefixes().iterator();

            while(var6.hasNext()) {
                String urlPrefix = (String)var6.next();
                String prefix = ":" + urlPrefix + ":";
                if (driver != UNKNOWN && urlWithoutPrefix.startsWith(prefix)) {
                    return driver;
                }
            }
        }
    }

    return UNKNOWN;
}

2)spring.datasource.*.driverClassName不替换也没有影响。

源码org.springframework.boot.autoconfigure.jdbc包中ConfigurationProperties.class文件反编译后,发现属性即为driverClassName字段,具体源码如下:

public String determineDriverClassName() {
    if (StringUtils.hasText(this.driverClassName)) {
        Assert.state(this.driverClassIsLoadable(), () -> {
            return "Cannot load driver class: " + this.driverClassName;
        });
        return this.driverClassName;
    } else {
    ...

修改application.properties文件配置,参考信息如下:

spring.datasource.one.jdbc-url=jdbc:mysql://123.57.47.154:3306/springboot1
spring.datasource.one.username=root
spring.datasource.one.password=wangyoodb
spring.datasource.one.driver-class-name=com.mysql.cj.jdbc.Driver

spring.datasource.two.jdbc-url=jdbc:mysql://123.57.47.154:3306/springboot2
spring.datasource.two.username=root
spring.datasource.two.password=wangyoodb
spring.datasource.two.driver-class-name=com.mysql.cj.jdbc.Driver

引入话题

之前有群里的网友问Spring Boot中jdbc-url和url有什么区别?(题外话:关注微信公众号“Java精选”,留言切换工会总好后台发送消息可以进群,群内只允许探讨技术,完全免费,帮助大家解决各位技术难题。)

相信现在通过上述的分析,大家应该很清楚了吧,两者是因为Spring Boot升级版本调整了源码,所以“url”参数被重新命名了。

至此集成mybatis实现多数据源的方法已完成,项目启动成功后可以正常访问,通过浏览器访问输出如下信息:

[{"id":"1","name":"素文宅博客","detail":"欢迎关注“Java精选”微信公众号,专注 程序员 推送一些Java开发知识,包括基础知识、各大流行框架(Mybatis、Spring、Spring Boot等)、大数据技术(Storm、Hadoop、MapReduce、Spark等)、数据库(Mysql、Oracle、NoSQL等)、算法与数据结构、面试专题、面试技巧经验、职业规划以及优质开源项目等。"},{"id":"2","name":"素文宅博客导航","detail":"欢迎关注“Java精选”微信公众号,一部分由小编总结整理,另一部分来源于网络上优质资源,希望对大家的学习和工作有所帮助。"}]

使用JdbcTemplate

1、新增controller类文件

新增文件名JdbcTemplateController类文件,具体代码如下:

package com.yoodb.study.demo03;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.yoodb.study.demo03.bean.BootUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
@RequestMapping("/jte")
public class JdbcTemplateController {
    @Autowired
    private JdbcTemplate oneSqlSessionTemplate;

    @Autowired
    private JdbcTemplate twoSqlSessionTemplate;

    @RequestMapping("/getOneUsers")
    public List<Map<String, Object>> getOneUsers(){
        String sql = "select * from boot_user";
        List<Map<String, Object>> list =  twoSqlSessionTemplate.queryForList(sql);
        for (Map<String, Object> map : list) {
            Set<Entry<String, Object>> entries = map.entrySet( );
            if(entries != null) {
                Iterator<Entry<String, Object>> iterator = entries.iterator( );
                while(iterator.hasNext( )) {
                    Entry<String, Object> entry =(Entry<String, Object>) iterator.next( );
                    Object key = entry.getKey( );
                    Object value = entry.getValue();
                    System.out.println(key+":"+value);
                }
            }
        }
        return list;
    }

    @RequestMapping("/getTwoUsers")
    public List<BootUser> getTwoUsers() {
        List<BootUser> list = twoSqlSessionTemplate.query("select id,user_name " +
                "name,detail from boot_user", new BeanPropertyRowMapper<>(BootUser.class));
        return list;
    }
    
}

多数据源配置文件、多数据源类文件、实体类文件、controller层创建完成后,目录如图:

Spring Boot从入门到精通(五)多数据源配置实现及源码分析 上述操作完成后,因为集成mybatis时部分代码已存在(配置多数据源类文件),所以使用JdbcTemplate配置完成。

2、项目启动

项目启动后访问多数据源一请求地址:

http://localhost:8080/jte/getOneUsers

通过浏览器访问输出如下信息:

[{"id":1,"user_name":"素文宅博客","password":"e10adc3949ba59abbe56e057f20f883e","role_name":"素文宅博客","detail":"欢迎关注“Java精选”微信公众号,专注程序员推送一些Java开发知识,包括基础知识、各大流行框架(Mybatis、Spring、Spring Boot等)、大数据技术(Storm、Hadoop、MapReduce、Spark等)、数据库(Mysql、Oracle、NoSQL等)、算法与数据结构、面试专题、面试技巧经验、职业规划以及优质开源项目等。"}]

项目启动后访问多数据源二请求地址:

http://localhost:8080/jte/getTwoUsers

通过浏览器访问输出如下信息:

[{"id":"1","name":"素文宅博客","detail":"欢迎关注“Java精选”微信公众号,专注程序员推送一些Java开发知识,包括基础知识、各大流行框架(Mybatis、Spring、Spring Boot等)、大数据技术(Storm、Hadoop、MapReduce、Spark等)、数据库(Mysql、Oracle、NoSQL等)、算法与数据结构、面试专题、面试技巧经验、职业规划以及优质开源项目等。"}]

Spring容器中JdbcTemplate提供了两种注入方式,一种是使用@Resource注解,直接通过byName的方式注入进来,另外一种就是@Autowired注解加上@Qualifier注解,两者联合起来,实际上也是byName。

注意:

将JdbcTemplate注入成功后,oneSqlSessionTemplate和twoSqlSessionTemplate此时就代表操作不同的数据源,使用不同的JdbcTemplate操作不同的数据源,实现了多数据源配置。

Spring Boot从入门到精通项目源码(多数据源配置springboot-study-demo03)地址:

https://github.com/yoodb/springboot

至此,Spring Boot集成MyBatis和使用JdbcTemplate两种方式多数据源配置完成,下面大家有什么问题欢迎留言评论。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Algorithms on Strings, Trees and Sequences

Algorithms on Strings, Trees and Sequences

Dan Gusfield / Cambridge University Press / 1997-5-28 / USD 99.99

String algorithms are a traditional area of study in computer science. In recent years their importance has grown dramatically with the huge increase of electronically stored text and of molecular seq......一起来看看 《Algorithms on Strings, Trees and Sequences》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

MD5 加密
MD5 加密

MD5 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换