1. 程式人生 > >springboot配置多資料來源之Spring Date JPA

springboot配置多資料來源之Spring Date JPA

多資料來源在專案開發中是經常遇到的,如果同一個專案的不同模組使用的是不同資料庫,就需要多資料來源的處理。現在先寫之前使用JPA的時候遇到多資料來源的配置,後續可能再來個關於mybatis的多資料來源配置。

現在有這樣的需求,專案中有兩個模組,分別是flow與imap,flow需要使用預設資料來源,imap需要使用imap資料來源。

先來個maven依賴,使用的連線池是durid。

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-devtools</artifactId>
	<optional>true</optional>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
	<groupId>com.google.code.gson</groupId>
	<artifactId>gson</artifactId>
</dependency>
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--阿里巴巴druid資料庫連線池--><!--http://localhost:8080/druid/index.html-->
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>druid</artifactId>
	<version>1.1.1</version>
</dependency>

先來個application.yml配置,配置多個數據源。

server:
  port: 8080

spring:
  application:
    name: xichuan
  profiles:
    active: dev


---
spring:
  profiles: dev
  datasource:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db_flow?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false
    username: root
    password: root
    type: com.alibaba.druid.pool.DruidDataSource
    initialSize: 1
    minIdle: 1
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: true
    testOnReturn: false
    poolPreparedStatements: false
    maxPoolPreparedStatementPerConnectionSize: 20
    filters: stat,wall,log4j
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000

  imap_datasource:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db_imap?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false
    username: root
    password: root
    type: com.alibaba.druid.pool.DruidDataSource
    initialSize: 1
    minIdle: 1
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: true
    testOnReturn: false
    poolPreparedStatements: false
    maxPoolPreparedStatementPerConnectionSize: 20
    filters: stat,wall,log4j
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000

  jpa:
    database : MYSQL
    show-sql : true
    hibernate:
        ddl-auto: update
    properties:
        hibernate.format_sql: true
        hibernate.naming.physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
        hibernate.cache.use_second_level_cache: false
        hibernate.search.default.directory_provider: filesystem
        hibernate.search.default.indexBase: ./indexes
    open-in-view: true

druid:
  allow:
    ip: 127.0.0.1
  login:
    user_name: root
    password: root

新增durid的配置,之前有寫過springboot整合durid的博文:https://blog.csdn.net/zc_ad/article/details/83340067

@Configuration
public class DruidConfig {

    private static final Logger log = LoggerFactory.getLogger(DruidConfig.class);

    @Value("${druid.login.user_name}")
    private String userName;

    @Value("${druid.login.password}")
    private String password;

    @Value("${druid.allow.ip}")
    private String allowIp;

    /**
     * 配置預設資料來源
     * @return
     */
    @Bean(name = "flow_databaseSource")
    @Qualifier("flow_databaseSource")
    @Primary
    @ConfigurationProperties(prefix="spring.datasource")
    public DataSource flowDataSource() {
        return  new DruidDataSource();
    }


    /**
     * 配置imap資料來源
     * @return
     */
    @Bean(name = "imap_databaseSource")
    @Qualifier("imap_databaseSource")
    @ConfigurationProperties(prefix="spring.imap_datasource")
    public DataSource imapDataSource() {
        return new DruidDataSource();
    }


    @Bean
    public ServletRegistrationBean druidServlet() {
        log.info("init Druid Servlet Configuration, username:{},password:{},allowip:{}",userName,password,allowIp);
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
        servletRegistrationBean.setServlet(new StatViewServlet());
        servletRegistrationBean.addUrlMappings("/druid/*");
        Map<String, String> initParameters = new HashMap<>();
        initParameters.put("loginUsername", userName);// 使用者名稱
        initParameters.put("loginPassword", password);// 密碼
        //initParameters.put("resetEnable", "false");// 禁用HTML頁面上的“Reset All”功能
        initParameters.put("allow", ""); // IP白名單 (沒有配置或者為空,則允許所有訪問)
        //initParameters.put("deny", "");// IP黑名單 (存在共同時,deny優先於allow)
        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;
    }

}

