Spring Data JPA 多数据源并支持多数据源事务

application.yml 配置

com.seliote.twowaysync:
  datasource:
    zg:
      url: jdbc:mysql://192.168.0.1:3306/jd4?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true
      username: root
      password: 6125@hdynhjs
      driver: com.mysql.cj.jdbc.Driver
      hikari:
        maximum-pool-size: 200
        connection-timeout: 5000
        max-lifetime: 1800000
        minimum-idle: 5
        idle-timeout: 300000
        connection-test-query: SELECT 1
        dialect: org.hibernate.dialect.MySQLInnoDBDialect
    jd:
      url: jdbc:mysql://192.168.0.1:3306/jd3?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true
      username: root
      password: 6125@hdynhjs
      driver: com.mysql.cj.jdbc.Driver
      hikari:
        maximum-pool-size: 200
        connection-timeout: 5000
        max-lifetime: 1800000
        minimum-idle: 5
        idle-timeout: 300000
        connection-test-query: SELECT 1
        dialect: org.hibernate.dialect.MySQLInnoDBDialect
    tws:
      url: jdbc:mysql://192.168.0.1:3306/tws?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true
      username: root
      password: 6125@hdynhjs
      driver: com.mysql.cj.jdbc.Driver
      hikari:
        maximum-pool-size: 200
        connection-timeout: 5000
        max-lifetime: 1800000
        minimum-idle: 5
        idle-timeout: 300000
        connection-test-query: SELECT 1
        dialect: org.hibernate.dialect.MySQLInnoDBDialect

对应的配置注入类:

package com.seliote.twowaysync.config;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * Yaml 配置
 *
 * @author Li Yangdi
 * @since 2022-04-16
 */
@Slf4j
@Getter
@Setter
@Component
@ConfigurationProperties(prefix = "com.seliote.twowaysync")
public class YmlConfig {

    private DatasourceConfig datasource = new DatasourceConfig();
    private ThreadPoolConfig threadPool = new ThreadPoolConfig();

    @Getter
    @Setter
    public static class DatasourceConfig {
        private DatasourceItemConfig zg = new DatasourceItemConfig();
        private DatasourceItemConfig jd = new DatasourceItemConfig();
        private DatasourceItemConfig tws = new DatasourceItemConfig();

        @Getter
        @Setter
        public static class DatasourceItemConfig {
            private String url;
            private String username;
            private String password;
            private String driver;
            private HikariConfig hikari;
        }

        @Getter
        @Setter
        public static class HikariConfig {
            private Integer maximumPoolSize;
            private Long connectionTimeout;
            private Long maxLifetime;
            private Integer minimumIdle;
            private Long idleTimeout;
            private String connectionTestQuery;
            private String dialect;
        }
    }

    @Getter
    @Setter
    public static class ThreadPoolConfig {
        private Integer poolSize;
    }
}

数据源相关工具类

package com.seliote.twowaysync.util;

import com.seliote.twowaysync.config.YmlConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;

import javax.persistence.EntityManagerFactory;
import javax.persistence.SharedCacheMode;
import javax.persistence.ValidationMode;
import javax.sql.DataSource;
import java.util.HashMap;

/**
 * 数据源工具
 *
 * @author Li Yangdi
 * @since 2022-04-16
 */
@Slf4j
public class DatasourceUtils {

    /**
     * 创建 HikariDataSource
     *
     * @param dataName 数据名
     * @param config   配置
     * @return HikariDataSource 对象
     */
    public static HikariDataSource getDataSource(String dataName,
                                                 YmlConfig.DatasourceConfig.DatasourceItemConfig config) {
        var hikariConfig = new com.zaxxer.hikari.HikariConfig();
        hikariConfig.setPoolName("[" + dataName.toUpperCase() + "-HIKARI-POOL]");
        hikariConfig.setJdbcUrl(config.getUrl());
        hikariConfig.setUsername(config.getUsername());
        hikariConfig.setPassword(config.getPassword());
        hikariConfig.setDriverClassName(config.getDriver());
        hikariConfig.setMaximumPoolSize(config.getHikari().getMaximumPoolSize());
        hikariConfig.setConnectionTimeout(config.getHikari().getConnectionTimeout());
        hikariConfig.setMaxLifetime(config.getHikari().getMaxLifetime());
        hikariConfig.setMinimumIdle(config.getHikari().getMinimumIdle());
        hikariConfig.setIdleTimeout(config.getHikari().getIdleTimeout());
        hikariConfig.setConnectionTestQuery(config.getHikari().getConnectionTestQuery());
        var hikariDatasource = new HikariDataSource(hikariConfig);
        log.debug("Create {} datasource", dataName);
        return hikariDatasource;
    }

