Share via


Biblioteca cliente de Azure Spring Data Cosmos para Java: versión 5.6.0

Azure Spring Data Cosmos proporciona compatibilidad con Spring Data para Azure Cosmos DB mediante la SQL API, basada en la plataforma de Spring Data. Azure Cosmos DB es un servicio de base de datos de distribución global que permite a los desarrolladores trabajar con datos mediante diversas API estándar, como SQL, MongoDB, Cassandra, Graph y Table.

Directiva de soporte técnico de Spring Boot

Este proyecto admite varias versiones de Spring Boot. Para obtener una lista completa de las versiones admitidas actualmente, visite nuestra asignación de versiones de Spring.

Las versiones de Spring Boot se marcan como "Fin de la vida útil" cuando ya no se admiten ni se lanzan en ningún formulario. Si ejecuta una versión de EOL, debe actualizar lo antes posible.

Tenga en cuenta que una versión puede estar fuera de soporte técnico antes de que se marque como "Fin de vida". Durante este tiempo, solo debe esperar versiones para errores críticos o problemas de seguridad.

Para obtener más información sobre las versiones compatibles con Spring Boot, visite Versiones admitidas de Spring Boot.

Compatibilidad con versiones de Spring Boot

Los usuarios de Maven pueden heredar del proyecto spring-boot-starter-parent para obtener una sección de administración de dependencias que permita a Spring administrar las versiones para las dependencias.

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

Con esta configuración, también puede invalidar dependencias individuales al invalidar una propiedad en su propio proyecto. Por ejemplo, para actualizar a otra serie de versiones de Spring Data, agregaría lo siguiente a pom.xml.

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

Si no desea utilizar spring-boot-starter-parent, todavía puede mantener las ventajas de la administración de dependencias mediante una dependencia 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>

¿Qué versión de Azure Spring Data Cosmos debo usar?

Asignación de la versión de Spring Boot / Spring Cloud a las versiones de Azure Spring Data Cosmos

Versión de Spring Boot Versión de Spring Cloud Versiones de Azure Spring Data Cosmos
3.0.x 2022.0.x 5.3.0 y versiones posteriores
2.7.x 2021.0.x 3.23.0 y versiones posteriores
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

Uso la versión X de Spring Boot

Si usa Spring Boot en el proyecto, puede encontrar versiones relacionadas de Azure Spring Data Cosmos de la tabla anterior. Por ejemplo: si usa Spring Boot 3.0.x, debe usar las versiones 5.3.0 y posteriores de Azure Spring Data Cosmos .

Uso la versión Y de Spring Cloud

Si usa Spring Cloud en el proyecto, también puede encontrar versiones relacionadas de Azure Spring Data Cosmos de la tabla anterior. Por ejemplo, si usa Spring Cloud 2022.0.x, debe usar las versiones 5.3.0 y posteriores de Azure Spring Data Cosmos .

Compatibilidad con versiones de Spring Data

Este proyecto admite spring-data-commons 3.0.x versiones.

La configuración anterior no permite invalidar las dependencias individuales mediante una propiedad como se explicó anteriormente. Para lograr el mismo resultado, debe agregar una entrada en dependencyManagement del proyecto antes de la entrada spring-boot-dependencies. Por ejemplo, para actualizar a otra serie de versiones de Spring Data, agregaría lo siguiente a 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>

Nota: Reemplace ${spring.boot.version} y ${spring.data.version} por las versiones de Spring Boot y Spring Data que desee utilizar en el proyecto.

Introducción

Inclusión del paquete

Si utiliza Maven, agregue la siguiente dependencia.

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

Prerrequisitos

  • Kit de desarrollo de Java (JDK), versión 8 o posterior.
  • Una cuenta de Azure activa. Si no tiene una, puede registrarse para obtener una cuenta gratuita. Como alternativa, puede usar el Emulador de Azure Cosmos DB para el desarrollo y las pruebas. Como el certificado https del emulador está autofirmado, debe importar su certificado en el almacén de certificados de confianza de Java, que se explica aquí.
  • (Opcional) SLF4J es una fachada de registro.
  • (Opcional) El enlace SLF4J se utiliza para asociar una plataforma de registro específica a SLF4J.
  • (Opcional) Maven

