前言:

近期公司要上线3.0版本,需要将2.0的数据迁移到3.0中继续沿用,由于3.0的数据库相比2.0.的数据库改动很大,最主要的是2.0数据库的主键为自然数自增主键,而3.0数据库的主键为UUID2,所以只能使用程序动态迁移!

声明:

本教程使用的持久化框架为JPA,所以数据源也是基于JPA。采用的是SpringBoot2 + SpringDataJPA + MySQL + 双数据源!

一、双数据源的适用场景:

1、主从库分离(数据库读写分离)

2、数据迁移

3、系统版本升级,数据库升级到另外一款

二、application.yml中配置

spring:
  jpa:
    hibernate:
      ddl-auto: create
      naming:
        physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
        implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
    open-in-view: true
    show-sql: true
    generate-ddl: true


  datasource: #database
    primary:  # 3.0 Datasource
      jdbc-url: jdbc:mysql://127.0.0.1:3306/gtu?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
      username: root
      password: 123456

    secondary:  # 2.0 Datasource
      jdbc-url: jdbc:mysql://127.0.0.1:3306/gtu-not-completed?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
      username: root
      password: 123456

注:配置文件中需要指定两个数据源,这里在配置的时候是没有自动提示的,因为这是我们自定义的,需要在程序中动态读取。

三、读取application.yml配置的两个数据源,并将其注入到Spring的IOC容器中

@Configuration
public class DataSourceConfig {


    @Bean(name = "primaryDataSource")
    @Qualifier("primaryDataSource")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "secondaryDataSource")
    @Qualifier("secondaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

}

注解解释:

@Configuration:SpringBoot启动将该类作为配置类,同配置文件一起加载

@Bean:将该实体注入到IOC容器中

@Qualifier:指定数据源名称,与Bean中的name属性原理相同,主要是为了确保注入成功

@Primary:指定主数据源

@ConfigurationProperties:将配置文件中的数据源读取进到方法中,进行build

四、以类的方式配置两个数据源

(1)主数据源(对应DataSourceConfig类中的primaryDataSource)

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactoryPrimary",
        transactionManagerRef = "transactionManagerPrimary",
        basePackages = {"com.gtcloud.repository"})    // 指定该数据源操作的DAO接口包
public class PrimaryConfig {

    @Autowired
    @Qualifier("primaryDataSource")
    private DataSource primaryDataSource;

    @Primary
    @Bean(name = "entityManagerPrimary")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
    }

    @Primary
    @Bean(name = "entityManagerFactoryPrimary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(primaryDataSource)
                .properties(getVendorProperties())
                .packages("com.gtcloud.model")         //设置实体类所在位置
                .persistenceUnit("primaryPersistenceUnit")
                .build();
    }

    private Map getVendorProperties() {
        HashMap<String, Object> properties = new HashMap<>();
        properties.put("hibernate.dialect",
                env.getProperty("hibernate.dialect"));
        properties.put("hibernate.ddl-auto",
                "create");
        properties.put("hibernate.physical_naming_strategy",
                "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
        properties.put("hibernate.implicit_naming_strategy",
                "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
        return properties;
    }

    @Autowired
    private Environment env;

    @Primary
    @Bean(name = "transactionManagerPrimary")
    public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
    }

}

 

(2)从(次)数据源

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactorySecondary",
        transactionManagerRef = "transactionManagerSecondary",
        basePackages = {"com.gtmove.repository"}) //设置DAO接口层所在包位置
public class SecondaryConfig {

    @Autowired
    @Qualifier("secondaryDataSource")
    private DataSource secondaryDataSource;

    @Bean(name = "entityManagerSecondary")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return entityManagerFactorySecondary(builder).getObject().createEntityManager();
    }

    @Bean(name = "entityManagerFactorySecondary")
    public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(secondaryDataSource)
                .properties(getVendorProperties())
                .packages("com.gtmove.model")        //设置实体类所在包的位置
                .persistenceUnit("primaryPersistenceUnit")
                .build();
    }

    private Map getVendorProperties() {
        HashMap<String, Object> properties = new HashMap<>();
        properties.put("hibernate.hbm2ddl.auto",
                env.getProperty("hibernate.hbm2ddl.auto"));
        properties.put("hibernate.ddl-auto",
                env.getProperty("update"));
        properties.put("hibernate.dialect",
                env.getProperty("hibernate.dialect"));
        properties.put("hibernate.physical_naming_strategy",
                "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
        properties.put("hibernate.implicit_naming_strategy",
                "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
        return properties;
    }

    @Autowired
    private Environment env;

    @Bean(name = "transactionManagerSecondary")
    PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());
    }
}

这两个类主要配置每个数据源,包括事务管理器、以及实体管理器等配置。

注:必须要指定DAO接口所在的包以及实体类所在的包。每个数据源主要操作它指定的资源(DAO接口CURD、实体类)

五、注意点:

1、SpringBoot启动类必须关闭 --程序启动加载的仓库(@EnableJpaRepositories),因为在数据源配置类中已经开启了。如果没有去掉,程序会跑不起来!

@SpringBootApplication(scanBasePackages = {""})  // 指定加载程序主包,存在默认值【可选】
//@EntityScan({""})
//@EnableJpaRepositories(basePackages = {""})
public class Gt3datamoverApplication {

    public static void main(String[] args) {
        SpringApplication.run(Gt3datamoverApplication.class, args);
    }

}

2、如果需要对数据源连接的表进行DDL(正向生成表、程序启动动态更新表),需要在PrimaryConfig类中 / SecondaryConfig类中的getVendorProperties()方法中进行手动设置(此教程都已设置好了!)

六、在整合双数据源有问题的,欢迎加博主QQ:1402218191 !

Logo

更多推荐