Spring Boot的多數據源配置——JPA

    之前的項目一直在用Mybatis,不過因爲sql都比較複雜,所Mybatis實現起來很方便。但一些簡單的增刪改查卻也要寫sql就比較麻煩了,畢竟代碼的話能少寫一點是一點。於是開始打算用JPA來做一些簡單的小服務。

一. yml文件配置

    項目就直接用STS建了,導包也直接在建項目時勾選就行。

    如果只是單獨的數據源的話直接配置yml使用Spring Boot的datasource配置方式就行。(其中自帶有四種連接池)

    不過我寫的demo使用的是阿里的druid,所以可根據使用的連接池更換不同的寫法。下面貼上我application.yml文件的配置。

server:
  port: 8888
spring:
  application:
    name: lcy-many-datesource
  datasource:
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    # poolPreparedStatements: Oracle爲true,MySql可爲false
    poolPreparedStatements: true
    maxPoolPreparedStatementPerConnectionSize: 20
    filters: stat,log4j
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
    testdb:
      driverClassName: com.mysql.jdbc.Driver
      url: jdbc:mysql://132.97.61.65:3306/test?useUnicode=true&characterEncoding=utf-8
      username: itsm
      password: whtisson
    demodb:
      driverClassName: com.mysql.jdbc.Driver
      url: jdbc:mysql://132.97.61.65:3306/demo?useUnicode=true&characterEncoding=utf-8
      username: itsm
      password: whtisson
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update

    這裏我把連接數配置、連接健康狀況檢查配置都寫成了公共部分,而testdbdemodb兩個數據庫配置單獨分開寫。因爲這裏懶得建表了所以直接把ddl - auto設置爲update讓它自己建表。

二. 類配置

    因爲Spring Boot不使用xml文件進行配置,所以使用類來完成entity類、repository接口等相關的配置。而JPA的主要獲取:DataSourceEntityManagerFactoryPlatformTransactionManager,具體配置如下。

1. DruidDataSourceConfig.java (Druid配置)
package com.lcy.config;

import java.sql.SQLException;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import com.alibaba.druid.pool.DruidDataSource;

/**
 * @ClassName: DruidDataSourceConfig
 * @Description: 總數據源配置類
 * @author lcy
 * @date 2018年4月4日 下午2:36:26
 */
@Configuration
public class DruidDataSourceConfig {

	private Logger log = LoggerFactory.getLogger(DruidDataSourceConfig.class);

	@Value("${spring.datasource.initialSize}")
	private int initialSize;

	@Value("${spring.datasource.minIdle}")
	private int minIdle;

	@Value("${spring.datasource.maxActive}")
	private int maxActive;

	@Value("${spring.datasource.maxWait}")
	private int maxWait;

	@Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
	private int timeBetweenEvictionRunsMillis;

	@Value("${spring.datasource.minEvictableIdleTimeMillis}")
	private int minEvictableIdleTimeMillis;

	@Value("${spring.datasource.validationQuery}")
	private String validationQuery;

	@Value("${spring.datasource.testWhileIdle}")
	private boolean testWhileIdle;

	@Value("${spring.datasource.testOnBorrow}")
	private boolean testOnBorrow;

	@Value("${spring.datasource.testOnReturn}")
	private boolean testOnReturn;

	@Value("${spring.datasource.poolPreparedStatements}")
	private boolean poolPreparedStatements;

	@Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
	private int maxPoolPreparedStatementPerConnectionSize;

	@Value("${spring.datasource.filters}")
	private String filters;

	@Value("{spring.datasource.connectionProperties}")
	private String connectionProperties;

	/* #####################基礎公共配置##################### */

	@Value("${spring.datasource.testdb.url}")
	private String testUrl;

	@Value("${spring.datasource.testdb.username}")
	private String testUsername;

	@Value("${spring.datasource.testdb.password}")
	private String testPassword;

	@Value("${spring.datasource.testdb.driverClassName}")
	private String testDriverClassName;

	@Bean(name = "testDataSource")
	@Primary // 確定主數據源
	public DataSource testDataSource() {
		log.info("創建testDataSource數據源");
		return createDataSource(testUrl, testUsername, testPassword, testDriverClassName);
	}

	/* #####################testDataSource配置##################### */

	@Value("${spring.datasource.demodb.url}")
	private String demoUrl;

	@Value("${spring.datasource.demodb.username}")
	private String demoUsername;

	@Value("${spring.datasource.demodb.password}")
	private String demoPassword;

	@Value("${spring.datasource.demodb.driverClassName}")
	private String demoDriverClassName;

	@Bean(name = "demoDataSource")
	public DataSource demoDataSource() {
		log.info("創建demoDataSource數據源");
		return createDataSource(demoUrl, demoUsername, demoPassword, demoDriverClassName);
	}

	/* #####################demoDataSource配置##################### */