SLF4J solo es necesario si planea utilizar el registro; descargue también un enlace SLF4J que vinculará SLF4J API con la implementación de registro de su elección. Consulte el manual del usuario de SLF4J para más información.

Configuración de la clase Configuration

  • Para configurar la clase Configuration, deberá ampliar AbstractCosmosConfiguration.

  • Azure-spring-data-cosmos también admite Response Diagnostics String, Query Metrics y Max Degree of Parallelism. Establezca la marca queryMetricsEnabled en true en application.properties para habilitar las métricas de consulta. Además de establecer la marca, implemente ResponseDiagnosticsProcessor para registrar la información de diagnóstico. Establezca maxDegreeOfParallelism la marca en un entero en application.properties para permitir el procesamiento paralelo; establecer el valor en -1 dará lugar a que el SDK decida el valor óptimo. Establezca maxBufferedItemCount la marca en un entero de application.properties para permitir al usuario establecer el número máximo de elementos que se pueden almacenar en búfer durante la ejecución de consultas paralelas; si se establece en menos de 0, el sistema decide automáticamente el número de elementos que se van a almacenar en búfer. NOTA: Establecer esto en un valor muy alto puede dar lugar a un consumo elevado de memoria. Establezca responseContinuationTokenLimitInKb la marca en un entero en application.properties para permitir al usuario limitar la longitud del token de continuación en la respuesta de consulta. El token de continuación contiene campos obligatorios y opcionales. Los campos obligatorios son necesarios para reanudar la ejecución desde donde se detuvo. Los campos opcionales pueden contener trabajo de búsqueda de índice serializado que se realizó pero que aún no se ha utilizado. Esto evita volver a rehacer el trabajo en las continuaciones posteriores y, por tanto, mejorar el rendimiento de las consultas. Si se establece el tamaño máximo de continuación en 1 KB, el servicio Azure Cosmos DB solo serializará los campos necesarios. A partir de 2 KB, el servicio Azure Cosmos DB serializaría tanto como pudiera caber hasta que alcance el tamaño máximo especificado. Establezca pointOperationLatencyThresholdInMS, nonPointOperationLatencyThresholdInMSrequestChargeThresholdInRU y payloadSizeThresholdInBytes para habilitar los diagnósticos en el nivel de cliente cuando se superen estos umbrales.

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

}

Personalización de la configuración

Puede personalizar DirectConnectionConfig o ambos y proporcionarlos para CosmosClientBuilder que se personalicen. Puede personalizar CosmosAsyncClientpointOperationLatencyThresholdInMS, requestChargeThresholdInRUnonPointOperationLatencyThresholdInMSy payloadSizeThresholdInBytes para personalizar los umbrales para el registro de diagnóstico cuando se combina con CosmosDiagnosticsHandler el que se habilita el registro de diagnóstico con los umbrales predeterminados cuando se agrega a CosmosClientBuilder.GatewayConnectionConfig

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

De forma predeterminada, @EnableCosmosRepositories examinará el paquete actual en busca de interfaces que extiendan una de las interfaces del repositorio de Spring Data. Utilícelo para anotar la clase Configuration a fin de examinar un paquete raíz diferente mediante @EnableCosmosRepositories(basePackageClass=UserRepository.class) si el diseño del proyecto tiene varios proyectos.

Habilitación del registro de diagnósticos para Aplicación de Azure Insights con JavaAgent

Los diagnósticos se pueden habilitar pasando JavaAgent con la aplicación como se indica a continuación. Esto habilitará el registro con los umbrales predeterminados. Se debe pasar "-javaagent" antes de "-jar".

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

Uso del rendimiento aprovisionado de la base de datos

Cosmos admite el rendimiento aprovisionado de contenedor y base de datos . De forma predeterminada, spring-data-cosmos aprovisionará el rendimiento de cada contenedor creado. Si prefiere compartir el rendimiento entre contenedores, puede habilitar el rendimiento aprovisionado de la base de datos mediante CosmosConfig.

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

