Partager via


Bibliothèque de client Azure Spring Data Cosmos pour Java - version 5.6.0

Azure Spring Data Cosmos assure la prise en charge de Spring Data pour Azure Cosmos DB à l’aide de l’API SQL, basée sur le framework Spring Data. Azure Cosmos DB est un service de base de données distribué à l’échelle mondiale qui permet aux développeurs de travailler sur des données à l’aide de diverses API standard, telles que SQL, MongoDB, Cassandra, Graph et Table.

Stratégie de support Spring Boot

Ce projet prend en charge plusieurs versions de Spring Boot. Pour obtenir la liste complète des versions actuellement prises en charge, consultez notre mappage de versions Spring.

Les versions Spring Boot sont marquées « Fin de vie » lorsqu’elles ne sont plus prises en charge ou publiées sous une quelconque forme. Si vous exécutez une version EOL, vous devez effectuer une mise à niveau dès que possible.

Notez qu’une version peut ne pas être prise en charge avant d’être marquée comme « Fin de vie ». Pendant ce temps, vous ne devez attendre que des mises en production pour des bogues critiques ou des problèmes de sécurité.

Pour plus d’informations sur les versions prises en charge de Spring Boot, consultez Versions prises en charge de Spring Boot.

Prise en charge des versions de Spring Boot

Les utilisateurs de Maven peuvent hériter du projet spring-boot-starter-parent pour obtenir une section de gestion des dépendances afin de permettre à Spring de gérer les versions des dépendances.

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

Avec cette configuration, vous pouvez également substituer des dépendances individuelles en substituant une propriété dans votre propre projet. Par exemple, pour passer à un autre train de livraison (release train) Spring Data, vous devez ajouter ce qui suit à votre fichier pom.xml.

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

Si vous ne souhaitez pas utiliser spring-boot-starter-parent, vous pouvez tout de même conserver l’avantage de la gestion des dépendances en utilisant une dépendance 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>

Quelle version d’Azure Spring Data Cosmos dois-je utiliser ?

Mappage de la version Spring Boot / Spring Cloud aux versions d’Azure Spring Data Cosmos

Version de Spring Boot Version de Spring Cloud Versions d’Azure Spring Data Cosmos
3.0.x 2022.0.x 5.3.0 et versions ultérieures
2.7.x 2021.0.x 3.23.0 et versions ultérieures
2.6.x 2021.0.x 3.15.0 - 3.22.0
2.5.x 2020.0.x 3.8.0 - 3.14.0
2.4.x 2020.0.x 3.5.0 - 3.7.0

J’utilise Spring Boot version X

Si vous utilisez Spring Boot dans votre projet, vous trouverez les versions d’Azure Spring Data Cosmos associées dans le tableau ci-dessus. Par exemple : si vous utilisez Spring Boot 3.0.x, vous devez utiliser Azure Spring Data Cosmos versions 5.3.0 et ultérieures.

J’utilise Spring Cloud Version Y

Si vous utilisez Spring Cloud dans votre projet, vous pouvez également trouver les versions Azure Spring Data Cosmos associées dans le tableau ci-dessus. Par exemple, si vous utilisez Spring Cloud 2022.0.x, vous devez utiliser Azure Spring Data Cosmos versions 5.3.0 et ultérieures.

Prise en charge des versions de Spring Data

Ce projet prend en charge les spring-data-commons 3.0.x versions.

La configuration ci-dessus ne vous permet pas de remplacer des dépendances individuelles à l’aide d’une propriété, comme expliqué ci-dessus. Pour obtenir le même résultat, vous devez ajouter une entrée dans la partie dependencyManagement de votre projet avant l’entrée spring-boot-dependencies. Par exemple, pour passer à un autre train de livraison (release train) Spring Data, vous devez ajouter ce qui suit à votre fichier 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>

Remarque : Remplacez ${spring.boot.version} et ${spring.data.version} par les versions de Spring Boot et de Spring Data que vous souhaitez utiliser dans votre projet.

