Spring Boot jpa多Repository(数据源)及读写分离

为了解决数据库瓶颈,分散数据库压力,读写分离经常被使用到。接下来我们就来谈一谈,在spring boot 中如何使用jpa进行读写分离。本文提供示例源码


在只有一个数据源的时候,我们可以很简单的使用有关JPA的自动配置来完成数据库操作。但是读写分离的时候显然我们至少要两个DataSource了,那么这些都是需要我们手动配置了,因为自动配置代码都是使用了条件注解的,我们手动配置之后就不再帮我们自动配置了。这个可以通过查看源码发现。



多Repository配置


我们通过springboot,spring data的官网及spring boot源码,可以看到Repository的自动配置过程及配置关键点。有三个比较关键的Bean就是DataSource/EntityManager/TransactionManager,再有就是Repository的接口类所在的包。这方面的配置大家可以在网上很轻松的搜索到,也可以查看文档及源码自己完成,参见github上对应源码. 关键代码:


 
 
  1.  @Bean

  2.  @Primary

  3.  @ConfigurationProperties("spring.datasource.write")

  4.  public DataSourceProperties writeDataSourceProperties() {

    扫描二维码关注公众号,回复: 120066 查看本文章
  5.  return new DataSourceProperties();

  6.  }

  7.  @Bean

  8.  @Primary

  9.  @ConfigurationProperties("spring.datasource.write")

  10.  public DataSource writeDataSource() {

  11.  return writeDataSourceProperties().initializeDataSourceBuilder().build();

  12.  }

  13.  @Bean

  14.  @Primary

  15.  public LocalContainerEntityManagerFactoryBean writeEntityManagerFactory(

  16.  EntityManagerFactoryBuilder builder, @Qualifier("writeDataSource"DataSource dataSource) {

  17.  return builder

  18.  .dataSource(dataSource)

  19.  .packages(User.class)

  20.  .properties(getVendorProperties(dataSource))

  21.  .persistenceUnit("write")

  22.  .build();

  23.  }

  24.  @Bean

  25.  @Primary

  26.  public PlatformTransactionManager writeTransactionManager(@Qualifier("writeEntityManagerFactory"LocalContainerEntityManagerFactoryBean writeEntityManagerFactory) {

  27.  JpaTransactionManager transactionManager = new JpaTransactionManager(writeEntityManagerFactory.getObject());

  28.  return transactionManager;

  29.  }



第一种方案

根据JPA多Repository的原理,我们可以知道,我们是可以通过配置扫描不同Repository接口类所在的包达到配置多Repository的目的。 这个这一点,第一种方案就很自然的可以想到。那就是通过接口继承的方式添加一个子接口,但是我们子接口里什么都不用操作,只维护原接口就可以了。这样我们让读的Repository扫描另外的Repository所在的包就可以轻松实现读写分离了。这种方案简单易实现,唯一的步骤就是多添加了一个接口。



第二种方案

如果是已经完成的项目,添加接口也有可能是非常庞大的一个工程。那么我们就可以利用第二种方案了。这是通过修改注册Bean时候的源码,让两次扫描到的Repository生成不同的名称注册到Spring容器当中,把原来的标记为Primary。通过源码我们可以发现生成Bean名称的类是 org.springframework.data.repository.config.RepositoryConfigurationDelegate.我们就拦截这个类中生成Bean名称的过程,把不同配置类扫描到的Repository使用不同的名称,虽然它们类型是一样的,我们可以通过名称限定来注入相应的Bean。我们可以添加一个自己的注解,用来给我们的配置类添加元信息。


自定义注解:

 
 
  1. /**

  2. * repository bean 名称的前缀

  3. */

  4. @Target(ElementType.TYPE)

  5. @Retention(RetentionPolicy.RUNTIME)

  6. @Documented

  7. @Inherited

  8. public @interface RepositoryBeanNamePrefix {

  9.  String value();

  10. }


修改RepositoryConfigurationDelegate,添加对应的逻辑:


 
 
  1. String beanName = configurationSource.generateBeanName(beanDefinition);

  2. AnnotationMetadata metadata = (AnnotationMetadata) configurationSource.getSource();

  3. //判断配置类是否使用primary进行了标注,如果有,就设为primary

  4. if(metadata.hasAnnotation(Primary.class.getName())){

  5.  beanDefinition.setPrimary(true);

  6. }else if(metadata.hasAnnotation(RepositoryBeanNamePrefix.class.getName())){

  7.  // 再判断是否使用了RepositoryBeanNamePrefix进行了标注,如果有,添加名称前缀

  8.  Map<String,Object> prefixData = metadata.getAnnotationAttributes(RepositoryBeanNamePrefix.class.getName());

  9.  String prefix = (String) prefixData.get("value");

  10.  beanName = prefix + beanName;

  11. }


配置多个Repository扫描的配置类:

 
 
  1.  @EnableJpaRepositories(basePackageClasses = UserRepository.class,

  2.  entityManagerFactoryRef = "writeEntityManagerFactory", transactionManagerRef = "writeTransactionManager")

  3.  @Primary

  4.  public class WriteConfiguration {

  5.  }

  6.  @EnableJpaRepositories(basePackageClasses = UserRepository.class,

  7.  entityManagerFactoryRef = "readEntityManagerFactory", transactionManagerRef = "readTransactionManager")

  8.  @RepositoryBeanNamePrefix("second")

  9.  public class SameRepositoryWriteConfiguration {

  10.  }


使用时我们可以通过名称注入的方式,使用读Repository:


 
 
  1. @RestController

  2. @RequestMapping("/user")

  3. public class UserController {

  4.  @Autowired

  5.  private UserRepository userRepository;

  6.  @Autowired

  7.  private UserReadRepository readRepository;

  8.  @Autowired

  9.  @Qualifier("seconduserRepository")

  10.  private UserRepository seconduserRepository;

  11. }


这样就达到我们读写分离的目的了。



总结


本文提供了Jpa多Repository连接多数据源的实现方式,及两种读写分离方案。以上列出的只是关键代码,很难通过语言完整详细的描述整个过程。大家如果有什么疑问,欢迎讨论,最好还是下载示例代码自己看看代码也许会清楚很多。


示例代码 下载完后可以直接运行。因为数据库使用的时内存数据库h2,可以换成自己使用的数据库。



互联网金融是当下非常流行的热点领域。


作为一个紧跟时代的程序员,如果你对互联网金融领域感兴趣却不知如何进入,那这门课程就是你入行的加速器,能让你积累实际项目经验,提供技术综合运用能力!


猜你喜欢

转载自blog.csdn.net/u012382336/article/details/80217235
今日推荐