多数据源

所谓多数据源,就是一个Java EE项目中采用了不同数据库实例中的多个库,或者同一个数据库实例中多个不同的库。一般来说,采用MyCat等分布式数据库中间件是比较好的解决方案,这样可以把数据库读写分离、分库分表、备份等操作交给中间件去做,Java代码只需要专注于业务即可。

不过,这并不意味着无法使用Java代码解决类似的问题,在Spring Framework中就可以配置多数据源,Spring Boot继承其衣钵,只不过配置方式有所变化。

JdbcTemplate多数据源

JdbcTemplate多数据源的配置是比较简单的,因为一个JdbcTemplate对应一个DataSource,开发者只需要手动提供多个DataSource,再手动配置JdbcTemplate即可。具体步骤如下。

创建数据库

创建两个数据库:multiple_data1和multiple_data2。两个库中都创建book表,再各插入1条数据,创建脚本如下:

create database `multiple_data1` default CHARACTER SET utf8;
use multiple_data1;
create table z_book(
	id int(11) not null auto_increment,
	name varchar(128),
	author varchar(128),
	primary key(id)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
insert into z_book values (null,'图书1','作者1');

create database `multiple_data2` DEFAULT CHARACTER SET utf8;
use multiple_data2;
create table z_book(
	id int(11) not null auto_increment,
	name varchar(128),
	author varchar(128),
	primary key(id)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
insert into z_book values (null,'图书2','作者2');

创建项目

创建Spring Boot Web项目,添加如下依赖:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

注意这里添加的数据库连接池依赖是druid-spring-boot-starter。druid-spring-boot-starter可以帮助开发者在Spring Boot项目中轻松集成Druid数据库连接池和监控。

springboot多数据源JdbcTemplate_java

配置数据库连接

在application.properties中配置数据库连接信息,代码如下:

server.port=8099
#数据源1
spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.one.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.one.url=jdbc:mysql://localhost:3306/multiple_data1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimeZone=UTC
spring.datasource.one.username=root
spring.datasource.one.password=mysql123
#数据源2
spring.datasource.two.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.two.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.two.url=jdbc:mysql://localhost:3306/multiple_data2?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimeZone=UTC
spring.datasource.two.username=root
spring.datasource.two.password=mysql123

配置两个数据源,区别主要是数据库不同,其他都是一样的。

配置数据源

创建DataSourceConfig配置数据源,根据application.properties中的配置生成两个数据源:

DataSourceConfig.java

package com.shrimpking.config;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/6/6 12:52
 * 配置类
 */
@Configuration
public class DataSourceConfig
{
    /**
     * 数据源1
     * @return
     */
    @Bean
    @ConfigurationProperties("spring.datasource.one")
    DataSource dataSourceOne()
    {
        return DruidDataSourceBuilder.create().build();
    }

    /**
     * 数据源2
     * @return
     */
    @Bean
    @ConfigurationProperties("spring.datasource.two")
    DataSource dataSourceTwo()
    {
        return DruidDataSourceBuilder.create().build();
    }
}

代码解释:

• DataSourceConfig中提供了两个数据源:dataSourceOne和dataSourceTwo,默认方法名即实例名。

• @ConfigurationProperties注解表示使用不同前缀的配置文件来创建不同的DataSource实例。

配置JdbcTemplate

只要引入了spring-jdbc依赖,那么开发者没有提供JdbcTemplate实例时,Spring Boot默认会提供一个JdbcTemplate实例。现在配置多数据源时,由开发者自己提供JdbcTemplate实例,代码如下:

JdbcTemplateConfig.java

package com.shrimpking.config;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/6/6 12:55
 */
@Configuration
public class JdbcTemplateConfig
{
    /**
     * 数据源1
     * @param dataSource
     * @return
     */
    @Bean
    JdbcTemplate getJdbcTemplateOne(@Qualifier("dataSourceOne") DataSource dataSource)
    {
        return new JdbcTemplate(dataSource);
    }

    /**
     * 数据源2
     * @param dataSource
     * @return
     */
    @Bean
    JdbcTemplate getJdbcTemplateTwo(@Qualifier("dataSourceTwo") DataSource dataSource)
    {
        return new JdbcTemplate(dataSource);
    }
}

代码解释:

• JdbcTemplateConfig中提供两个JdbcTemplate实例。每个JdbcTemplate实例都需要提供DataSource,由于Spring容器中有两个DataSource实例,因此需要通过方法名查找。@Qualifier注解表示查找不同名称的DataSource实例注入进来。

创建BookController

创建实体类Book和BookController进行测试:

Book.java

package com.shrimpking.pojo;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/6/6 13:01
 */
public class Book
{
    private int id;
    private String name;
    private String author;

    public Book()
    {
    }

    public Book(String name, String author)
    {
        this.name = name;
        this.author = author;
    }

    public int getId()
    {
        return id;
    }

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

    public String getName()
    {
        return name;
    }

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

    public String getAuthor()
    {
        return author;
    }

    public void setAuthor(String author)
    {
        this.author = author;
    }

    @Override
    public String toString()
    {
        return "Book{" + "id=" + id + ", name='" + name + '\'' + ", author='" + author + '\'' + '}';
    }
}

BookController.java

package com.shrimpking.controller;

import com.shrimpking.pojo.Book;
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.GetMapping;
import org.springframework.web.bind.annotation.RestController;

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

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Shrimpking
 * @create 2023/6/6 13:03
 */
@RestController
public class BookController
{
    @Resource(name = "getJdbcTemplateOne")
    private JdbcTemplate jdbcTemplateOne;
    @Autowired
    @Qualifier("getJdbcTemplateTwo")
    private JdbcTemplate jdbcTemplateTwo;

    @GetMapping("/booktest")
    public String test()
    {
        String sql = "select id,name,author from z_book";
        List<Book> books1 = jdbcTemplateOne.query(sql, new BeanPropertyRowMapper<>(Book.class));
        List<Book> books2 = jdbcTemplateTwo.query(sql, new BeanPropertyRowMapper<>(Book.class));

        System.out.println("books1:" + books1);
        System.out.println("books2:" + books2);
        return "查询成功";
    }
}

简单起见,这里没有添加Service层,而是直接将JdbcTemplate注入到了Controller中。

在Controller中注入两个不同的JdbcTemplate有两种方式:

一种是使用@Resource注解,并指明name属性,即按name进行装配,此时会根据实例名查找相应的实例注入;

另一种是使用@Autowired注解结合@Qualifier注解,效果等同于使用@Resource注解。

测试

springboot多数据源JdbcTemplate_java_02

 

springboot多数据源JdbcTemplate_spring_03