Клиентская библиотека Azure Spring Data Cosmos для Java

Azure Spring Data Cosmos обеспечивает поддержку Spring Data для Azure Cosmos DB с помощью API SQL, основанного на платформе Spring Data. Azure Cosmos DB — это глобально распределенная служба баз данных, предоставляющая разработчикам возможность работать с данными с помощью разных стандартных API, например SQL, MongoDB, Cassandra, Graph и таблиц.

Поддержка версий Spring Data

Этот проект поддерживает версии spring-data-commons 2.2.x и spring-data-commons 2.3.x. Пользователи Maven могут использовать наследование от проекта spring-boot-starter-parent, чтобы получить раздел управления зависимостями, позволяющий Spring управлять версиями для зависимостей.

<!-- Inherit defaults from Spring Boot -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>${spring.boot.version}</version>
</parent>

С помощью этой настройки вы можете также переопределить отдельные зависимости, переопределив свойство в своем проекте. Например, чтобы выполнить обновление до другой цепочки выпуска Spring Data, необходимо добавить приведенный ниже код в pom.xml.

<properties>
    <spring-data-releasetrain.version>${spring.data.version}</spring-data-releasetrain.version>
</properties>

Если вы не хотите использовать spring-boot-starter-parent, то можете сохранить преимущество управления зависимостями с помощью зависимости scope=import:

<dependencyManagement>
     <dependencies>
        <dependency>
            <!-- Import dependency management from Spring Boot -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring.boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Эта конфигурация не позволяет переопределять отдельные зависимости с помощью свойства, как описано выше. Чтобы добиться того же результата, необходимо добавить запись в dependencyManagement проекта перед записью spring-boot-dependencies. Например, чтобы выполнить обновление до другой цепочки выпуска Spring Data, необходимо добавить приведенный ниже код в pom.xml.

<dependencyManagement>
    <dependencies>
        <!-- Override Spring Data release train provided by Spring Boot -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-releasetrain</artifactId>
            <version>${spring.data.version}</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring.boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Примечание

Замените ${spring.boot.version} и ${spring.data.version} версиями Spring Boot и Spring Data, которые вы хотите использовать в проекте.

Начало работы

Включение пакета

Если вы используете Maven, добавьте следующую зависимость:

<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-spring-data-cosmos</artifactId>
    <version>3.9.0</version>
</dependency>

Предварительные требования

  • Пакет средств разработки для Java (JDK) версии 8 или более поздней.
  • Активная учетная запись Azure. Если у вас ее нет, зарегистрируйте бесплатную учетную запись. Кроме того, вы можете использовать эмулятор Azure Cosmos DB для разработки и тестирования. Так как HTTPS-сертификат эмулятора является самозаверяющим, необходимо импортировать его сертификат в хранилище доверенных сертификатов Java, как описано здесь.
  • (Необязательно) SLF4J — это интерфейс для ведения журнала.
  • (Необязательно) Привязка SLF4J используется для связывания определенной платформы ведения журналов с SLF4J.
  • (Необязательно) Maven.

SLF4J требуется только в том случае, если вы планируете использовать ведение журнала. В таком случае вам также понадобится скачать привязку SLF4J, которая свяжет API SLF4J с выбранной реализацией ведения журнала. Дополнительные сведения см. в руководстве пользователя по SLF4J.

Настройка класса конфигурации

Чтобы настроить класс конфигурации, необходимо расширить AbstractCosmosConfiguration.

Azure-spring-data-cosmos также поддерживает Response Diagnostics String и Query Metrics. Установите для флага queryMetricsEnabled значение true в application.properties, чтобы включить метрики запросов. Помимо установки флага реализуйте ResponseDiagnosticsProcessor для записи диагностической информации.

@Configuration
@EnableCosmosRepositories
public class AppConfiguration extends AbstractCosmosConfiguration {

    private static final Logger LOGGER = LoggerFactory.getLogger(AppConfiguration.class);

    @Value("${azure.cosmos.uri}")
    private String uri;

    @Value("${azure.cosmos.key}")
    private String key;

    @Value("${azure.cosmos.secondaryKey}")
    private String secondaryKey;

    @Value("${azure.cosmos.database}")
    private String dbName;

    @Value("${azure.cosmos.queryMetricsEnabled}")
    private boolean queryMetricsEnabled;

    private AzureKeyCredential azureKeyCredential;