Prise en main

Inclure le package

Si vous utilisez Maven, ajoutez la dépendance suivante.

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

Prérequis

  • Kit de développement Java (JDK), version 8 ou ultérieure.
  • Un compte Azure actif. Si vous n’en avez pas, vous pouvez vous inscrire pour bénéficier d’un compte gratuit. Vous pouvez également utiliser l’émulateur Azure Cosmos DB à des fins de développement et de test. Comme le certificat https de l’émulateur est auto-signé, vous devez importer son certificat dans le magasin de certificats approuvé Java, expliqué ici
  • (Facultatif) SLF4J est une façade de journalisation.
  • (Facultatif) La liaison SLF4J est utilisée pour associer un framework de journalisation spécifique à SLF4J.
  • (Facultatif) Maven

SLF4J n’est nécessaire que si vous envisagez d’utiliser la journalisation. Téléchargez également une liaison SLF4J qui lie l’API SLF4J à l’implémentation de journalisation de votre choix. Pour plus d’informations, consultez le manuel de l’utilisateur SLF4J.

Installer la classe de configuration

  • Pour installer la classe de configuration, vous devez étendre AbstractCosmosConfiguration.

  • Azure-spring-data-cosmos prend également en charge Response Diagnostics String, Query Metrics et Max Degree of Parallelism. Définissez l’indicateur queryMetricsEnabled avec la valeur true dans application.properties pour activer les métriques de requête. En plus de définir l’indicateur, implémentez ResponseDiagnosticsProcessor pour journaliser les informations de diagnostic. Définissez l’indicateur sur un entier dans application.properties pour autoriser le traitement parallèle ; si vous définissez maxDegreeOfParallelism la valeur sur -1, le SDK décide de la valeur optimale. Définissez maxBufferedItemCount l’indicateur sur un entier dans application.properties pour permettre à l’utilisateur de définir le nombre maximal d’éléments pouvant être mis en mémoire tampon pendant l’exécution d’une requête parallèle ; si la valeur est inférieure à 0, le système décide automatiquement du nombre d’éléments à mettre en mémoire tampon. REMARQUE : La définition d’une valeur très élevée peut entraîner une consommation élevée de mémoire. Définissez responseContinuationTokenLimitInKb l’indicateur sur un entier dans application.properties pour permettre à l’utilisateur de limiter la longueur du jeton de continuation dans la réponse à la requête. Le jeton de continuation contient à la fois les champs obligatoires et facultatifs. Les champs obligatoires sont nécessaires pour reprendre l’exécution à partir de l’endroit où elle a été arrêtée. Les champs facultatifs peuvent contenir un travail de recherche d’index sérialisé qui a été effectué mais qui n’a pas encore été utilisé. Cela évite de refaire le travail dans les continuations suivantes et, par conséquent, améliore les performances des requêtes. Si vous définissez la taille de continuation maximale sur 1 Ko, le service Azure Cosmos DB sérialise uniquement les champs obligatoires. À partir de 2 Ko, le service Azure Cosmos DB sérialise autant qu’il peut le faire jusqu’à ce qu’il atteigne la taille maximale spécifiée. Définissez pointOperationLatencyThresholdInMS, nonPointOperationLatencyThresholdInMSet payloadSizeThresholdInBytesrequestChargeThresholdInRU pour activer diagnostics au niveau du client lorsque ces seuils sont dépassés.

