【问题标题】:Avoiding code repetition on multischema database避免多模式数据库上的代码重复
【发布时间】:2019-10-05 03:10:31
【问题描述】:

我有一个带有数据库的遗留应用程序,该数据库将数据拆分为同一物理数据库上的多个模式。这些模式在结构上是相同的。

我使用一个使用 Spring Boot Data JPA 的微服务来处理单个模式。然后为了避免代码重复,我创建了一个路由器服务,将请求转发到单个模式微服务副本,每个副本都有不同的数据库连接。但我发现这有点矫枉过正(但有效)

我正在尝试将其缩减为单个微服务。我还没有成功,但我使用schema 属性设置了表。

@Table(
    name = "alerts",
    schema = "ca"
)

但是,当我尝试进行继承和@MappedSuperclass 以减少代码重复时,它会感到困惑。

此外,@OneToMany 会因为继承错误而分崩离析,例如 X references an unknown entity: Y

基本上有一种在 JPA 上使用继承的方法,它使用相同的表结构,不同之处只是模式,无需复制和粘贴太多代码。理想情况下,我只想将“模式”参数传递给 DAO,它会以某种方式为我做到这一点。

【问题讨论】:

    标签: spring jpa spring-data microservices


    【解决方案1】:

    最后,我们只需要一个可以根据情况进行路由的数据源。为此,使用了扩展 AbstractRoutingDataSource@Component,并使用了 ThreadLocal 来存储请求上下文。

    ThreadLocal 是这样的(示例使用 Lombok)

    @AllArgsConstructor
    public class UserContext {
        private static final ThreadLocal<UserContext> context =
            new ThreadLocal<>();
        private final String schema;
    
        public static String getSchema() {
            return context.get().schema;
        }
    
        public static void setFromXXX(...) {
            context.set(new UserContext(
                ...
            ));
        }
    }
    

    需要数据源的来源:

    @Configuration
    public class DataSources {
    
        @Bean
        public DataSource schema1() {
            return build("schema1");
        }
    
        @Bean
        public DataSource schema2() {
            return build("schema2");
        }
    
        private DataSource buildDataSource(String schema) {
            ...
            return new DriverManagerDataSource(url, username, password);
        }
    }
    

    最后是被标记为@Primary 数据源的路由器,以确保它是被 JPA 使用的那个。

    @Component
    @Primary
    public class RoutingDatasource extends AbstractRoutingDataSource {
        @Autowired
        @Qualifier("schema1")
        private DataSource schema1;
    
        @Autowired
        @Qualifier("schema2")
        private DataSource schema2;
    
        @Override
        public void afterPropertiesSet() {
            setTargetDataSources(
                Map.of(
                    "schema1", schema1,
                    "schema2", schema2
                )
            );
            super.afterPropertiesSet();
        }
    
        @Override
        protected Object determineCurrentLookupKey() {
            return UserContext.getSchema();
        }
    }
    

    这避免了当唯一不同的是架构甚至数据源时的代码重复。

    【讨论】:

      猜你喜欢
      • 2021-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-07
      • 2012-06-28
      • 1970-01-01
      相关资源
      最近更新 更多