    @Bean
    public CosmosClientBuilder getCosmosClientBuilder() {
        this.azureKeyCredential = new AzureKeyCredential(key);
        DirectConnectionConfig directConnectionConfig = new DirectConnectionConfig();
        GatewayConnectionConfig gatewayConnectionConfig = new GatewayConnectionConfig();
        return new CosmosClientBuilder()
            .endpoint(uri)
            .credential(azureKeyCredential)
            .directMode(directConnectionConfig, gatewayConnectionConfig);
    }

    @Override
    public CosmosConfig cosmosConfig() {
        return CosmosConfig.builder()
                           .enableQueryMetrics(queryMetricsEnabled)
                           .responseDiagnosticsProcessor(new ResponseDiagnosticsProcessorImplementation())
                           .build();
    }

    public void switchToSecondaryKey() {
        this.azureKeyCredential.update(secondaryKey);
    }

    @Override
    protected String getDatabaseName() {
        return "testdb";
    }

    private static class ResponseDiagnosticsProcessorImplementation implements ResponseDiagnosticsProcessor {

        @Override
        public void processResponseDiagnostics(@Nullable ResponseDiagnostics responseDiagnostics) {
            LOGGER.info("Response Diagnostics {}", responseDiagnostics);
        }
    }

}

Настройка конфигурации

Вы можете настроить DirectConnectionConfig и (или) GatewayConnectionConfig и предоставить их в bean-компонент CosmosClientBuilder для настройки CosmosAsyncClient.

@Bean
public CosmosClientBuilder getCosmosClientBuilder() {

    DirectConnectionConfig directConnectionConfig = new DirectConnectionConfig();
    GatewayConnectionConfig gatewayConnectionConfig = new GatewayConnectionConfig();
    return new CosmosClientBuilder()
        .endpoint(uri)
        .directMode(directConnectionConfig, gatewayConnectionConfig);
}

@Override
public CosmosConfig cosmosConfig() {
    return CosmosConfig.builder()
                       .enableQueryMetrics(queryMetricsEnabled)
                       .responseDiagnosticsProcessor(new ResponseDiagnosticsProcessorImplementation())
                       .build();
}

По умолчанию @EnableCosmosRepositories будет проверять текущий пакет на наличие интерфейсов, расширяющих один из интерфейсов репозитория Spring Data. Если макет проекта содержит несколько проектов, используйте @EnableCosmosRepositories(basePackageClass=UserRepository.class), чтобы добавить в класс Configuration заметку для сканирования другого корневого пакета.

Определение сущности

Определите простую сущность как элемент в Azure Cosmos DB.

Сущности можно определить, добавив заметку @Container и указав свойства, связанные с контейнером, такие как имя контейнера, единицы запроса (ЕЗ), срок жизни и флаг автоматического создания контейнера.

Контейнеры создаются автоматически, если вы не измените соответствующую настройку. Установите для параметра autoCreateContainer значение false в заметке @Container, чтобы отключить автоматическое создание контейнеров.

Примечание

По умолчанию только что созданным контейнерам назначается 400 единиц запроса. Укажите другое значение ru, чтобы настроить количество единиц запроса для контейнера, созданного пакетом SDK (минимальное значение — 400).

@Container(containerName = "myContainer", ru = "400")
public class User {
    private String id;
    private String firstName;


    @PartitionKey
    private String lastName;

    public User() {
        // If you do not want to create a default constructor,
        // use annotation @JsonCreator and @JsonProperty in the full args constructor
    }

    public User(String id, String firstName, String lastName) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return String.format("User: %s %s, %s", firstName, lastName, id);
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

Поле id будет использоваться в качестве идентификатора элемента в Azure Cosmos DB. Если вы хотите использовать другое поле, например firstName, в качестве элемента id, просто добавьте к этому полю заметку @Id.

Заметка @Container(containerName="myContainer") указывает имя контейнера в Azure Cosmos DB.

Заметка @PartitionKey в поле lastName указывает это поле в качестве ключа секции в Azure Cosmos DB.

Создание контейнеров с автомасштабируемой пропускной способностью

В поле заметки autoScale указывается контейнер, который будет создан с автомасштабируемой пропускной способностью, если задано значение true. Значение по умолчанию — false. Это означает, что контейнеры создаются с настраиваемой вручную пропускной способностью.

Дополнительные сведения об автомасштабируемой пропускной способности см. здесь.

@Container(containerName = "myContainer", autoScale = true, ru = "4000")
public class UserSample {
    @Id
    private String emailAddress;

}

Поддержка ключей вложенных секций

Пакет SDK Cosmos для Spring Data поддерживает ключ вложенной секции. Чтобы добавить ключ вложенной секции, используйте поле partitionKeyPath в заметке @Container.

partitionKeyPath следует использовать только для поддержки пути ключа вложенной секции. Для поддержки ключа общей секции используйте метку @PartitionKey.

По умолчанию заметка @PartitionKey будет иметь приоритет, если не указано иное.

В следующем примере показано, как правильно использовать функцию ключа вложенной секции.

@Container(containerName = "nested-partition-key", partitionKeyPath = "/nestedEntitySample/nestedPartitionKey")
public class NestedPartitionKeyEntitySample {