@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;

    @Value("${azure.cosmos.maxDegreeOfParallelism}")
    private int maxDegreeOfParallelism;

    @Value("${azure.cosmos.maxBufferedItemCount}")
    private int maxBufferedItemCount;

    @Value("${azure.cosmos.responseContinuationTokenLimitInKb}")
    private int responseContinuationTokenLimitInKb;

    @Value("${azure.cosmos.diagnosticsThresholds.pointOperationLatencyThresholdInMS}")
    private int pointOperationLatencyThresholdInMS;

    @Value("${azure.cosmos.diagnosticsThresholds.nonPointOperationLatencyThresholdInMS}")
    private int nonPointOperationLatencyThresholdInMS;

    @Value("${azure.cosmos.diagnosticsThresholds.requestChargeThresholdInRU}")
    private int requestChargeThresholdInRU;

    @Value("${azure.cosmos.diagnosticsThresholds.payloadSizeThresholdInBytes}")
    private int payloadSizeThresholdInBytes;


    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)
            .clientTelemetryConfig(
                new CosmosClientTelemetryConfig()
                    .diagnosticsThresholds(
                        new CosmosDiagnosticsThresholds()
                            .setNonPointOperationLatencyThreshold(Duration.ofMillis(nonPointOperationLatencyThresholdInMS))
                            .setPointOperationLatencyThreshold(Duration.ofMillis(pointOperationLatencyThresholdInMS))
                            .setPayloadSizeThreshold(payloadSizeThresholdInBytes)
                            .setRequestChargeThreshold(requestChargeThresholdInRU)
                    )
                    .diagnosticsHandler(CosmosDiagnosticsHandler.DEFAULT_LOGGING_HANDLER));
    }

    @Override
    public CosmosConfig cosmosConfig() {
        return CosmosConfig.builder()
                           .enableQueryMetrics(queryMetricsEnabled)
                           .maxDegreeOfParallelism(maxDegreeOfParallelism)
                           .maxBufferedItemCount(maxBufferedItemCount)
                           .responseContinuationTokenLimitInKb(responseContinuationTokenLimitInKb)
                           .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);
        }
    }

}

Personnalisation de la configuration

Vous pouvez personnaliser DirectConnectionConfig ou ou GatewayConnectionConfig les deux et leur fournir le CosmosClientBuilder bean pour personnaliserCosmosAsyncClient. Vous pouvez personnaliser pointOperationLatencyThresholdInMS, requestChargeThresholdInRUnonPointOperationLatencyThresholdInMSet payloadSizeThresholdInBytes pour personnaliser les seuils de journalisation des diagnostics lorsqu’ils sont combinés avec CosmosDiagnosticsHandler ce qui active la journalisation des diagnostics avec les seuils par défaut lors de l’ajout à .CosmosClientBuilder

@Bean
public CosmosClientBuilder getCosmosClientBuilder() {

    DirectConnectionConfig directConnectionConfig = new DirectConnectionConfig();
    GatewayConnectionConfig gatewayConnectionConfig = new GatewayConnectionConfig();
    return new CosmosClientBuilder()
        .endpoint(uri)
        .directMode(directConnectionConfig, gatewayConnectionConfig)
        .clientTelemetryConfig(
            new CosmosClientTelemetryConfig()
                .diagnosticsThresholds(
                    new CosmosDiagnosticsThresholds()
                        .setNonPointOperationLatencyThreshold(Duration.ofMillis(nonPointOperationLatencyThresholdInMS))
                        .setPointOperationLatencyThreshold(Duration.ofMillis(pointOperationLatencyThresholdInMS))
                        .setPayloadSizeThreshold(payloadSizeThresholdInBytes)
                        .setRequestChargeThreshold(requestChargeThresholdInRU)
                )
                .diagnosticsHandler(CosmosDiagnosticsHandler.DEFAULT_LOGGING_HANDLER));
}

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

Par défaut, @EnableCosmosRepositories analyse le package actuel à la recherche d’interfaces qui étendent l’une des interfaces de référentiel de Spring Data. Utilisez-le pour annoter votre classe Configuration afin d’analyser un autre package racine avec @EnableCosmosRepositories(basePackageClass=UserRepository.class) si la disposition de votre projet compte plusieurs projets.

Activation de la journalisation diagnostics dans Azure Application Insights avec JavaAgent

Les diagnostics peuvent être activés en passant le JavaAgent avec votre application, comme ci-dessous. Cette opération active la journalisation avec les seuils par défaut. Le « -javaagent » doit être passé avant « -jar ».

