历史上最详细的SpringBoot多数据源配置及使用流程

关于标题—>只是想看看标题党的效果如何

一、场景(简化)

要实现一个用户数据中心的系统架构,其中要用到两个数据库,一个database名为sso,主要存放用户的信息。另一个database名为configuration,存放一些配置信息。当A系统通过接口过来请求用户信息时,需要在配置库查询A系统的权限,然后将对应权限的用户信息返回给A系统。所以就需要使用两个不同的库,要在同一个项目中配置两套EntityManager(或者Hibernate的session)和事物管理。

连接池使用阿里巴巴的Druid,持久框架使用的Hibernate,需要引入spring-boot-starter-data-jpa

二、实体的包结构

  • com.kingboy.configuration.domain(配置中心的实体)
  • com.kingboy.ssoservice.domain(用户信息的实体)

三、配置文件(application.properties)

分别编写两套数据源的配置,我主要用不同的模块名称来区分不同的数据源。

  • spring.datasource.configuration.*
  • spring.datasource.sso.*
#-----------------------------------通用数据源配置-----------------------------
spring.jpa.hibernate.ddl-auto=update
spring.jpa.open-in-view=false
spring.jpa.show-sql=true
#---------------------------------------------------------
#configuration数据源
spring.datasource.configuration.url=jdbc:mysql://localhost:3306/configration?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false
spring.datasource.configuration.username=root
spring.datasource.configuration.password=123456
spring.datasource.configuration.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.configuration.maxActive=20
spring.datasource.configuration.initialSize=5
spring.datasource.configuration.minIdle=5
spring.datasource.configuration.maxWait=60000
spring.datasource.configuration.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.configuration.timeBetweenEvictionRunsMillis=60000
spring.datasource.configuration.minEvictableIdleTimeMillis=300000
spring.datasource.configuration.poolPreparedStatements=true
#---------------------------------------------------------
#sso数据源
spring.datasource.sso.url=jdbc:mysql://localhost:3306/sso?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false
spring.datasource.sso.username=root
spring.datasource.sso.password=123456
spring.datasource.sso.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.sso.maxActive=20
spring.datasource.sso.initialSize=5
spring.datasource.sso.minIdle=5
spring.datasource.sso.maxWait=60000
spring.datasource.sso.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.sso.timeBetweenEvictionRunsMillis=60000
spring.datasource.sso.minEvictableIdleTimeMillis=300000
spring.datasource.sso.poolPreparedStatements=true

这么多属性一看就很萌逼了,我们先把它加载到一个信息载体类中,方便以后使用。

configuration数据源的信息载体类:

package com.kingboy.configuration.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @Author kingboy
 * @Date 2017/6/19 下午5:15
 * @Description ConfigurationProperties is used to configuration的数据池属性
 */
@ConfigurationProperties(prefix = "spring.datasource.configuration")
@Component
public class ConfigurationDataSourceProperties {

    public String url;

    public String username;

    public String password;

    public String driverClassName;

    public Integer maxActive;

    public Integer initialSize;

    public Integer minIdle;

    public Integer maxWait;

    public Integer maxPoolPreparedStatementPerConnectionSize;

    public Integer timeBetweenEvictionRunsMillis;

    public Integer minEvictableIdleTimeMillis;

    public Boolean poolPreparedStatements;

}

sso数据源的信息载体类:

package com.kingboy.ssoservice.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @Author kingboy
 * @Date 2017/6/19 下午5:15
 * @Description ConfigurationProperties is used to configuration的数据池属性
 */
@ConfigurationProperties(prefix = "spring.datasource.sso")
@Component
public class SSODataSourceProperties {

    public String url;

    public String username;

    public String password;

    public String driverClassName;

    public Integer maxActive;

    public Integer initialSize;

    public Integer minIdle;

    public Integer maxWait;

    public Integer maxPoolPreparedStatementPerConnectionSize;

    public Integer timeBetweenEvictionRunsMillis;

    public Integer minEvictableIdleTimeMillis;

    public Boolean poolPreparedStatements;

}

四、配置configuration和sso的实体管理Bean和事物管理Bean

具体的配置说明都写在代码注释里面了。

configuration的配置

package com.kingboy.configuration.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
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.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;
import javax.sql.DataSource;
import java.util.Map;