    private NestedEntitySample nestedEntitySample;
}
public class NestedEntitySample {
    private String nestedPartitionKey;
}

Создание репозиториев

Расширяет интерфейс CosmosRepository, который обеспечивает поддержку репозитория Spring Data.

@Repository
public interface UserRepository extends CosmosRepository<User, String> {
    Iterable<User> findByFirstName(String firstName);
    long countByFirstName(String firstName);
    User findOne(String id, String lastName);
}
  • Метод findByFirstName является методом пользовательских запросов. Он выполняет поиск элементов по firstName.

QueryAnnotation. Использование запросов с заметками в репозиториях

Azure Spring Data Cosmos поддерживает указание запросов с заметками в репозиториях с помощью @Query.

Ниже приведены некоторые примеры запросов с заметками в синхронном интерфейсе CosmosRepository:

public interface AnnotatedQueriesUserRepositoryCodeSnippet extends CosmosRepository<User, String> {
    @Query("select * from c where c.firstName = @firstName and c.lastName = @lastName")
    List<User> getUsersByFirstNameAndLastName(@Param("firstName") String firstName, @Param("lastName") String lastName);

    @Query("select * from c offset @offset limit @limit")
    List<User> getUsersWithOffsetLimit(@Param("offset") int offset, @Param("limit") int limit);

    @Query("select value count(1) from c where c.firstName = @firstName")
    long getNumberOfUsersWithFirstName(@Param("firstName") String firstName);
}

Ниже приведены некоторые примеры запросов с заметками в ReactiveCosmosRepository.

public interface AnnotatedQueriesUserReactiveRepositoryCodeSnippet extends ReactiveCosmosRepository<User, String> {
    @Query("select * from c where c.firstName = @firstName and c.lastName = @lastName")
    Flux<User> getUsersByTitleAndValue(@Param("firstName") int firstName, @Param("lastName") String lastName);

    @Query("select * from c offset @offset limit @limit")
    Flux<User> getUsersWithOffsetLimit(@Param("offset") int offset, @Param("limit") int limit);

    @Query("select count(c.id) as num_ids, c.lastName from c group by c.lastName")
    Flux<ObjectNode> getCoursesGroupByDepartment();

    @Query("select value count(1) from c where c.lastName = @lastName")
    Mono<Long> getNumberOfUsersWithLastName(@Param("lastName") String lastName);
}

Запросы, заданные в заметке, совпадают с запросами Cosmos. Дополнительные сведения о запросах SQL в Cosmos см. в следующих статьях:

Создание класса приложения

Этот код создает класс приложения со всеми компонентами:

@SpringBootApplication
public class SampleApplication implements CommandLineRunner {

    @Autowired
    private UserRepository repository;

    @Autowired
    private ApplicationContext applicationContext;

    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }

    public void run(String... var1) {

        final User testUser = new User("testId", "testFirstName", "testLastName");

        repository.deleteAll();
        repository.save(testUser);

        // to find by Id, please specify partition key value if collection is partitioned
        final User result = repository.findOne(testUser.getId(), testUser.getLastName());

        //  Switch to secondary key
        UserRepositoryConfiguration bean =
            applicationContext.getBean(UserRepositoryConfiguration.class);
        bean.switchToSecondaryKey();

        //  Now repository will use secondary key
        repository.save(testUser);

    }
}

Автоматически внедрите интерфейс UserRepository, чтобы выполнять такие операции, как сохранение, удаление, поиск и т. д.

Spring Data Azure Cosmos DB использует CosmosTemplate и ReactiveCosmosTemplate для выполнения запросов, расположенных за методами find и save. Вы можете использовать этот шаблон для более сложных запросов.

Основные понятия

CrudRepository и ReactiveCrudRepository