Definición de una entidad

  • Defina una entidad simple como elemento en Azure Cosmos DB.

  • Para definir entidades, puede agregar la anotación @Container y especificar las propiedades relacionadas con el contenedor, como el nombre del contenedor, las unidades de solicitud (RU), el período de vida y la marca de creación automática del contenedor.

  • Los contenedores se crearán automáticamente a menos que no lo quiera. Establezca autoCreateContainer en false en la anotación @Container para deshabilitar la creación automática de contenedores.

  • Nota: De forma predeterminada, las unidades de solicitud asignadas a los contenedores recién creados son 400. Especifique un valor de RU diferente para personalizar las unidades de solicitud para el contenedor creado por el SDK (el valor mínimo de RU es de 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 field se usará como id. de elemento en Azure Cosmos DB. Si desea usar otro campo como firstName elemento id, simplemente anote ese campo con @Id anotación.

  • La anotación @Container(containerName="myContainer") especifica el nombre del contenedor en Azure Cosmos DB.

  • La anotación @PartitionKey en el campo lastName especifica este campo como clave de partición en Azure Cosmos DB.

Creación de contenedores con un rendimiento de escalabilidad automática

  • El campo autoScale de la anotación especifica el contenedor que se va a crear con un rendimiento de escalabilidad automática si se establece en true. El valor predeterminado es false, lo que significa que los contenedores se crean con un rendimiento manual.
  • Lea más información sobre el rendimiento de escalabilidad automática aquí.
@Container(containerName = "myContainer", autoScale = true, ru = "4000")
public class UserSample {
    @Id
    private String emailAddress;

}

Compatibilidad con la clave de partición anidada

  • Azure Spring Data Cosmos admite la clave de partición anidada. Para agregar la clave de partición anidada, utilice el campo partitionKeyPath de la anotación @Container.
  • Solo se debe utilizar partitionKeyPath para que admita la ruta de acceso de la clave de partición anidada. Para obtener una compatibilidad general con la clave de partición, utilice la anotación @PartitionKey.
  • De forma predeterminada, la anotación @PartitionKey tendrá prioridad, a menos que no se especifique.
  • En el ejemplo siguiente se muestra cómo usar correctamente la característica de clave de partición anidada.
@Container(containerName = "nested-partition-key", partitionKeyPath = "/nestedEntitySample/nestedPartitionKey")
public class NestedPartitionKeyEntitySample {

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

Creación de repositorios

Extiende la interfaz de CosmosRepository, que proporciona compatibilidad con el repositorio de 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);
}
  • El método findByFirstName es un método de consulta personalizado que buscará elementos por firstName.

Almacenamiento en caché del plan de consulta

Las API de consulta del repositorio de Spring, como findByFirstName(String firstName) donde firstName es la partición o las consultas anotadas que contienen la clave de partición, darán lugar a un menor tiempo de ejecución de consultas debido al almacenamiento en caché del plan de consulta. Actualmente, el almacenamiento en caché del plan de consulta solo se admite para los métodos de consulta destinados a una sola partición.

QueryAnnotation: uso de consultas anotadas en repositorios

Azure Spring Data Cosmos admite la especificación de consultas anotadas en los repositorios mediante @Query.

  • Ejemplos de consultas anotadas en CosmosRepository sincrónico:
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);
}
  • Ejemplos de consultas anotadas en 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);
}

Las consultas especificadas en la anotación son las mismas que las consultas de Cosmos. Consulte los artículos siguientes para más información sobre las consultas SQL en Cosmos.

Creación de una clase Application

Aquí se crea una clase Application con todos los componentes.

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

    }
}
  • Conexión automática de la interfaz UserRepository para realizar operaciones como save, delete, find, etc.
  • Spring Data Azure Cosmos DB utiliza CosmosTemplate y ReactiveCosmosTemplate para ejecutar las consultas detrás de los métodos find y save. Puede utilizar la plantilla usted mismo para consultas más complejas.

Conceptos clave

CrudRepository y ReactiveCrudRepository

  • Azure Spring Data Cosmos admite ReactiveCrudRepository y CrudRepository que proporciona la funcionalidad CRUD básica.
    • Guardar
    • findAll
    • findOne por id.
    • deleteAll
    • delete by Id
    • delete entity

Anotaciones de Spring Data

Anotación de Spring Data @Id

Hay dos maneras de asignar un campo de clase de dominio al campo id de elemento de Azure Cosmos DB.

  • anotar un campo en la clase de dominio con @Id, este campo se asignará al elemento id de Cosmos DB.
  • establecer el nombre de este campo en id, este campo se asignará al elemento id de Azure Cosmos DB.