    /**
     * 创建 EntityManagerFactory
     *
     * @param dataSource   数据源 Datasource
     * @param dialect      Hibernate 方言
     * @param scanPackages 扫描的包
     * @return LocalContainerEntityManagerFactoryBean 对象
     */
    public static LocalContainerEntityManagerFactoryBean getEntityManagerFactory(DataSource dataSource,
                                                                                 String dialect,
                                                                                 String... scanPackages) {
        var props = new HashMap<String, Object>();
        props.put("javax.persistence.schema-generation.database.action", "none");
        var jpaVendorAdapter = new HibernateJpaVendorAdapter();
        jpaVendorAdapter.setDatabasePlatform(dialect);
        var entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter);
        entityManagerFactory.setDataSource(dataSource);
        entityManagerFactory.setPackagesToScan(scanPackages);
        entityManagerFactory.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE);
        entityManagerFactory.setValidationMode(ValidationMode.NONE);
        entityManagerFactory.setJpaPropertyMap(props);
        log.debug("Create EntityManagerFactory for '{}' by dialect {}",
                String.join(", ", scanPackages), dialect);
        return entityManagerFactory;
    }

    /**
     * 创建 PlatformTransactionManager
     *
     * @param entityManagerFactory EntityManagerFactory 对象
     * @return PlatformTransactionManager 对象
     */
    public static PlatformTransactionManager getTransactionManager(EntityManagerFactory entityManagerFactory) {
        log.debug("Create TransactionManager");
        return new JpaTransactionManager(entityManagerFactory);
    }
}

数据源 1

package com.seliote.twowaysync.config;

import com.seliote.twowaysync.util.DatasourceUtils;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AdviceMode;
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.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * 机电数据源
 *
 * @author Li Yangdi
 * @since 2022-04-16
 */
@Configuration
@EnableTransactionManagement(mode = AdviceMode.PROXY)
@EnableJpaRepositories(
        basePackages = {"com.seliote.twowaysync.repo.jd"},
        entityManagerFactoryRef = "jdEntityManagerFactory",
        transactionManagerRef = "jdTransactionManager"
)
public class JdDataSourceConfig {

    private YmlConfig.DatasourceConfig.DatasourceItemConfig jdDatasourceConfig;

    @Autowired
    public void setDatasourceItemConfig(YmlConfig ymlConfig) {
        this.jdDatasourceConfig = ymlConfig.getDatasource().getJd();
    }

    /**
     * 综管 Datasource Bean
     *
     * @return HikariDataSource 对象
     */
    @Primary
    @Bean(name = "jdDataSource")
    public HikariDataSource jdDataSource() {
        return DatasourceUtils.getDataSource("jd", jdDatasourceConfig);
    }

    /**
     * 综管 EntityManagerFactory Bean
     *
     * @return LocalContainerEntityManagerFactoryBean 对象
     */
    @Primary
    @Bean(name = "jdEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean jdEntityManagerFactory() {
        return DatasourceUtils.getEntityManagerFactory(jdDataSource(),
                jdDatasourceConfig.getHikari().getDialect(),
                "com.seliote.twowaysync.entity.jd");
    }

    /**
     * 综管 PlatformTransactionManager Bean
     *
     * @return PlatformTransactionManager 对象
     */
    @Primary
    @Bean("jdTransactionManager")
    public PlatformTransactionManager jdTransactionManager() {
        return DatasourceUtils.getTransactionManager(jdEntityManagerFactory().getObject());
    }
}