Azure Spring Data Cosmos поддерживает ReactiveCrudRepository и CrudRepository, которые обеспечивают базовую функциональность CRUD.

  • Сохранить
  • findAll (поиск всех)
  • findOne by ID (поиск одного по идентификатору)
  • deleteAll (удаление всех)
  • delete by ID (удаление по идентификатору)
  • delete entity (удаление объекта)

Заметки Spring Data

Есть два способа сопоставления поля в доменном классе с полем id элемента Azure Cosmos DB: - добавить заметку к полю в доменном классе с помощью @Id — это поле будет сопоставлено с элементом id в Cosmos DB; - задать для поля имя id — это поле будет сопоставлено с элементом id в Azure Cosmos DB.

Поддерживает автоматическое создание UUID строкового типа с помощью заметки @GeneratedValue. К полю идентификатора сущности с идентификатором строкового типа можно добавить заметку @GeneratedValue для автоматического создания случайного UUID перед вставкой.

public class GeneratedIdEntity {

    @Id
    @GeneratedValue
    private String id;

}
  • Выражение SpEL и пользовательское имя контейнера.
    • По умолчанию имя контейнера будет именем доменного класса пользователя. Чтобы настроить его, добавьте в доменный класс заметку @Container(containerName="myCustomContainerName"). Поле контейнера также поддерживает выражения SpEL (например, container = "${dynamic.container.name}" или container = "#{@someBean.getContainerName()}"), чтобы предоставлять имена контейнеров программно или через свойства конфигурации.
    • Чтобы выражения SpEL работали правильно, необходимо добавить @DependsOn("expressionResolver") поверх класса приложения Spring.
@SpringBootApplication
@DependsOn("expressionResolver")
public class SampleApplication {

}
  • Пользовательское значение IndexingPolicy. По умолчанию IndexingPolicy устанавливает служба Azure. Для настройки добавьте в доменный класс заметку @CosmosIndexingPolicy. Эта заметка содержит 4 атрибута, которые можно настроить:
// Indicate if indexing policy use automatic or not
// Default value is true
boolean automatic() default Constants.DEFAULT_INDEXING_POLICY_AUTOMATIC;

// Indexing policy mode, option Consistent.
IndexingMode mode() default IndexingMode.CONSISTENT;

// Included paths for indexing
String[] includePaths() default {};

// Excluded paths for indexing
String[] excludePaths() default {};

Секция Azure Cosmos DB

Azure-spring-data-cosmos поддерживает секцию Azure Cosmos DB.

Чтобы указать поле доменного класса в качестве поля ключа секции, добавьте к нему заметку @PartitionKey.

Затем при выполнении операций CRUD указывайте значение секции.

Дополнительные примеры для CRUD секции см. здесь.

Оптимистическая блокировка

Azure-spring-data-cosmos поддерживает оптимистичную блокировку для конкретных контейнеров. Это означает, что операции upsert или удаления по элементу будут завершаться с исключением в случае, если элемент был изменен другим процессом в то же время.

Чтобы включить оптимистическую блокировку для контейнера, просто создайте строковое поле _etag и пометьте его заметкой @Version. См. следующие разделы:

@Container(containerName = "myContainer")
public class MyItem {
    String id;
    String data;
    @Version
    String _etag;
}

Пользовательский запрос Spring Data, разбивка на страницы и сортировка

Azure-spring-data-cosmos поддерживает пользовательские запросы Spring Data, например операцию поиска, такую как findByAFieldAndBField.

Поддерживает разбивку на страницы, сортировку и получение среза Spring Data. - В зависимости от единиц запроса (ЕЗ), доступных для учетной записи базы данных, cosmosDB может возвращать элементы, размер которых меньше или равен запрошенному размеру. - Из-за этого переменного количества возвращаемых элементов в каждой итерации пользователь не должен полагаться на totalPageSize, а вместо этого выполнять итерацию разбивки на страницы.

