spring+Jpa多数据源配置的方法示例

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

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

数据库信息:

数据表信息:

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@Repositorypublic 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());
 }
}

测试结果

 一些坑

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

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。

声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:notice#nhooo.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。