java -javaagent:"<path-to-applicationinsights-agent-jar>" -jar <myapp.jar>

Utilisation du débit approvisionné de base de données

Cosmos prend en charge le débit provisionné pour les conteneurs et les bases de données . Par défaut, spring-data-cosmos provisionne le débit pour chaque conteneur créé. Si vous préférez partager le débit entre les conteneurs, vous pouvez activer le débit approvisionné par la base de données via CosmosConfig.

@Override
public CosmosConfig cosmosConfig() {
    int autoscale = false; 
    int initialRequestUnits = 400;
    return CosmosConfig.builder()
                       .enableDatabaseThroughput(autoscale, initialRequestUnits) 
                       .build();
}

Définir une entité

  • Définissez une entité simple en tant qu’élément dans Azure Cosmos DB.

  • Vous pouvez définir des entités en ajoutant l’annotation @Container et en spécifiant des propriétés associées au conteneur, notamment le nom du conteneur, les unités de requête (RU), la durée de vie et la création automatique du conteneur.

  • Sauf si vous spécifiez le contraire, les conteneurs sont créés automatiquement. Définissez autoCreateContainer avec la valeur false dans l’annotation @Container pour désactiver la création automatique des conteneurs.

  • Remarque : Par défaut, 400 unités de requête sont affectées aux conteneurs nouvellement créés. Spécifiez une valeur ru différente afin de personnaliser les unités de requête pour le conteneur créé par le SDK (la valeur RU minimale est 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 le champ sera utilisé comme ID d’élément dans Azure Cosmos DB. Si vous souhaitez utiliser un autre champ comme firstName élément id, il vous suffit d’annoter ce champ avec @Id une annotation.

  • L’annotation @Container(containerName="myContainer") spécifie le nom du conteneur dans Azure Cosmos DB.

  • L’annotation @PartitionKey du champ lastName spécifie ce champ en tant que clé de partition dans Azure Cosmos DB.

Création de conteneurs avec débit de mise à l’échelle automatique

  • S’il est défini avec la valeur true, le champ d’annotation autoScale spécifie que le conteneur doit être créé avec un débit de mise à l’échelle automatique. La valeur par défaut est false, ce qui signifie que les conteneurs sont créés avec un débit manuel.
  • Pour plus d’informations sur le débit de mise à l’échelle automatique, cliquez ici.
@Container(containerName = "myContainer", autoScale = true, ru = "4000")
public class UserSample {
    @Id
    private String emailAddress;

}

Prise en charge des clés de partition imbriquées

  • Azure Spring Data Cosmos prend en charge la clé de partition imbriquée. Pour ajouter une clé de partition imbriquée, utilisez le champ partitionKeyPath dans l’annotation @Container.
  • Utilisez uniquement partitionKeyPath pour prendre en charge le chemin à la clé de partition imbriquée. Pour la prise en charge générale des clés de partition, utilisez l’annotation @PartitionKey.
  • L’annotation @PartitionKey est prioritaire par défaut, sauf si elle n’est pas spécifiée.
  • L’exemple ci-dessous montre comment utiliser correctement la fonctionnalité de clé de partition imbriquée.
@Container(containerName = "nested-partition-key", partitionKeyPath = "/nestedEntitySample/nestedPartitionKey")
public class NestedPartitionKeyEntitySample {

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

Créer des référentiels

Étend l’interface CosmosRepository, qui prend en charge les référentiels 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);
}
  • La méthode findByFirstName est une méthode de requête personnalisée qui trouve des éléments par prénom (firstName).

Mise en cache d’un plan de requête

Les API de requête spring repository telles que findByFirstName(String firstName) l’emplacement de firstName la partition ou les requêtes annotées contenant la clé de partition réduisent le temps d’exécution des requêtes en raison de la mise en cache du plan de requête. Actuellement, la mise en cache du plan de requête n’est prise en charge que pour les méthodes de requête ciblant une seule partition.