private List<T> findAllWithPageSize(int pageSize) {

    final CosmosPageRequest pageRequest = new CosmosPageRequest(0, pageSize, null);
    Page<T> page = repository.findAll(pageRequest);
    List<T> pageContent = page.getContent();
    while (page.hasNext()) {
        Pageable nextPageable = page.nextPageable();
        page = repository.findAll(nextPageable);
        pageContent = page.getContent();
    }
    return pageContent;
}
public interface SliceQueriesUserRepository extends CosmosRepository<User, String> {
    @Query("select * from c where c.lastName = @lastName")
    Slice<User> getUsersByLastName(@Param("lastName") String lastName, Pageable pageable);
}
private List<User> getUsersByLastName(String lastName, int pageSize) {

    final CosmosPageRequest pageRequest = new CosmosPageRequest(0, pageSize, null);
    Slice<User> slice = repository.getUsersByLastName(lastName, pageRequest);
    List<User> content = slice.getContent();
    while (slice.hasNext()) {
        Pageable nextPageable = slice.nextPageable();
        slice = repository.getUsersByLastName(lastName, nextPageable);
        content.addAll(slice.getContent());
    }
    return content;
}

Spring Boot Starter Data Rest

Azure-spring-data-cosmos поддерживает spring-boot-starter-data-rest.

  • Поддерживает список и вложенный тип в доменном классе.
  • Настраиваемый bean-компонент ObjectMapper с уникальным именем cosmosObjectMapper. Используйте пользовательский ObjectMapper только если это действительно требуется. Пример:
@Bean(name = "cosmosObjectMapper")
public ObjectMapper objectMapper() {
    return new ObjectMapper(); // Do configuration to the ObjectMapper if required
}

Аудит

Azure-spring-data-cosmos поддерживает поля аудита для сущностей базы данных с использованием стандартных заметок spring-data.

Эту функцию можно включить, добавив заметку @EnableCosmosAuditing в конфигурацию приложения.

Сущности могут добавлять заметки к полям с помощью @CreatedBy, @CreatedDate, @LastModifiedBy и @LastModifiedDate. Эти поля будут обновлены автоматически.

@Container(containerName = "myContainer")
public class AuditableUser {
    private String id;
    private String firstName;
    @CreatedBy
    private String createdBy;
    @CreatedDate
    private OffsetDateTime createdDate;
    @LastModifiedBy
    private String lastModifiedBy;
    @LastModifiedDate
    private OffsetDateTime lastModifiedByDate;
}

Конфигурация с несколькими базами данных

Azure-spring-data-cosmos поддерживает конфигурацию с несколькими базами данных, включая "несколько учетных записей баз данных" и "одну учетную запись с несколькими базами данных".

Несколько учетных записей баз данных

В примере используется файл application.properties:

# primary account cosmos config
azure.cosmos.primary.uri=your-primary-cosmosDb-uri
azure.cosmos.primary.key=your-primary-cosmosDb-key
azure.cosmos.primary.secondaryKey=your-primary-cosmosDb-secondary-key
azure.cosmos.primary.database=your-primary-cosmosDb-dbName
azure.cosmos.primary.populateQueryMetrics=if-populate-query-metrics

# secondary account cosmos config
azure.cosmos.secondary.uri=your-secondary-cosmosDb-uri
azure.cosmos.secondary.key=your-secondary-cosmosDb-key
azure.cosmos.secondary.secondaryKey=your-secondary-cosmosDb-secondary-key
azure.cosmos.secondary.database=your-secondary-cosmosDb-dbName
azure.cosmos.secondary.populateQueryMetrics=if-populate-query-metrics

Определение сущности и репозитория аналогично приведенному выше. Разные сущности баз данных можно разместить в разных пакетах.

@EnableReactiveCosmosRepositories или @EnableCosmosRepositories поддерживают определение шаблона Cosmos пользователем. Используйте reactiveCosmosTemplateRef или cosmosTemplateRef для настройки имени bean-компонента ReactiveCosmosTemplate или CosmosTemplate для использования с обнаруженными репозиториями.

Если у вас несколько учетных записей базы данных Cosmos, можно определить несколько CosmosAsyncClient. Если в одной учетной записи Cosmos несколько баз данных, можно использовать тот же CosmosAsyncClient для инициализации шаблона Cosmos.

@Configuration
@EnableReactiveCosmosRepositories(basePackages = "com.azure.spring.sample.cosmos.multi.database.multiple.account.repository",
    reactiveCosmosTemplateRef = "primaryDatabaseTemplate")
public class PrimaryDatasourceConfiguration extends AbstractCosmosConfiguration{

    private static final String PRIMARY_DATABASE = "primary_database";

    @Bean
    @ConfigurationProperties(prefix = "azure.cosmos.primary")
    public CosmosProperties primary() {
        return new CosmosProperties();
    }

    @Bean
    public CosmosClientBuilder primaryClientBuilder(@Qualifier("primary") CosmosProperties primaryProperties) {
        return new CosmosClientBuilder()
            .key(primaryProperties.getKey())
            .endpoint(primaryProperties.getUri());
    }