Generación automática de identificadores

  • Admite la generación automática de UUID de tipo cadena mediante la anotación @GeneratedValue. El campo id de una entidad con un identificador de tipo de cadena se puede anotar con @GeneratedValue para generar automáticamente un UUID aleatorio antes de la inserción.
public class GeneratedIdEntity {

    @Id
    @GeneratedValue
    private String id;

}

Expresión SpEL y nombre de contenedor personalizado.

  • De forma predeterminada, el nombre del contenedor será el nombre de clase de la clase de dominio de usuario. Para personalizarlo, agregue la anotación @Container(containerName="myCustomContainerName") a la clase de dominio. El campo contenedor también admite expresiones SpEL (por ejemplo container = "${dynamic.container.name}" , o container = "#{@someBean.getContainerName()}") para proporcionar nombres de contenedor mediante programación o mediante propiedades de configuración.
  • Para que las expresiones SpEL funcionen correctamente, debe agregar @DependsOn("expressionResolver") a partir de la clase Spring Application.
@SpringBootApplication
@DependsOn("expressionResolver")
public class SampleApplication {
    
}

Directiva de indexación

  • De forma predeterminada, El servicio Azure Portal establecerá IndexingPolicy. Para personalizarlo, agregue una anotación @CosmosIndexingPolicy a la clase de dominio. Esta anotación tiene 5 atributos para personalizar, consulte lo siguiente:
// 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 {};

Directiva de clave única

  • Azure Spring Data Cosmos admite la configuración UniqueKeyPolicy en el contenedor agregando la anotación @CosmosUniqueKeyPolicy a la clase de dominio. Esta anotación tiene los siguientes atributos:
@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;
}

Partición de Azure Cosmos DB

  • Azure-spring-data-cosmos admite la partición de Azure Cosmos DB.
  • Para especificar que un campo de clase de dominio sea un campo de clave de partición, solo tiene que anotarlo con @PartitionKey.
  • Cuando realice una operación CRUD, especifique el valor de la partición.
  • Para obtener más ejemplos de CRUD de partición, consulte la prueba aquí.

Bloqueo optimista

  • Azure-spring-data-cosmos admite el bloqueo optimista para contenedores específicos, lo que significa que las operaciones upsert/delete por elemento producirán un error con una excepción en caso de que otro proceso modifique el elemento mientras tanto.
  • Si quiere habilitar el bloqueo optimista para un contenedor, basta con crear un campo _etag de cadena y marcarlo con la anotación @Version. Consulte lo siguiente:
@Container(containerName = "myContainer")
public class MyItem {
    String id;
    String data;
    @Version
    String _etag;
}
  • Obtenga más información sobre el bloqueo optimista aquí.

Consulta personalizada, paginable y ordenación de Spring Data

  • Azure-spring-data-cosmos admite consultas personalizadas de Spring Data.
  • Por ejemplo, una operación find, como findByAFieldAndBField
  • Admite Pageable, Slice y Sort de Spring Data.
    • En función de las unidades de solicitud (RU) disponibles en la cuenta de base de datos, cosmosDB puede devolver elementos menores o iguales que el tamaño solicitado.
    • Debido a este número variable de elementos devueltos en cada iteración, el usuario no debe confiar en totalPageSize y, en su lugar, debe realizar la iteración sobre Pageable de esta manera.
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 admite spring-boot-starter-data-rest.
  • Admite List y el tipo anidado en la clase de dominio.
  • Bean de ObjectMapper configurable con el nombre cosmosObjectMapperúnico , solo configure ObjectMapper personalizado si realmente necesita, por ejemplo,
@Bean(name = "cosmosObjectMapper")
public ObjectMapper objectMapper() {
    return new ObjectMapper(); // Do configuration to the ObjectMapper if required
}

Auditoría

  • Azure-spring-data-cosmos admite la auditoría de campos en entidades de bases de datos mediante anotaciones de spring-data estándar.
  • Para habilitar esta característica, agregue una anotación @EnableCosmosAuditing a la configuración de la aplicación.
  • Las entidades pueden anotar campos mediante @CreatedBy, @CreatedDate, @LastModifiedBy y @LastModifiedDate. Estos campos se actualizarán automáticamente.
