转载

spring+Jpa多数据源配置

Spring多数据源配置

今天临下班时遇到了一个需求,我的管理平台需要从不同的数据库中获取数据信息,这就需要进行Spring的多数据源配置,对于这种配置,第一次永远都是痛苦的,不过经历了这次的折磨,今后肯定会对这种配置印象深刻。我们这里简单回顾一下流程。

我们配置了两个数据库,一个是公司的数据库,另一个是我本地的一个数据库。首先是application.yml的配置(其中对于公司的数据库我们采取了假的地址,而本机的数据库是真是存在对应的表和库的)

数据库信息:

spring+Jpa多数据源配置

数据表信息:

spring+Jpa多数据源配置

1、application.yml

datasource:
    primary:
      url: jdbc:mysql://companyurl.com:5002/db1
      username: unameq
      password: passwd1
      driver-class-name: com.mysql.jdbc.Driver
    secondary:
      url: jdbc:mysql://localhost:3306/django_test
      username: root
      password: 123456
      driver-class-name: com.mysql.jdbc.Driver
  jpa:
    database-platform: org.hibernate.dialect.MySQL5Dialect
    hibernate:
      ddl-auto: update
      show-sql: true

2、创建总的DataSource配置文件以及两个Repostory的配置文件PrimaryConfig以及SecondaryConfig

  • DataSourceConfig
@Configuration
public class DataSourceConfig {
    @Bean(name = "primaryDataSource")
    @Qualifier("primaryDataSource")
    @ConfigurationProperties(prefix="spring.datasource.primary")//对应的数据库配置信息
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "secondaryDataSource")
    @Qualifier("secondaryDataSource")
    @Primary
    @ConfigurationProperties(prefix="spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }
}
  • PrimaryConfig
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef="entityManagerFactoryPrimary",
        transactionManagerRef="transactionManagerPrimary",
        basePackages= { "数据访问层所在的包" }) //设置Repository所在位置
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(primaryDataSource))
                .packages("实体类所在的包") //设置实体类所在位置
                .persistenceUnit("primaryPersistenceUnit")
                .build();
    }

    @Autowired
    private JpaProperties jpaProperties;

    private Map<String, String> getVendorProperties(DataSource dataSource) {
        return jpaProperties.getHibernateProperties(dataSource);
    }

    @Primary
    @Bean(name = "transactionManagerPrimary")
    public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
    }
}
  • SecondaryConfig
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef="entityManagerFactorySecondary",
        transactionManagerRef="transactionManagerSecondary",
        basePackages= { "数据访问层所在的包" }) //设置Repository所在位置
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(secondaryDataSource))
                .packages("实体类所在的包") //设置实体类所在位置
                .persistenceUnit("secondaryPersistenceUnit")
                .build();
    }

    @Autowired
    private JpaProperties jpaProperties;

    private Map<String, String> getVendorProperties(DataSource dataSource) {
        return jpaProperties.getHibernateProperties(dataSource);
    }

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

3、然后我对于本地数据库新建实体类PeoplePerson

@Entity
@Table(name = "people_person")
public class PeoplePerson implements Serializable {
    @Id
    @GeneratedValue
    private Integer id;

    @Column(name = "name")
    private String name;

    @Column(name = "age")
    private Integer age;

    public PeoplePerson() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "PeoplePerson{" +
                "id=" + id +
                ", name='" + name + '/'' +
                ", age=" + age +
                '}';
    }
}

并创建对应的Repositoy,PeoplePersonDao并创建了一个findAll的方法

@Transactional
@Repository
public interface PeoplePersonDao extends JpaRepository<PeoplePerson, Long> {
    List<PeoplePerson> findAll();
}

4、最后,在test包中进行测试

@Autowired
private PeoplePersonDao peoplePersonDao;
@Test
public void testMultiDataSource() {
   List<PeoplePerson> list = peoplePersonDao.findAll();
    for (int i = 0; i < list.size(); i++) {
        logger.info(list.get(i).toString());
    }
}

测试结果

spring+Jpa多数据源配置

一些坑

不仅仅是dao层扫描的包需要区分,对于实体类所在的包,不同的DataSource的配置中也需要区分开

对于这种套路性的东西,总结一遍是非常必要的,下次可以节省许多不必要的时间,对于内部原理,我将在完成对Ioc和Aop分析后反过来分析其原理。

谢谢你请我吃糖果

原文  https://bryantchang.github.io/2018/07/31/spring-multidatasource/
正文到此结束
Loading...