Мультитенанс с пружинным диваном - PullRequest
0 голосов
/ 15 октября 2018

Фон

Я создаю приложение для пружин, в котором есть несколько ковшей для диванов.Главный сегмент содержит данные о конфигурации других арендаторов, а остальные наборы относятся к арендатору / клиенту и используют одни и те же DAO, службы.

Проблема

Я хочу сохранять / извлекать документы в / из определенных сегментов арендатора, но база данных данных Spring имеет статическую природу и не позволяет динамически привязывать сегменты к репозиториям или переключаться между группамиво время выполнения.Есть ли способ динамически отображать / привязывать корзину к хранилищу в весенней базе данных?

Конфигурация

Я инициализирую 3 шаблона арендаторов, устанавливая мастер по умолчанию и хочу переключаться между двумя другими на основе арендаторов во время выполнения.

@Configuration
@EnableCouchbaseRepositories(basePackages = {"com.user"})
@EnableCouchbaseAuditing
public class CouchbaseMultiBucketConfig extends AbstractCouchbaseConfiguration {

private static final String ACCESS_FAILED = "Failed to access bucket template: ";

@Value("${bucket.master.name}")
private String masterBucketName;
@Value("${bucket.master.password}")
private String masterBucketPassword;
@Value("${bucket.master.host:#{null}}")
private String masterBucketHost;

@Value("${bucket.tenant1.name}")
private String tenant1BucketName;
@Value("${bucket.tenant1.password}")
private String tenant1BucketPassword;
@Value("${bucket.tenant1.host:#{null}}")
private String tenant1BucketHost;

@Value("${bucket.tenant2.name}")
private String tenant2BucketName;
@Value("${bucket.tenant2.password}")
private String tenant2ucketPassword;
@Value("${bucket.tenant2.host:#{null}}")
private String tenant2ucketHost;

@Value("${cb.hosts}")
private String hosts;

@Bean
@Qualifier("tenant1")
public Bucket tenant1Bucket() {
    return openBucket(tenant1BucketName, tenant1BucketPassword, tenant1BucketHost);
}

@Bean
@Qualifier("tenant2")
public Bucket tenant1Bucket() {
    return openBucket(tenant2BucketName, tenant2BucketPassword, tenant2BucketHost);
}

@Bean
@Qualifier("master")
public Bucket masterBucket() {
    return openBucket(masterBucketName, masterBucketPassword, masterBucketHost);
}

@Bean
@Qualifier("masterTemplate")
public CouchbaseTemplate masterTemplate() {
    try {
        final CouchbaseTemplate template = new CouchbaseTemplate(
                couchbaseClusterInfo(), //reuse the default bean
                masterBucket(), //the bucket is non-default
                mappingCouchbaseConverter(), translationService() //default beans here as well
        );
        template.setDefaultConsistency(getDefaultConsistency());
        return template;
    } catch (Exception ex) {
        throw new IllegalStateException(ACCESS_FAILED, ex);
    }
}

@Bean
@Qualifier("tenant1Template")
public CouchbaseTemplate tenant1Template() {
    try {
        final CouchbaseTemplate template = new CouchbaseTemplate(
                couchbaseClusterInfo(), //reuse the default bean
                tenant1Bucket(), //the bucket is non-default
                mappingCouchbaseConverter(), translationService() //default beans here as well
        );
        template.setDefaultConsistency(getDefaultConsistency());
        return template;
    } catch (Exception ex) {
        throw new IllegalStateException(ACCESS_FAILED, ex);
    }
}

@Bean
@Qualifier("tenant2Template")
public CouchbaseTemplate tenant2Template() {
    try {
        final CouchbaseTemplate template = new CouchbaseTemplate(
                couchbaseClusterInfo(), //reuse the default bean
                tenant2Bucket(), //the bucket is non-default
                mappingCouchbaseConverter(), translationService() //default beans here as well
        );
        template.setDefaultConsistency(getDefaultConsistency());
        return template;
    } catch (Exception ex) {
        throw new IllegalStateException(ACCESS_FAILED, ex);
    }
}

private Bucket openBucket(final String bucketName, final String bucketPassword, final String alternativeHost)
        throws IllegalStateException {
    try {
        return couchbaseCluster(alternativeHost).openBucket(bucketName, bucketPassword);
    } catch (Exception ex) {
        throw new IllegalStateException("Failed to open bucket " + bucketName, ex);
    }
}


@Override
public void configureRepositoryOperationsMapping(final RepositoryOperationsMapping baseMapping) {
    baseMapping.setDefault(masterTemplate());
}

@Override
protected List<String> getBootstrapHosts() {
    return parse(hosts);
}

@Override
protected String getBucketName() {
    return tenant1BucketName;
}

@Override
protected String getBucketPassword() {
    return tenant1BucketPassword;
}

private List<String> parse(final String hosts) {
    return Arrays.asList(hosts.split(","))
            .stream().map(in -> in.trim()).collect(Collectors.toList());
}

}

Хранилище

@Repository
public interface UserRepository extends CouchbaseRepository<User, String> {

User getByDocKey(final String docKey);

@Query("#{#n1ql.selectEntity} WHERE tenantId= $1")
List<User> findByTenantId(String tenantId);

}

Спасибо

1 Ответ

0 голосов
/ 15 октября 2018

Простой ответ

Похоже, это можно сделать, но это не тривиально.https://forums.couchbase.com/t/spring-couchbase-multiple-buckets/16984

Длинный ответ

Вы отправляете в базу данных что-то, что должно обрабатываться вашим приложением.Если у вас возникла такая проблема, это, вероятно, означает, что у вас должно быть одно ведро для обслуживания всех ваших клиентов.В конце концов, использование этого подхода не позволит вам обслуживать 100 клиентов.

PS: с помощью n1ql вы все еще можете легко переключаться между сегментами и даже использовать несколько блоков в одном запросе.

...