QueryAnnotation : utilisation de requêtes annotées dans les référentiels

Azure Spring Data Cosmos prend en charge la spécification de requêtes annotées dans les référentiels avec @Query.

  • Exemples de requêtes annotées dans CosmosRepository synchrone :
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);
}
  • Exemples de requêtes annotées dans 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);
}

Les requêtes spécifiées dans l’annotation sont identiques aux requêtes Cosmos. Pour plus d’informations sur les requêtes SQL dans Cosmos, consultez les articles suivants.

Créer une classe Application

Voici comment créer une classe Application avec tous les composants :

@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);

    }
}
  • Câblez automatiquement l’interface UserRepository pour effectuer des opérations telles que l’enregistrement, la suppression, la recherche, etc.
  • Spring Data Azure Cosmos DB utilise CosmosTemplate et ReactiveCosmosTemplate pour exécuter les requêtes derrière les méthodes find et save. Vous pouvez utiliser le modèle vous-même pour des requêtes plus complexes.

Concepts clés

CrudRepository et ReactiveCrudRepository

  • Azure Spring Data Cosmos prend en charge ReactiveCrudRepository et CrudRepository, qui fournissent des fonctionnalités CRUD de base.
    • Enregistrer
    • findAll
    • findOne by ID
    • deleteAll
    • supprimer par ID
    • delete entity

Annotations Spring Data

Annotation spring Data @Id

Il existe deux façons de mapper un champ d’une classe de domaine au champ id d’un élément Azure Cosmos DB.

  • Annoter un champ dans une classe de domaine avec @Id, ce champ étant mappé à l’id d’élément dans Cosmos DB.
  • Définir le nom de ce champ sur id, ce champ étant mappé à l’id d’élément dans Cosmos DB.

Génération automatique d’ID

  • Prend en charge la génération automatique d’UUID de type chaîne avec l’annotation @GeneratedValue. Le champ id d’une entité avec un ID de type chaîne peut être annoté avec @GeneratedValue pour générer automatiquement un UUID aléatoire avant l’insertion.
public class GeneratedIdEntity {

    @Id
    @GeneratedValue
    private String id;

}

Expression SpEL et nom de conteneur personnalisé.

  • Par défaut, le nom du conteneur est le nom de la classe du domaine de l’utilisateur. Pour le personnaliser, ajoutez l’annotation @Container(containerName="myCustomContainerName") à la classe de domaine. Le champ conteneur prend également en charge les expressions SpEL (par exemple container = "${dynamic.container.name}" , ou container = "#{@someBean.getContainerName()}") afin de fournir des noms de conteneur par programmation/via des propriétés de configuration.
  • Pour que les expressions SpEL fonctionnent correctement, vous devez ajouter @DependsOn("expressionResolver") au-dessus de la classe Spring Application.
@SpringBootApplication
@DependsOn("expressionResolver")
public class SampleApplication {
    
}

Stratégie d’indexation

  • Par défaut, IndexingPolicy est défini par le service portail Azure. Pour le personnaliser, ajoutez l’annotation @CosmosIndexingPolicy à la classe de domaine. Cette annotation a 5 attributs à personnaliser, consultez les rubriques suivantes :
// 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 {};

Stratégie de clé unique

  • Azure Spring Data Cosmos prend en charge la définition UniqueKeyPolicy sur le conteneur en ajoutant l’annotation @CosmosUniqueKeyPolicy à la classe de domaine. Cette annotation a les attributs suivants :
@Container
@CosmosUniqueKeyPolicy(uniqueKeys = {
    @CosmosUniqueKey(paths = {"/lastName", "/zipCode"}),
    @CosmosUniqueKey(paths = {"/city"})
})
public class CosmosUniqueKeyPolicyCodeSnippet {

    @Id
    String id;

    @PartitionKey
    String firstName;

    String lastName;
    String zipCode;
    String city;
}

