栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java > SpringBoot

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

SpringBoot 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

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

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

多Repository配置

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

   @Bean
    @Primary
    @ConfigurationProperties("spring.datasource.write")
    public DataSourceProperties writeDataSourceProperties() {
 return new DataSourceProperties();
    }

    @Bean
    @Primary
    @ConfigurationProperties("spring.datasource.write")
    public DataSource writeDataSource() {
 return writeDataSourceProperties().initializeDataSourceBuilder().build();
    }

    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean writeEntityManagerFactory(
     EntityManagerFactoryBuilder builder, @Qualifier("writeDataSource") DataSource dataSource) {
 return builder
  .dataSource(dataSource)
  .packages(User.class)
  .properties(getVendorProperties(dataSource))
  .persistenceUnit("write")
  .build();
    }

    @Bean
    @Primary
    public PlatformTransactionManager writeTransactionManager(@Qualifier("writeEntityManagerFactory") LocalContainerEntityManagerFactoryBean writeEntityManagerFactory) {
 JpaTransactionManager transactionManager = new JpaTransactionManager(writeEntityManagerFactory.getObject());
 return transactionManager;
    }
第一种方案

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

第二种方案

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

自定义注解:


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@Inherited
public @interface RepositoryBeanNamePrefix {
    String value();
}

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

String beanName = configurationSource.generateBeanName(beanDefinition);

Annotationmetadata metadata = (Annotationmetadata) configurationSource.getSource();

//判断配置类是否使用primary进行了标注,如果有,就设为primary
if(metadata.hasAnnotation(Primary.class.getName())){
    beanDefinition.setPrimary(true);
}else  if(metadata.hasAnnotation(RepositoryBeanNamePrefix.class.getName())){
    // 再判断是否使用了RepositoryBeanNamePrefix进行了标注,如果有,添加名称前缀
    Map prefixData = metadata.getAnnotationAttributes(RepositoryBeanNamePrefix.class.getName());
    String prefix = (String) prefixData.get("value");
    beanName = prefix + beanName;
}

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

    @EnableJpaRepositories(basePackageClasses = UserRepository.class,
     entityManagerFactoryRef = "writeEntityManagerFactory", transactionManagerRef = "writeTransactionManager")
    @Primary
    public class WriteConfiguration {
    }

    @EnableJpaRepositories(basePackageClasses = UserRepository.class,
     entityManagerFactoryRef = "readEntityManagerFactory", transactionManagerRef = "readTransactionManager")
    @RepositoryBeanNamePrefix("second")
    public class SameRepositoryWriteConfiguration {
    }

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

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private UserReadRepository readRepository;

    @Autowired
    @Qualifier("seconduserRepository")
    private UserRepository seconduserRepository;
}

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

总结

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

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

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号