	private DataSource createDataSource(String url, String username, String password, String driverClassName) {
		DruidDataSource datasource = new DruidDataSource();
		datasource.setUrl(url);
		datasource.setUsername(username);
		datasource.setPassword(password);
		datasource.setDriverClassName(driverClassName);
		// configuration
		datasource.setInitialSize(initialSize);
		datasource.setMinIdle(minIdle);
		datasource.setMaxActive(maxActive);
		datasource.setMaxWait(maxWait);
		datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
		datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
		datasource.setValidationQuery(validationQuery);
		datasource.setTestWhileIdle(testWhileIdle);
		datasource.setTestOnBorrow(testOnBorrow);
		datasource.setTestOnReturn(testOnReturn);
		datasource.setPoolPreparedStatements(poolPreparedStatements);
		datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
		try {
			datasource.setFilters(filters);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		datasource.setConnectionProperties(connectionProperties);
		return datasource;
	}

}

    這個配置應該沒有特別要說明的,聲明一個阿里的Datasource對象,將yml中的參數set進去後控制反轉,設置一個唯一的Bean的name即可。

2. TestDataSourceConfig.java (數據源一配置)
package com.lcy.config;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
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;

/**
 * @ClassName: TestDataSourceConfig
 * @Description: Test數據源配置類
 * @author lcy
 * @date 2018年4月4日 下午3:05:44
 */
@Configuration
@EnableTransactionManagement // 開啓註解事務管理
@EnableJpaRepositories(entityManagerFactoryRef = "testEntityManagerFactory", // 實體類工廠依賴
		transactionManagerRef = "testTransactionManager", // 事務依賴
		basePackages = "com.lcy.repository.test") // repository類所在的包
public class TestDataSourceConfig {

	private Logger log = LoggerFactory.getLogger(TestDataSourceConfig.class);

	@Autowired
	private JpaProperties jpaProperties;

	@Autowired
	@Qualifier("testDataSource")
	private DataSource dataSource;

	/*
	 * 通過LocalContainerEntityManagerFactoryBean來獲取EntityManagerFactory實例
	 */
	@Bean(name = "testEntityManagerFactoryBean")
	public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder) {
		log.info("創建testEntityManagerFactoryBean");
		return builder.dataSource(dataSource)// 設置使用的數據源
				.properties(jpaProperties.getHibernateProperties(dataSource))// 設置JPA屬性
				.packages("com.lcy.entity.test")// 設置實體類所在的包
				// 持久性單元的名稱,如果只構建一個EntityManagerFactory,可以省略它,
				// 但是如果在同一個應用程序中有多個,應該給它們起不同的名稱。
				.persistenceUnit("testPersistenceUnit")
				.build();
		// 不要在這裏直接獲取EntityManagerFactory
	}

	/*
	 * EntityManagerFactory類似於Hibernate的SessionFactory,mybatis的SqlSessionFactory
	 * 總之,在執行操作之前,我們總要獲取一個EntityManager,這就類似於Hibernate的Session,
	 * mybatis的sqlSession.
	 */
	@Bean(name = "testEntityManagerFactory")
	@Primary
	public EntityManagerFactory entityManagerFactory(EntityManagerFactoryBuilder builder) {
		log.info("創建testEntityManagerFactory");
		return this.entityManagerFactoryBean(builder).getObject();
	}

	/*
	 * 配置事務管理器
	 */
	@Bean(name = "testTransactionManager")
	@Primary
	public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
		log.info("創建testTransactionManager");
		return new JpaTransactionManager(this.entityManagerFactory(builder));
	}

}
  1. @Primary註解在這裏依舊是強調主數據源而已,不加並不影響。
  2. 依賴注入Datasource時一定要加@Qualifier來聲明要注入的Bean是哪個,不然會默認注入DataSourceConfig.java中加了@Primary的Datasource。
3. DemoDataSourceConfig.java (數據源二配置)    
package com.lcy.config;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
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;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "demoEntityManagerFactory",
						transactionManagerRef = "demoTransactionManager",
						basePackages = "com.lcy.repository.demo")
public class DemoDataSourceConfig {
	
	private Logger log = LoggerFactory.getLogger(TestDataSourceConfig.class);

	@Autowired
	private JpaProperties jpaProperties;
	
	@Autowired
    @Qualifier("demoDataSource")
    private DataSource dataSource;
	
	@Bean(name = "demoEntityManagerFactoryBean")
	public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder){
		log.info("創建demoEntityManagerFactoryBean");
		return builder
				.dataSource(dataSource)
				.properties(jpaProperties.getHibernateProperties(dataSource))
				.packages("com.lcy.entity.demo")
				.persistenceUnit("demoPersistenceUnit")
				.build();
	}
	
	@Bean(name = "demoEntityManagerFactory")
	public EntityManagerFactory entityManagerFactory(EntityManagerFactoryBuilder builder){
		log.info("創建demoEntityManagerFactory");
		return this.entityManagerFactoryBean(builder).getObject();
	}
	
	@Bean(name = "demoTransactionManager")
	public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder){
		log.info("創建demoTransactionManager");
		return new JpaTransactionManager(this.entityManagerFactory(builder));
	}
	
}

    基本結構入圖,只要在配置中的包路徑配置正確就可以操作不同的數據源了。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章