/**
 * @Author kingboy
 * @Date 2017/6/18 下午11:13
 * @Description ConfigurationDataSource is used to 数据源配置
 */
@Configuration
@EnableTransactionManagement//开启事物管理
@EnableJpaRepositories(//自定义数据管理的配置
        //指定EntityManager的创建工厂Bean
        entityManagerFactoryRef="configurationEntityManagerFactory",
        //指定事物管理的Bean
        transactionManagerRef="configurationTransactionManager",
        //指定管理的实体位置
        basePackages= {"com.kingboy.configuration.domain"}) 
public class ConfigurationJPAConfig {

    /*
     * 配置数据源
     */
    @Bean
    public DataSource configurationDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        //设置数据源的属性
        setDruidProperties(dataSource);
        return dataSource;
    }

    @Autowired
    ConfigurationDataSourceProperties config;//注入数据源配置信息

    //设置数据源的属性的方法
    private void setDruidProperties(DruidDataSource dataSource) {
        dataSource.setUrl(config.url);
        dataSource.setUsername(config.username);
        dataSource.setPassword(config.password);
        dataSource.setDriverClassName(config.driverClassName);
        dataSource.setMaxActive(config.maxActive);
        dataSource.setInitialSize(config.initialSize);
        dataSource.setMinIdle(config.minIdle);
        dataSource.setMaxWait(config.maxWait);
        dataSource.setMaxPoolPreparedStatementPerConnectionSize(config.maxPoolPreparedStatementPerConnectionSize);
        dataSource.setTimeBetweenEvictionRunsMillis(config.timeBetweenEvictionRunsMillis);
        dataSource.setMinEvictableIdleTimeMillis(config.minEvictableIdleTimeMillis);
        dataSource.setPoolPreparedStatements(config.poolPreparedStatements);
    }

    /*
     * 配置实体管理工厂Bean
     */
    @Bean
    public LocalContainerEntityManagerFactoryBean configurationEntityManagerFactory (EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(configurationDataSource())
                .packages("com.kingboy.configuration.domain")//设置实体类所在位置
                .persistenceUnit("configuration")
                .properties(getProperties(configurationDataSource()))//设置hibernate通用配置
                .build();
    }

    @Autowired
    private JpaProperties jpaProperties;//注入spring自带的jpa属性类

    /*
     *拿到hibernate的通用配置
     */
    private Map<String, String> getProperties(DataSource dataSource) {
        return jpaProperties.getHibernateProperties(dataSource);
    }

    /*
     *配置事物管理的Bean
     */
    @Bean
    public PlatformTransactionManager configurationTransactionManager(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(configurationEntityManagerFactory(builder).getObject());
    }


}

sso的配置

package com.kingboy.ssoservice.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
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;

import javax.sql.DataSource;
import java.util.Map;

/**
 * @Author kingboy
 * @Date 2017/6/18 下午11:13
 * @Description ConfigurationDataSource is used to 数据源配置
 */
@Configuration
@EnableTransactionManagement//开启事物管理
@EnableJpaRepositories(//自定义数据管理的配置
        //指定EntityManager的创建工厂Bean
        entityManagerFactoryRef="ssoEntityManagerFactory",
        //指定事物管理的Bean
        transactionManagerRef="ssoTransactionManager",
        //指定管理的实体位置
        basePackages= {"com.kingboy.ssoservice.domain"}) //设置Repository所在位置
public class SSOJPAConfig {