@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;
}

Configuración de varias bases de datos

  • Azure-spring-data-cosmos admite la configuración de varias bases de datos, incluidas "cuentas de varias bases de datos" y "cuenta única, con varias bases de datos".

Cuentas de varias bases de datos

En el ejemplo se utiliza el archivo 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 definición de Entity y Repository es similar a la anterior. Puede colocar diferentes entidades de bases de datos en distintos paquetes.

  • @EnableReactiveCosmosRepositories o @EnableCosmosRepositories admiten la plantilla de Cosmos definida por el usuario, utilice reactiveCosmosTemplateRef o cosmosTemplateRef para configurar el nombre del bean ReactiveCosmosTemplate o CosmosTemplate que se usará con los repositorios detectados.

  • Si tiene cuentas de Cosmos de varias bases de datos, puede definir varios CosmosAsyncClient. Si la cuenta de Cosmos única tiene varias bases de datos, puede utilizar el mismo CosmosAsyncClient para inicializar la plantilla de 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);
        }
    }
}
  • En el ejemplo anterior, tenemos dos cuentas de Cosmos. Puede crear CosmosAsyncClient del modo siguiente:
@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();
}
  • Además, si desea definir queryMetricsEnabled, ResponseDiagnosticsProcessormaxDegreeOfParallelism, maxBufferedItemCount o responseContinuationTokenLimitInKb , puede crear para la CosmosConfig plantilla de Cosmos.
@Bean("secondaryCosmosConfig")
public CosmosConfig getCosmosConfig() {
    return CosmosConfig.builder()
        .enableQueryMetrics(true)
        .maxDegreeOfParallelism(0)
        .maxBufferedItemCount(0)
        .responseContinuationTokenLimitInKb(0)
        .responseDiagnosticsProcessor(new ResponseDiagnosticsProcessorImplementation())
        .build();
}
  • Creación de una clase 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();
    }
}

Cuenta única con varias bases de datos

En el ejemplo se utiliza el archivo 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 definición de Entity y Repository es similar a la anterior. Puede colocar diferentes entidades de bases de datos en distintos paquetes.
  • Puede utilizar EnableReactiveCosmosRepositories con diferentes reactiveCosmosTemplateRef para definir varias bases de datos en una única cuenta de 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);
        }

    }
}
  • Creación de una clase 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();
    }
}

Multiinquilino en el nivel de base de datos

  • Azure-spring-data-cosmos admite multiinquilino en la configuración de nivel de base de datos mediante la extensión CosmosFactory y invalidación de la función 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();
    }
}

Paquete de la versión beta

Está disponible la versión beta creada a partir de la rama main; puede consultar la instrucción para utilizar paquetes de la versión beta.

Solución de problemas

General

Si encuentra algún error, registre una incidencia aquí.

Para sugerir una nueva característica o cambios que se podrían realizar, registre una incidencia de la misma manera que haría en el caso de un error.

Habilitación del registro de cliente

  • Azure-spring-data-cosmos utiliza SLF4j como fachada de registro, que admite el registro en plataformas de registro populares como log4j y logback. Por ejemplo, si desea utilizar Spring Logback como plataforma de registro, agregue el siguiente xml a la carpeta de recursos.
<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>

Ejemplos

Cuentas de varias bases de datos

Cuenta única con varias bases de datos

Pasos siguientes

Contribuciones

Este proyecto agradece las contribuciones y sugerencias. La mayoría de las contribuciones requieren que acepte un Contrato de licencia para el colaborador (CLA) que declara que tiene el derecho a concedernos y nos concede los derechos para usar su contribución.

Cuando se envía una solicitud de incorporación de cambios, un bot de CLA determinará de forma automática si tiene que aportar un CLA y completar la PR adecuadamente (por ejemplo, la etiqueta, el comentario). Solo siga las instrucciones que le dará el bot. Solo será necesario que lo haga una vez en todos los repositorios con nuestro CLA.

Este proyecto ha adoptado el Código de conducta de Microsoft Open Source. Para más información, consulte las preguntas más frecuentes del código de conducta o póngase en contacto con opencode@microsoft.com si tiene cualquier otra pregunta o comentario.

Impresiones