多数据源
所谓多数据源,就是一个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数据库连接池和监控。
配置数据库连接
在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注解。
测试