    /*
     * 配置数据源
     */
    @Bean
    @Primary//主数据源,或者叫默认数据源,下面的@Primary同理
    public DataSource ssoDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        setDruidProperties(dataSource);
        return dataSource;
    }

    //注入数据源配置信息
    @Autowired
    SSODataSourceProperties config;

    private void setDruidProperties(DruidDataSource dataSource) {
        dataSource.setUrl(config.url);
        dataSource.setUsername(config.username);
        dataSource.setPassword(config.password);
        dataSource.setDriverClassName(config.driverClassName);
        dataSource.setMaxActive(config.maxActive);
        dataSource.setInitialSize(config.initialSize);
        dataSource.setMinIdle(config.minIdle);
        dataSource.setMaxWait(config.maxWait);
        dataSource.setMaxPoolPreparedStatementPerConnectionSize(config.maxPoolPreparedStatementPerConnectionSize);
        dataSource.setTimeBetweenEvictionRunsMillis(config.timeBetweenEvictionRunsMillis);
        dataSource.setMinEvictableIdleTimeMillis(config.minEvictableIdleTimeMillis);
        dataSource.setPoolPreparedStatements(config.poolPreparedStatements);
    }

    /*
     * 配置实体管理工厂Bean
     */
    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean ssoEntityManagerFactory (EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(ssoDataSource())
                .packages("com.kingboy.ssoservice.domain") //设置实体类所在位置
                .persistenceUnit("sso")
                .properties(getProperties(ssoDataSource()))//设置hibernate通用配置
                .build();
    }

    @Autowired
    private JpaProperties jpaProperties;//注入spring自带的jpa属性类

    /*
     *拿到hibernate的通用配置
     */
    private Map<String, String> getProperties(DataSource dataSource) {
        return jpaProperties.getHibernateProperties(dataSource);
    }

    /*
     *配置事物管理的Bean
     */
    @Bean
    public PlatformTransactionManager ssoTransactionManager(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(ssoEntityManagerFactory(builder).getObject());
    }


}

五、关于第四节的说明

  1. @Bean注解如果没有指定bean的名字,那么会以方法名作为bean的名字。所以就有了@EnableJpaRepositories注解中的entityManagerFactoryRef="ssoEntityManagerFactory"transactionManagerRef="ssoTransactionManager"

  2. private JpaProperties jpaProperties;是spring自动注入的,可以获取到配置文件中『通用数据源配置』的信息,如show-sql等属性。

  3. 只所以将sso与configuration分开配置,一是为了整洁。二是为了模块解耦,如果是多模块项目,会很好拆分。

六、使用

为了方便阅读,随便写个栗子,就从controller开始写了。也不使用接口编程了,这样看起来更顺畅。

实体类(注解就不加了)
public class User {
    private Integer id;
    private String telephone;
    private String password;
    //setter getter
}

public class Configuration {
    private Integer id;
    private String formatId;
    private String secret;
    //setter getter
}
Controller
@RestController
@RequestMapping(produces = "application/json")
public class UserController {

    @Resource
    UserService userService;

    @Resource
    ConfigurationService configurationService;

    /**
     * 添加User
     * @return
     */
    //为了方便用了restfule的形式,正常要用post,https
    @GetMapping(value = "/AddUser/{telephone}/{password}")
    public ApiResult add(@PathVariable String telephone, @PathVariable String password) {
        userService.addUser(telephone, password);
        return ApiResult.success("add user success!");
    }

    /**
     * 添加配置
     * @return
     */
    //为了方便用了restfule的形式,正常要用post,https
    @GetMapping(value = "/AddConfig/{formatId}/{secret}")
    public ApiResult add(@PathVariable String formatId, @PathVariable String secret) {
        configurationService.addConfig(formatId, secret);
        return ApiResult.success("add config success!");
    }

}
Service
@Service
public class UserServiceImpl{

    @Resource
    UserRepository userRepository;

    @Override
    @Transactional(rollbackFor = Exception.class, value = "ssoTransactionManager")//对应的事物管理Bean的名字
    public void addUser(String telephone,String password) {
        userRepository.addUser(telephone, password);
    }

}

@Service
public class ConfigurationServiceImpl{

    @Resource
    ConfigurationRepository configurationRepository;

    @Override
    @Transactional(rollbackFor = Exception.class, value = "configurationTransactionManager")//对应的事物管理Bean的名字
    public void addConfig(String formatId,String secret) {
        configurationRepository.addConfig(formatId, secret);
    }

}
Repository
@Repository
public class UserRepositoryImpl {

    @Autowired
    @Qualifier("ssoEntityManagerFactory")//实体管理工厂Bean的名字
    EntityManager ssoEntityManager;

    @Override
    public void addUser(String telephone, String password) {
        User user = new User(null, telephone, password);
        ssoEntityManager.persist(user);
    }

}

@Repository
public class ConfigurationRepositoryImpl {

    @Autowired
    @Qualifier("configurationEntityManagerFactory")//实体管理工厂Bean的名字
    EntityManager configurationEntityManager;

    @Override
    public void addConfig(String formatId, String secret) {
        Configuration config = new Configuration(null, formatId, secret);
        configurationEntityManager.persist(config);
    }

}

上面代码手写,可能个别地方会有个小纰漏。

至此,全部搞定……m……m……p

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值