    @Bean
    public ReactiveCosmosTemplate primaryDatabaseTemplate(CosmosAsyncClient cosmosAsyncClient,
                                                          CosmosConfig cosmosConfig,
                                                          MappingCosmosConverter mappingCosmosConverter) {
        return new ReactiveCosmosTemplate(cosmosAsyncClient, PRIMARY_DATABASE, cosmosConfig, mappingCosmosConverter);
    }

    @Override
    protected String getDatabaseName() {
        return PRIMARY_DATABASE;
    }
}
@Configuration
@EnableCosmosRepositories(cosmosTemplateRef  = "secondaryDatabaseTemplate")
public class SecondaryDatasourceConfiguration {

    private static final Logger LOGGER = LoggerFactory.getLogger(SecondaryDatasourceConfiguration.class);
    public static final String SECONDARY_DATABASE = "secondary_database";

    @Bean
    @ConfigurationProperties(prefix = "azure.cosmos.secondary")
    public CosmosProperties secondary() {
        return new CosmosProperties();
    }

    @Bean("secondaryCosmosClient")
    public CosmosAsyncClient getCosmosAsyncClient(@Qualifier("secondary") CosmosProperties secondaryProperties) {
        return CosmosFactory.createCosmosAsyncClient(new CosmosClientBuilder()
            .key(secondaryProperties.getKey())
            .endpoint(secondaryProperties.getUri()));
    }

    @Bean("secondaryCosmosConfig")
    public CosmosConfig getCosmosConfig() {
        return CosmosConfig.builder()
            .enableQueryMetrics(true)
            .responseDiagnosticsProcessor(new ResponseDiagnosticsProcessorImplementation())
            .build();
    }

    @Bean
    public CosmosTemplate secondaryDatabaseTemplate(@Qualifier("secondaryCosmosClient") CosmosAsyncClient client,
                                                    @Qualifier("secondaryCosmosConfig") CosmosConfig cosmosConfig,
                                                    MappingCosmosConverter mappingCosmosConverter) {
        return new CosmosTemplate(client, SECONDARY_DATABASE, cosmosConfig, mappingCosmosConverter);
    }

    private static class ResponseDiagnosticsProcessorImplementation implements ResponseDiagnosticsProcessor {

        @Override
        public void processResponseDiagnostics(@Nullable ResponseDiagnostics responseDiagnostics) {
            LOGGER.info("Response Diagnostics {}", responseDiagnostics);
        }
    }
}

В приведенном выше примере используются две учетные записи Cosmos. Вы можете создать CosmosAsyncClient следующим образом:

@Bean("secondaryCosmosClient")
public CosmosAsyncClient getCosmosAsyncClient(@Qualifier("secondary") CosmosProperties secondaryProperties) {
    return CosmosFactory.createCosmosAsyncClient(new CosmosClientBuilder()
        .key(secondaryProperties.getKey())
        .endpoint(secondaryProperties.getUri()));
}

@Bean("secondaryCosmosConfig")
public CosmosConfig getCosmosConfig() {
    return CosmosConfig.builder()
        .enableQueryMetrics(true)
        .responseDiagnosticsProcessor(new ResponseDiagnosticsProcessorImplementation())
        .build();
}

Если вы хотите определить queryMetricsEnabled или ResponseDiagnosticsProcessor, можно создать CosmosConfig для шаблона Cosmos.

@Bean("secondaryCosmosConfig")
public CosmosConfig getCosmosConfig() {
    return CosmosConfig.builder()
        .enableQueryMetrics(true)
        .responseDiagnosticsProcessor(new ResponseDiagnosticsProcessorImplementation())
        .build();
}

Создайте класс Application:

@SpringBootApplication
public class MultiDatabaseApplication implements CommandLineRunner {

    @Autowired
    private CosmosUserRepository cosmosUserRepository;

    @Autowired
    private MysqlUserRepository mysqlUserRepository;

    @Autowired
    @Qualifier("secondaryDatabaseTemplate")
    private CosmosTemplate secondaryDatabaseTemplate;

    @Autowired
    @Qualifier("primaryDatabaseTemplate")
    private ReactiveCosmosTemplate primaryDatabaseTemplate;

    private final CosmosUser cosmosUser = new CosmosUser("1024", "1024@geek.com", "1k", "Mars");
    private static CosmosEntityInformation<CosmosUser, String> userInfo = new CosmosEntityInformation<>(CosmosUser.class);