預設資料來源配置:

@Configuration
@EnableJpaRepositories(
        entityManagerFactoryRef="flow_entityManagerFactory",
        transactionManagerRef = "flow_transactionManager",
        basePackages = {
                "com.xichuan.dev.flow.repository"
        }
    )
@EnableTransactionManagement
public class FlowDatabaseConfig {


    @Autowired
    @Qualifier("flow_databaseSource")
    private DataSource flowDataSource;

    @Autowired
    private JpaProperties jpaProperties;

    /**
     * 設定實現JPA實現的特定屬性
     * @return
     */
    @Bean
    //@Primary
    public JpaVendorAdapter jpaVendorAdapter() {
        HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
        adapter.setDatabase(Database.MYSQL);
        adapter.setShowSql(true);
        adapter.setGenerateDdl(true);
        adapter.setDatabasePlatform("org.hibernate.dialect.MySQL5Dialect");
        return adapter;
    }

    /**
     *實體管理
     * @param builder
     * @return
     */
    @Bean(name = "flow_entityManagerFactoryBean")
    @Primary
    public LocalContainerEntityManagerFactoryBean flowEntityManagerFactoryBean(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(flowDataSource)
                .properties(jpaProperties.getHibernateProperties(flowDataSource))
                .packages("com.xichuan.dev.flow.entity") //設定實體類所在位置
                .persistenceUnit("aPersistenceUnit")
                .build();
    }

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

    /**
     * 配置預設資料來源的事務
     * @param flowDataSource
     * @return
     */
    @Bean(name = "flow_transactionManager")
    public PlatformTransactionManager flowTransactionManager(@Qualifier("flow_databaseSource") DataSource flowDataSource) {
        return new DataSourceTransactionManager(flowDataSource);
    }

    /**
     * 配置JdbcOperations,可以使用JdbcOperations進行原生態的JDBC操作
     * @param flowDataSource
     * @return
     */
    @Bean(name = "flow_JdbcOperations")
    public JdbcOperations prodJdbcOperations(@Qualifier("flow_databaseSource") DataSource flowDataSource) {
        return new JdbcTemplate(flowDataSource);

        /**
         * 對JdbcOperations(是JdbcTemplate的抽象類)引用例子
         * @Autowired
         * @Qualifier("default_JdbcOperations")
         * private JdbcOperations jdbcOperations;
         *
         *
         * 對 JdbcOperations使用
         * jdbcOperations.execute(SQL);
         * */
    }
}

imap資料來源配置:

@Configuration
@EnableJpaRepositories
        (
                entityManagerFactoryRef="imap_entityManagerFactory",
                transactionManagerRef = "imap_transactionManager",
                basePackages = {
                        "com.xichuan.dev.imap.repository"
                }
        )
@EnableTransactionManagement
public class ImapDatabaseConfig {

    @Autowired
    @Qualifier("imap_databaseSource")
    private DataSource imapDataSource;

    @Autowired
    private JpaProperties jpaProperties;

    /**
     *實體管理
     * @param builder
     * @return
     */
    @Bean(name = "imap_entityManagerFactoryBean")
    public LocalContainerEntityManagerFactoryBean imapEntityManagerFactoryBean(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(imapDataSource)
                .properties(jpaProperties.getHibernateProperties(imapDataSource))
                .packages("com.xichaun.dev.imap.entity") //設定實體類所在位置
                .persistenceUnit("bPersistenceUnit")
                .build();
    }

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

    /**
     * 配置imap的jpa事務
     * @param builder
     * @return
     */
    @Bean(name = "imap_transactionManager")
    public PlatformTransactionManager writeTransactionManager(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(imapEntityManagerFactory(builder));
    }

}

配置完後,就可以在flow模組使用使用DAO、service,預設到的資料庫是db_flow庫查詢。imap預設到的資料庫是db_imap庫。

但如果要需要事務的話,需要在不同模組所需的方法上新增不同的事務。如在flow模組新增事務:

@Transactional("flow_transactionManager")
public Objetc init(String code, String content)throws Exception{
	...
	...
}