在单数据源的情况下,Spring Boot的配置非常简单,只需要在application.properties文件中配置连接参数即可。但是往往随着业务量发展,我们通常会进行数据库拆分或是引入其他数据库,从而我们需要配置多个数据源,下面介绍多数据源的配置方式。
主要目录结构:主要关注红色方框中与本节相关的类。
- pom.xml
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.easted</groupId>
<artifactId>card</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>card</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Dalston.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 阿里的druid依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.19</version>
</dependency>
<!-- 格式化对象,方便输出日志 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.1.41</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- lombok 在类上加@Data可以省略get、set方法 -->
<!-- <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>
spring-boot-starter-data-elasticsearch
</artifactId>
</dependency>
<dependency>
<groupId>com.sun.jna</groupId>
<artifactId>jna</artifactId>
<version>3.0.9</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.8</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- application.yml
# Server configuration
server:
port: 8090
contextPath:
# Spring configuration
spring:
thymeleaf:
cache: false
mvc:
favicon:
enabled: false
#Multi DataSource Config
datasource:
primary:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:postgresql://127.0.0.1/db_one
username: wangh
password: easted2013
driverClassName: org.postgresql.Driver
initialSize: 5
minIdle: 5
maxActive: 200
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
filters: stat,wall,log4j
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
slave:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:postgresql://127.0.0.1/db_two
username: wangh
password: easted2013
driverClassName: org.postgresql.Driver
initialSize: 5
minIdle: 5
maxActive: 200
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
filters: stat,wall,log4j
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
jpa:
show-sql: true
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
- DataSourceConfig类
package com.easted.card.core.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
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 com.alibaba.druid.pool.DruidDataSource;
/**
1. @ClassName:DataSourceConfig
2. @author:wh
3. @date: 2017年9月12日 上午10:33:39
*/
@Configuration
public class DataSourceConfig {
@Bean(name = "primaryDataSource")
@Qualifier("primaryDataSource")
@Primary//配置该数据源为主数据源
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource(){
// return DataSourceBuilder.create().build();
return new DruidDataSource();
}
@Bean(name = "slaveDataSource")
@Qualifier("slaveDataSource")
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource secondDataSource(){
// return DataSourceBuilder.create().build();
return new DruidDataSource();
}
}
- PrimaryConfig类
新增对第一数据源的JPA配置,注意两处注释的地方,用于指定数据源对应的Entity实体和Repository定义位置,用@Primary区分主数据源。
package com.easted.card.core.config;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import org.hibernate.cfg.ImprovedNamingStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
1. @ClassName:PrimaryConfig
2. @author:Wh
3. @date: 2017年9月13日 上午10:11:40
*/
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef="entityManagerFactoryPrimary",
transactionManagerRef="transactionManagerPrimary",
basePackages= { "com.easted.card.core.repository.primary"}) //设置Repository所在位置
public class PrimaryConfig {
@Autowired
@Qualifier("primaryDataSource")
private DataSource primaryDataSource;
@Primary
@Bean(name = "entityManagerPrimary")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
}
@Bean(name = "entityManagerFactoryPrimary")
@Primary
public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary (EntityManagerFactoryBuilder builder) {
return builder.dataSource(primaryDataSource)
.packages("com.easted.card.core.entity.postgre1")
.persistenceUnit("primary")
.properties(buildProperties())
.build();
}
@Bean(name="transactionManagerPrimary")
@Autowired
public PlatformTransactionManager primaryTransactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
}
// 公共jpa设置
@Value("${spring.jpa.hibernate.ddl-auto}")
String dll;
@Value("${spring.jpa.properties.hibernate.dialect}")
String dialect;
@Value("${spring.jpa.show-sql}")
String showSql;
private Map<String, Object> buildProperties() {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.ejb.naming_strategy", ImprovedNamingStrategy.class.getName());
properties.put("hibernate.hbm2ddl.auto", dll);
properties.put("hibernate.dialect", dialect);
properties.put("hibernate.show_sql", showSql);
return properties;
}
}
- SlaveConfig类
package com.easted.card.core.config;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import org.hibernate.cfg.ImprovedNamingStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* SlaveConfig
* @author:Wh
* @date: 2017年9月13日 上午10:11:40
*/
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef="entityManagerFactorySlave",
transactionManagerRef="transactionManagerSlave",
basePackages= { "com.easted.card.core.repository.slave"}) //设置Repository所在位置
public class SlaveConfig {
@Autowired
@Qualifier("slaveDataSource")
private DataSource slaveDataSource;
@Bean(name = "entityManagerSlave")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactorySlave(builder).getObject().createEntityManager();
}
@Bean(name = "entityManagerFactorySlave")
public LocalContainerEntityManagerFactoryBean entityManagerFactorySlave(EntityManagerFactoryBuilder builder) {
return builder.dataSource(slaveDataSource)
.packages("com.easted.card.core.entity.postgre2")
.persistenceUnit("slave")
.properties(buildProperties())
.build();
}
@Bean(name="transactionManagerSlave")
@Autowired
public PlatformTransactionManager slaveTransactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactorySlave(builder).getObject());
}
// 公共jpa设置
@Value("${spring.jpa.hibernate.ddl-auto}")
String dll;
@Value("${spring.jpa.properties.hibernate.dialect}")
String dialect;
@Value("${spring.jpa.show-sql}")
String showSql;
private Map<String, Object> buildProperties() {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.ejb.naming_strategy", ImprovedNamingStrategy.class.getName());
properties.put("hibernate.hbm2ddl.auto", dll);
properties.put("hibernate.dialect", dialect);
properties.put("hibernate.show_sql", showSql);
return properties;
}
}
- DruidConfig类
package com.easted.card.core.config;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
/**
1. 配置Druid监控
2. @ClassName:DruidDBConfig
3. @author:Wh
4. @date: 2017年8月23日 下午3:21:51
*/
@Configuration
@EnableTransactionManagement
public class DruidConfig{
private static final Logger log = LoggerFactory.getLogger(DruidConfig.class);
@Bean
public ServletRegistrationBean druidServlet() {
log.info("开始Druid Servlet初始化配置...");
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
servletRegistrationBean.setServlet(new StatViewServlet());
servletRegistrationBean.addUrlMappings("/druid/*");
Map<String, String> initParameters = new HashMap<String, String>();
//用户名
initParameters.put("loginUsername", "wangh");
//密码
initParameters.put("loginPassword", "easted");
// 禁用HTML页面上的“Reset All”功能
initParameters.put("resetEnable", "false");
// IP白名单 (没有配置或者为空,则允许所有访问)
initParameters.put("allow", "127.0.0.1");
// IP黑名单 (存在共同时,deny优先于allow)
initParameters.put("deny", "");
servletRegistrationBean.setInitParameters(initParameters);
return servletRegistrationBean;
}
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
return filterRegistrationBean;
}
}
- 实体类
在postgre1和postgre2包下分别建实体类。
package com.easted.card.core.entity.postgre1;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Book {
@Id
@GeneratedValue
private Integer id;
private String name;
/**
* @Title: getId <BR>
* @return:Integer <BR>
*/
public Integer getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Integer id) {
this.id = id;
}
/**
* @Title: getName <BR>
* @return:String <BR>
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
}
- primary包下BookRepository接口
package com.easted.card.core.repository.primary;
import org.springframework.data.jpa.repository.JpaRepository;
import com.easted.card.core.entity.postgre1.Book;
public interface BookRepository extends JpaRepository<Book, Integer> {
}
- slave包下BookRepository接口
package com.easted.card.core.repository.slave;
import org.springframework.data.jpa.repository.JpaRepository;
import com.easted.card.core.entity.postgre2.Book;
public interface BookRepository extends JpaRepository<Book, Integer> {
}
然后启动springboot.就可以了。
浏览器输入http://localhost:8090/druid/login.html
输入druidconfig配置的用户名密码。
可以看到有两个数据源。