    public static void main(String[] args) {
        SpringApplication.run(MultiDatabaseApplication.class, args);
    }

    public void run(String... var1) throws Exception {

        CosmosUser cosmosUserGet = primaryDatabaseTemplate.findById(cosmosUser.getId(), cosmosUser.getClass()).block();
        // Same to this.cosmosUserRepository.findById(cosmosUser.getId()).block();
        MysqlUser mysqlUser = new MysqlUser(cosmosUserGet.getId(), cosmosUserGet.getEmail(), cosmosUserGet.getName(), cosmosUserGet.getAddress());
        mysqlUserRepository.save(mysqlUser);
        mysqlUserRepository.findAll().forEach(System.out::println);
        CosmosUser secondaryCosmosUserGet = secondaryDatabaseTemplate.findById(CosmosUser.class.getSimpleName(), cosmosUser.getId(), CosmosUser.class);
        System.out.println(secondaryCosmosUserGet);
    }


    @PostConstruct
    public void setup() {
        primaryDatabaseTemplate.createContainerIfNotExists(userInfo).block();
        primaryDatabaseTemplate.insert(CosmosUser.class.getSimpleName(), cosmosUser, new PartitionKey(cosmosUser.getName())).block();
        // Same to this.cosmosUserRepository.save(user).block();
        secondaryDatabaseTemplate.createContainerIfNotExists(userInfo);
        secondaryDatabaseTemplate.insert(CosmosUser.class.getSimpleName(), cosmosUser, new PartitionKey(cosmosUser.getName()));
   }

    @PreDestroy
    public void cleanup() {
        primaryDatabaseTemplate.deleteAll(CosmosUser.class.getSimpleName(), CosmosUser.class).block();
        // Same to this.cosmosUserRepository.deleteAll().block();
        secondaryDatabaseTemplate.deleteAll(CosmosUser.class.getSimpleName() , CosmosUser.class);
        mysqlUserRepository.deleteAll();
    }
}

Одна учетная запись с несколькими базами данных

В примере используется файл application.properties:

azure.cosmos.uri=your-cosmosDb-uri
azure.cosmos.key=your-cosmosDb-key
azure.cosmos.secondary-key=your-cosmosDb-secondary-key
azure.cosmos.database=your-cosmosDb-dbName
azure.cosmos.populate-query-metrics=if-populate-query-metrics

Определение сущности и репозитория аналогично приведенному выше. Разные сущности баз данных можно разместить в разных пакетах.

Для определения нескольких баз данных в одной учетной записи Cosmos можно использовать EnableReactiveCosmosRepositories с разными reactiveCosmosTemplateRef.

@Configuration
public class DatasourceConfiguration {

    private static final String DATABASE1 = "database1";
    private static final String DATABASE2 = "database2";

    @Bean
    public CosmosProperties cosmosProperties() {
        return new CosmosProperties();
    }

    @Bean
    public CosmosClientBuilder primaryClientBuilder(CosmosProperties cosmosProperties) {
        return new CosmosClientBuilder()
            .key(cosmosProperties.getKey())
            .endpoint(cosmosProperties.getUri());
    }

    @EnableReactiveCosmosRepositories(basePackages = "com.azure.spring.sample.cosmos.multi.database.repository1",
        reactiveCosmosTemplateRef = "database1Template")
    public class Database1Configuration extends AbstractCosmosConfiguration {

        @Bean
        public ReactiveCosmosTemplate database1Template(CosmosAsyncClient cosmosAsyncClient,
                                                              CosmosConfig cosmosConfig,
                                                              MappingCosmosConverter mappingCosmosConverter) {
            return new ReactiveCosmosTemplate(cosmosAsyncClient, DATABASE1, cosmosConfig, mappingCosmosConverter);
        }

        @Override
        protected String getDatabaseName() {
            return DATABASE1;
        }
    }

    @EnableReactiveCosmosRepositories(basePackages = "com.azure.spring.sample.cosmos.multi.database.repository2",
        reactiveCosmosTemplateRef = "database2Template")
    public class Database2Configuration {

        @Bean
        public ReactiveCosmosTemplate database2Template(CosmosAsyncClient cosmosAsyncClient,
                                                              CosmosConfig cosmosConfig,
                                                              MappingCosmosConverter mappingCosmosConverter) {
            return new ReactiveCosmosTemplate(cosmosAsyncClient, DATABASE2, cosmosConfig, mappingCosmosConverter);
        }

    }
}