Partition Azure Cosmos DB

  • Azure-spring-data-cosmos prend en charge les partitions Azure Cosmos DB.
  • Pour spécifier un champ d’une classe de domaine comme champ de clé de partition, annotez-le simplement avec @PartitionKey.
  • Quand vous effectuez une opération CRUD, spécifiez la valeur de votre partition.
  • Pour plus d’exemples sur les opérations CRUD sur les partitions, consultez le test ici.

Verrouillage optimiste

  • Azure-spring-data-cosmos prend en charge le verrouillage optimiste pour des conteneurs spécifiques, ce qui signifie que les upserts/suppressions par élément échouent avec une exception quand l’élément est modifié par un autre processus entre-temps.
  • Pour activer le verrouillage optimiste pour un conteneur, créez simplement un champ _etag de type chaîne et marquez-le avec l’annotation @Version. Consultez les rubriques suivantes :
@Container(containerName = "myContainer")
public class MyItem {
    String id;
    String data;
    @Version
    String _etag;
}
  • En savoir plus sur Verrouillage optimiste ici

Requête personnalisée Spring Data, pagination et tri

  • Azure-spring-data-cosmos prend en charge les requêtes personnalisées Spring Data.
  • Exemple d’opération de recherche : findByAFieldAndBField.
  • Prend en charge les types Spring Data Pageable, Slice et Sort.
    • En fonction des unités de requête disponibles sur le compte de base de données, Cosmos DB peut retourner des éléments inférieurs ou égaux à la taille demandée.
    • En raison du nombre variable d’éléments retournés dans chaque itération, l’utilisateur ne doit pas se fier à totalPageSize. Au lieu de cela, effectuez l’itération sur Pageable de cette façon.
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 prend en charge spring-boot-starter-data-rest.
  • Prend en charge les listes et le type imbriqué dans la classe de domaine.
  • Haricot ObjectMapper configurable avec un nom cosmosObjectMapperunique , configurez uniquement objectMapper personnalisé si vous en avez vraiment besoin. par exemple,
@Bean(name = "cosmosObjectMapper")
public ObjectMapper objectMapper() {
    return new ObjectMapper(); // Do configuration to the ObjectMapper if required
}

Audit

  • Azure-spring-data-cosmos prend en charge l’audit des champs sur des entités de base de données à l’aide d’annotations Spring Data standard.
  • Cette fonctionnalité peut être activée en ajoutant une annotation @EnableCosmosAuditing à la configuration de votre application.
  • Les entités peuvent annoter des champs avec @CreatedBy, @CreatedDate, @LastModifiedBy et @LastModifiedDate. Ces champs seront mis à jour automatiquement.
@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;
}

Configuration de plusieurs bases de données

  • Azure-spring-data-cosmos prend en charge la configuration de plusieurs bases de données, notamment « plusieurs comptes de base de données » et « un seul compte, plusieurs bases de données ».

Plusieurs comptes de base de données

L’exemple utilise le fichier 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
  • La définition d’Entity et de Repository est semblable à celle ci-dessus. Vous pouvez placer différentes entités de base de données dans différents packages.

  • @EnableReactiveCosmosRepositories et @EnableCosmosRepositories prennent en charge les modèles Cosmos définis par l’utilisateur. Utilisez reactiveCosmosTemplateRef ou cosmosTemplateRef pour configurer le nom du bean ReactiveCosmosTemplate ou CosmosTemplate à utiliser avec les référentiels détectés.

  • Si vous avez plusieurs comptes de base de données Cosmos, vous pouvez définir plusieurs CosmosAsyncClient. Si un seul compte Cosmos comprend plusieurs bases de données, vous pouvez utiliser le même CosmosAsyncClient pour initialiser le modèle 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)
            .maxDegreeOfParallelism(0)
            .maxBufferedItemCount(0)
            .responseContinuationTokenLimitInKb(0)
            .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);
        }
    }
}
  • Dans l’exemple ci-dessus, nous avons deux comptes Cosmos. Vous pouvez créer CosmosAsyncClient comme ceci :
