• 68685

    文章

  • 645

    评论

  • 65

    友链

  • 最近新加了换肤功能,大家多来逛逛吧~~~~
  • 喜欢这个网站的朋友可以加一下QQ群,我们一起交流技术。

Spring Boot Jpa多数据源配置

撸了今年阿里、腾讯和美团的面试,我有一个重要发现.......>>

前言

随着业务量发展,我们通常会进行数据库拆分或是引入其他数据库,从而我们需要配置多个数据源,如:user一个库,business一个库。那么接下来我们就要考虑怎么去在spring boot中实现多个数据源的配置。

实现

  • 建表
  • 首先是建表语句,我们要建立两个数据库,并各库内新建一张表
  • user表
mysql> use `user`;
mysql> select * from `user`;
+----+-------+----------+
| id | name  | password |
+----+-------+----------+
|  1 | 用户A | ******   |
+----+-------+----------+
1 row in set
  • business表
mysql> use `business`;
mysql> select * from `business`;
+----+-------+-------------+
| id | name  | description |
+----+-------+-------------+
|  1 | 业务A | 业务A描述   |
+----+-------+-------------+
1 row in set
  • 接下来我们通过代码实现对两个库内的多张表进行查询。
  • 配置
  • 首先,创建一个Spring配置类,定义两个DataSource用来读取application.yml中的不同配置。本文中,我们user做为主数据源,主数据源配置为spring.datasource.user开头的配置,business数据源配置为spring.datasource.business开头的配置。
@Configuration
public class DataSourceConfig {
    @Primary
    @Bean(name = "userDataSource")
    @Qualifier("userDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.user")
    public DataSource userDataSource() {
        return DataSourceBuilder.create().build();
    }
    @Bean(name = "businessDataSource")
    @Qualifier("businessDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.business")
    public DataSource businessDataSource() {
        return DataSourceBuilder.create().build();
    }
}
  • 对应的配置文件application.yml如下:
spring:
  datasource:
    user:
      driver-class-name: com.mysql.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/user
      username: root
      password: 123456
    business:
      driver-class-name: com.mysql.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/business
      username: root
      password: 123456
  • 接下来我们对各数据源进行jpa的配置
  • 主数据源User
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactoryUser",
        transactionManagerRef = "transactionManagerUser",
        //设置Repository所在位置
        basePackages = {"com.ppc.spring.example.jpamultidatasource.repository.user"})
public class UserConfig {
    @Autowired
    @Qualifier("userDataSource")
    private DataSource userDataSource;
    @Autowired
    private JpaProperties jpaProperties;
    @Autowired
    private HibernateProperties hibernateProperties;
    @Primary
    @Bean(name = "entityManagerUser")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return entityManagerFactoryUser(builder).getObject().createEntityManager();
    }
    @Primary
    @Bean(name = "entityManagerFactoryUser")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryUser(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(userDataSource)
                //设置entity所在位置
                .packages("com.ppc.spring.example.jpamultidatasource.entity.user")
                .persistenceUnit("userPersistenceUnit")
                .properties(getVendorProperties())
                .build();
    }
    private Map<String, Object> getVendorProperties() {
        return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
    }
    @Primary
    @Bean(name = "transactionManagerUser")
    public PlatformTransactionManager transactionManagerUser(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(entityManagerFactoryUser(builder).getObject());
    }
}
  • 其他数据源business
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactoryBusiness",
        transactionManagerRef = "transactionManagerBusiness",
        //设置repository所在位置
        basePackages = {"com.ppc.spring.example.jpamultidatasource.repository.business"})
public class BusinessConfig {
    @Autowired
    @Qualifier("businessDataSource")
    private DataSource businessDataSource;
    @Autowired
    private JpaProperties jpaProperties;
    @Autowired
    private HibernateProperties hibernateProperties;
    @Bean(name = "entityManagerBusiness")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return entityManagerFactoryBusiness(builder).getObject().createEntityManager();
    }
    @Bean(name = "entityManagerFactoryBusiness")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBusiness(EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(businessDataSource)
                .properties(getVendorProperties())
                //设置实体类所在位置
                .packages("com.ppc.spring.example.jpamultidatasource.entity.business")
                .persistenceUnit("businessPersistenceUnit")
                .build();
    }
    private Map<String, Object> getVendorProperties() {
        return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
    }
    @Bean(name = "transactionManagerBusiness")
    PlatformTransactionManager transactionManagerBusiness(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(entityManagerFactoryBusiness(builder).getObject());
    }
}
  • 配置中需要注意以下几点:
  • Spring Boot 1.5.x
private Map<String, String> getVendorProperties() {
  return jpaProperties.getHibernateProperties(userDataSource);
}
  • Spring Boot 2.0.x
private Map<String, Object> getVendorProperties() {
  return jpaProperties.getHibernateProperties(new HibernateSettings());
}
  • Spring Boot 2.1.0参见上文代码,引进了HibernateProperties。同时,在Spring Boot 2.1.0中默认的mysql-connector-java版本为8.0.13,连接低版本mysql配置上比较繁琐,建议在配置文件中手动指定相应版本,如本文中指定5.1.46这个版本。
runtimeOnly('mysql:mysql-connector-java:5.1.46')
  • repository、entity的所在位置,要和实际保存的位置一致。
  •  
  • 主数据源的一些配置需要添加@Primary作为spring默认的首选项,其他数据源无需添加该注解。
  •  
  • 通过查看相关源码我们看到Spring Boot中JpaProperties的代码一直在调整,这里我们将properties相关代码单独提取出作为一个单独的方法getVendorProperties展示版本间的区别。其中:
  • 查询
  • 完成了所有的配置,接下来我们就可以开始写个简单代码验证我们配置了
@RestController
@SpringBootApplication
public class JpaMultiDatasourceApplication {
    @Autowired
    UserRepository userRepository;
    @Autowired
    BusinessRepository businessRepository;
    public static void main(String[] args) {
        SpringApplication.run(JpaMultiDatasourceApplication.class, args);
    }
    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Long id) {
        return userRepository.findById(id).orElse(null);
    }
    @GetMapping("/business/{id}")
    public Business getBusiness(@PathVariable Long id) {
        return businessRepository.findById(id).orElse(null);
    }
}
  • 我们对外暴露了两个接口,分别访问user表、business表确认可以正常获取数据。查询结果如下:
请求:http://localhost:8080/user/1
结果:{"id":1,"name":"用户A","password":"******"}
请求:http://localhost:8080/business/1
结果:{"id":1,"name":"业务A","description":"业务A描述"}
  • 就此,我们双数据源的配置和验证工作就完成了。

 转载至链接:https://my.oschina.net/u/3959468/blog/2875232。

695856371Web网页设计师②群 | 喜欢本站的朋友可以收藏本站,或者加入我们大家一起来交流技术!

欢迎来到梁钟霖个人博客网站。本个人博客网站提供最新的站长新闻,各种互联网资讯。 还提供个人博客模板,最新最全的java教程,java面试题。在此我将尽我最大所能将此个人博客网站做的最好! 谢谢大家,愿大家一起进步!

转载原创文章请注明出处,转载至: 梁钟霖个人博客www.liangzl.com

1条评论

Loading...
  • samBC643L

    跟着blog做出现这个错误,请问博主你有遇到吗? Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}



发表评论

电子邮件地址不会被公开。 必填项已用*标注

自定义皮肤
注册梁钟霖个人博客