Создайте класс Application:

@SpringBootApplication
public class MultiDatabaseApplication implements CommandLineRunner {

    @Autowired
    private User1Repository user1Repository;

    @Autowired
    @Qualifier("database1Template")
    private ReactiveCosmosTemplate database1Template;

    @Autowired
    @Qualifier("database2Template")
    private ReactiveCosmosTemplate database2Template;

    private final User1 user1 = new User1("1024", "1024@geek.com", "1k", "Mars");
    private static CosmosEntityInformation<User1, String> user1Info = new CosmosEntityInformation<>(User1.class);

    private final User2 user2 = new User2("2048", "2048@geek.com", "2k", "Mars");
    private static CosmosEntityInformation<User2, String> user2Info = new CosmosEntityInformation<>(User2.class);


    public static void main(String[] args) {
        SpringApplication.run(MultiDatabaseApplication.class, args);
    }

    public void run(String... var1) throws Exception {

        User1 database1UserGet = database1Template.findById(User1.class.getSimpleName(), user1.getId(), User1.class).block();
        // Same to userRepository1.findById(user.getId()).block()
        System.out.println(database1UserGet);
        User2 database2UserGet = database2Template.findById(User2.class.getSimpleName(), user2.getId(), User2.class).block();
        System.out.println(database2UserGet);
    }

    @PostConstruct
    public void setup() {
        database1Template.createContainerIfNotExists(user1Info).block();
        database1Template.insert(User1.class.getSimpleName(), user1, new PartitionKey(user1.getName())).block();
        // Same to this.userRepository1.save(user).block();
        database2Template.createContainerIfNotExists(user2Info).block();
        database2Template.insert(User2.class.getSimpleName(), user2, new PartitionKey(user2.getName())).block();
    }

    @PreDestroy
    public void cleanup() {
        database1Template.deleteAll(User1.class.getSimpleName(), User1.class).block();
        // Same to this.userRepository1.deleteAll().block();
        database2Template.deleteAll(User2.class.getSimpleName(), User2.class).block();
    }
}

Пакет бета-версии

Доступна бета-версия, созданная на основе ветви master. См. инструкции по использованию пакетов бета-версий.

Устранение неполадок

Общие сведения

Если вы столкнулись с ошибкой, сообщите о ней.

Предложить новую функцию или изменения можно таким же образом, как и в случае ошибки.

Включение ведения журнала клиента

Azure-spring-data-cosmos использует SLF4j как интерфейс ведения журнала, который поддерживает запись на популярные платформы ведения журналов, такие как log4j и logback. Например, если вы хотите использовать в качестве платформы ведения журналов logback для Spring, добавьте следующий XML в папку ресурсов:

<configuration>
  <include resource="/org/springframework/boot/logging/logback/base.xml"/>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
      </pattern>
    </encoder>
  </appender>
  <root level="info">
    <appender-ref ref="STDOUT"/>
  </root>
  <logger name="com.azure.cosmos" level="error"/>
  <logger name="org.springframework" level="error"/>
  <logger name="io.netty" level="error"/>
  <!-- This will enable query logging, to include query parameter logging, set this logger to TRACE -->  
  <logger name="com.azure.cosmos.implementation.SqlQuerySpecLogger" level="DEBUG"/>  
</configuration>

Примеры

См. пример проекта.

Несколько учетных записей баз данных

См. пример проекта с несколькими базами данных.

Одна учетная запись с несколькими базами данных

См. пример проекта, в котором используется одна учетная запись с несколькими базами данных.

Дальнейшие действия

Участие

На этом проекте приветствуются публикации и предложения. Для участия в большинстве процессов по разработке документации необходимо принять лицензионное соглашение участника (CLA), в котором указывается, что вы предоставляете нам права на использование ваших публикаций.

При отправке запроса на включение внесенных изменений CLA-бот автоматически определит необходимость предоставления соглашения CLA и соответствующего оформления запроса на включение внесенных изменений (например, добавление метки, комментария). Просто следуйте инструкциям бота. Будет достаточно выполнить их один раз для всех репозиториев, поддерживающих соглашение CLA.

В рамках этого проекта действуют правила поведения в отношении продуктов с открытым исходным кодом Майкрософт. Дополнительные сведения:вопросы и ответы по правилам поведения. С любыми другими вопросами или комментариями обращайтесь по адресуopencode@microsoft.com.

Просмотры