1. 程式人生 > >SpringBoot配置多資料來源(結合Druid)

SpringBoot配置多資料來源(結合Druid)

在單資料來源的情況下,Spring Boot的配置非常簡單,只需要在application.properties檔案中配置連線引數即可。但是往往隨著業務量發展,我們通常會進行資料庫拆分或是引入其他資料庫,從而我們需要配置多個數據源,下面介紹多資料來源的配置方式。

主要目錄結構:主要關注紅色方框中與本節相關的類。
這裡寫圖片描述

  1. 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>
  1. 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
  1. 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();
    }
}
  1. 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;
    }
}
  1. 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;
    }
}
  1. 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; 
    } 

}
  1. 實體類

在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;
    }


}
  1. 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> {

}
  1. 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> {

}

輸入druidconfig配置的使用者名稱密碼。
這裡寫圖片描述

這裡寫圖片描述

可以看到有兩個資料來源。