数据源 2

package com.seliote.twowaysync.config;

import com.seliote.twowaysync.util.DatasourceUtils;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AdviceMode;
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.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * 综管数据源
 *
 * @author Li Yangdi
 * @since 2022-04-16
 */
@Configuration
@EnableTransactionManagement(mode = AdviceMode.PROXY)
@EnableJpaRepositories(
        basePackages = {"com.seliote.twowaysync.repo.zg"},
        entityManagerFactoryRef = "zgEntityManagerFactory",
        transactionManagerRef = "zgTransactionManager"
)
public class ZgDataSourceConfig {

    private YmlConfig.DatasourceConfig.DatasourceItemConfig zgDatasourceConfig;

    @Autowired
    public void setDatasourceItemConfig(YmlConfig ymlConfig) {
        this.zgDatasourceConfig = ymlConfig.getDatasource().getZg();
    }

    /**
     * 综管 Datasource Bean
     *
     * @return HikariDataSource 对象
     */
    @Bean(name = "zgDataSource")
    public HikariDataSource zgDataSource() {
        return DatasourceUtils.getDataSource("zg", zgDatasourceConfig);
    }

    /**
     * 综管 EntityManagerFactory Bean
     *
     * @return LocalContainerEntityManagerFactoryBean 对象
     */
    @Bean(name = "zgEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean zgEntityManagerFactory() {
        return DatasourceUtils.getEntityManagerFactory(zgDataSource(),
                zgDatasourceConfig.getHikari().getDialect(),
                "com.seliote.twowaysync.entity.zg");
    }

    /**
     * 综管 PlatformTransactionManager Bean
     *
     * @return PlatformTransactionManager 对象
     */
    @Bean("zgTransactionManager")
    public PlatformTransactionManager zgTransactionManager() {
        return DatasourceUtils.getTransactionManager(zgEntityManagerFactory().getObject());
    }
}

数据源 3:

package com.seliote.twowaysync.config;

import com.seliote.twowaysync.util.DatasourceUtils;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AdviceMode;
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.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * 双向同步数据源
 *
 * @author Li Yangdi
 * @since 2022-04-18
 */
@Configuration
@EnableTransactionManagement(mode = AdviceMode.PROXY)
@EnableJpaRepositories(
        basePackages = {"com.seliote.twowaysync.repo.tws"},
        entityManagerFactoryRef = "twsEntityManagerFactory",
        transactionManagerRef = "twsTransactionManager"
)
public class TwsDataSourceConfig {

    private YmlConfig.DatasourceConfig.DatasourceItemConfig twsDatasourceConfig;

    @Autowired
    public void setDatasourceItemConfig(YmlConfig ymlConfig) {
        this.twsDatasourceConfig = ymlConfig.getDatasource().getTws();
    }

    /**
     * 综管 Datasource Bean
     *
     * @return HikariDataSource 对象
     */
    @Bean(name = "twsDataSource")
    public HikariDataSource twsDataSource() {
        return DatasourceUtils.getDataSource("tws", twsDatasourceConfig);
    }

    /**
     * 综管 EntityManagerFactory Bean
     *
     * @return LocalContainerEntityManagerFactoryBean 对象
     */
    @Bean(name = "twsEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean twsEntityManagerFactory() {
        return DatasourceUtils.getEntityManagerFactory(twsDataSource(),
                twsDatasourceConfig.getHikari().getDialect(),
                "com.seliote.twowaysync.entity.tws");
    }

    /**
     * 综管 PlatformTransactionManager Bean
     *
     * @return PlatformTransactionManager 对象
     */
    @Bean("twsTransactionManager")
    public PlatformTransactionManager twsTransactionManager() {
        return DatasourceUtils.getTransactionManager(twsEntityManagerFactory().getObject());
    }
}

不同包下的不同实体不同仓库,自动使用不同数据源

posted @ 2022-04-18 17:38  seliote  阅读(144)  评论(0)    收藏  举报