@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)
        .maxDegreeOfParallelism(0)
        .maxBufferedItemCount(0)
        .responseContinuationTokenLimitInKb(0)
        .responseDiagnosticsProcessor(new ResponseDiagnosticsProcessorImplementation())
        .build();
}
  • En outre, si vous souhaitez définir queryMetricsEnabled, ResponseDiagnosticsProcessor, maxDegreeOfParallelismmaxBufferedItemCount ou responseContinuationTokenLimitInKb , vous pouvez créer le CosmosConfig pour votre modèle cosmos.
@Bean("secondaryCosmosConfig")
public CosmosConfig getCosmosConfig() {
    return CosmosConfig.builder()
        .enableQueryMetrics(true)
        .maxDegreeOfParallelism(0)
        .maxBufferedItemCount(0)
        .responseContinuationTokenLimitInKb(0)
        .responseDiagnosticsProcessor(new ResponseDiagnosticsProcessorImplementation())
        .build();
}
  • Créer une classe 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();
    }
}

Compte unique avec plusieurs bases de données

L’exemple utilise le fichier 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
  • La définition d’Entity et de Repository est semblable à celle ci-dessus. Vous pouvez placer différentes entités de base de données dans différents packages.
  • Vous pouvez utiliser EnableReactiveCosmosRepositories avec un reactiveCosmosTemplateRef différent pour définir plusieurs bases de données dans un seul compte Cosmos.
@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);
        }

    }
}
  • Créer une classe 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();
    }
}

Multi-location au niveau de la base de données

  • Azure-spring-data-cosmos prend en charge l’architecture mutualisée au niveau de la base de données en étendant CosmosFactory et en remplaçant la fonction getDatabaseName().
public class MultiTenantDBCosmosFactory extends CosmosFactory {

    private String tenantId;

    /**
     * Validate config and initialization
     *
     * @param cosmosAsyncClient cosmosAsyncClient
     * @param databaseName      databaseName
     */
    public MultiTenantDBCosmosFactory(CosmosAsyncClient cosmosAsyncClient, String databaseName) {
        super(cosmosAsyncClient, databaseName);

        this.tenantId = databaseName;
    }

    @Override
    public String getDatabaseName() {
        return this.getCosmosAsyncClient().getDatabase(this.tenantId).toString();
    }
}

Package de la version bêta

La version bêta générée à partir de la branche main est disponible. Vous pouvez consulter les instructions pour utiliser des packages en version bêta.

Dépannage

Général

Si vous rencontrez des bogues, signalez un problème ici.

Pour suggérer une nouvelle fonctionnalité ou des modifications, signalez un problème comme vous le feriez pour un bogue.

Activer la journalisation du client

  • Azure-spring-data-cosmos utilise log4j comme façade de journalisation prenant en charge la journalisation dans les frameworks de journalisation connus tels que log4j et logback. Par exemple, si vous souhaitez utiliser spring logback comme framework de journalisation, ajoutez le code XML suivant au dossier resources.
<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>

Exemples

Plusieurs comptes de base de données

Compte unique avec plusieurs bases de données

Étapes suivantes

Contribution

Ce projet accepte les contributions et les suggestions. La plupart des contributions vous demandent d’accepter un contrat de licence de contribution (CLA) spécifiant que vous avez le droit de nous accorder les droits d’utiliser votre contribution, et que vous nous les accordez.

Quand vous envoyez une demande de tirage (pull request), un bot CLA détermine automatiquement si vous devez fournir un contrat CLA et agrémenter la demande de tirage de façon appropriée (par exemple, avec une étiquette ou un commentaire). Suivez simplement les instructions fournies par le bot. Vous ne devez effectuer cette opération qu’une seule fois sur tous les dépôts utilisant notre contrat CLA.

Ce projet a adopté le Code de conduite Open Source de Microsoft. Pour plus d’informations, consultez les Questions fréquentes (FAQ) sur le code de conduite ou envoyez vos questions ou vos commentaires à opencode@microsoft.com.

Impressions