使用Spring Boot连接Azure Cosmos DB

我用Spring Boot访问了Azure CosmosDB(MongoDB核心),这是记录。

我感到懶得寫代碼,因此參考了https://spring.pleiades.io/guides/gs/accessing-data-mongodb/。

首先,按照常规方式将示例代码进行git clone操作。

$ git clone https://github.com/spring-guides/gs-accessing-data-mongodb.git

按照教程在本地搭建MongoDB。

$ sudo apt install mongodb
$ mkdir -p data/db
$ mongod --dbpath=./data/db

在Gradle中运行。

$ gradle bootRun

Welcome to Gradle 6.5.1!

Here are the highlights of this release:
 - Experimental file-system watching
 - Improved version ordering
 - New samples

For more details see https://docs.gradle.org/6.5.1/release-notes.html

Starting a Gradle Daemon (subsequent builds will be faster)

> Task :bootRun

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.0.RELEASE)

2020-07-02 03:12:00.912  INFO 32643 --- [           main] c.e.a.AccessingDataMongodbApplication    : Starting AccessingDataMongodbApplication on DESKTOP-N9T4CN3 with PID 32643 (XXX/gs-accessing-data-mongodb/complete/build/classes/java/main started by XXX in XXX/gs-accessing-data-mongodb/complete)
2020-07-02 03:12:00.917  INFO 32643 --- [           main] c.e.a.AccessingDataMongodbApplication    : No active profile set, falling back to default profiles: default
2020-07-02 03:12:01.274  INFO 32643 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
2020-07-02 03:12:01.315  INFO 32643 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 36ms. Found 1 repository interfaces.
2020-07-02 03:12:01.589  INFO 32643 --- [           main] org.mongodb.driver.cluster               : Cluster created with settings {hosts=[localhost:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500}
2020-07-02 03:12:01.674  INFO 32643 --- [localhost:27017] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:1, serverValue:1}] to localhost:27017
2020-07-02 03:12:01.678  INFO 32643 --- [localhost:27017] org.mongodb.driver.cluster               : Monitor thread successfully connected to server with description ServerDescription{address=localhost:27017, type=STANDALONE, state=CONNECTED, ok=true, version=ServerVersion{versionList=[3, 6, 8]}, minWireVersion=0, maxWireVersion=6, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=2881100}
2020-07-02 03:12:01.745  WARN 32643 --- [           main] o.s.data.convert.CustomConversions       : Registering converter from class java.time.LocalDateTime to class java.time.Instant as reading converter although it doesn't convert from a store-supported type! You might wanna check you annotation setup at the converter implementation.
2020-07-02 03:12:01.745  WARN 32643 --- [           main] o.s.data.convert.CustomConversions       : Registering converter from class java.time.Instant to class java.time.LocalDateTime as reading converter although it doesn't convert from a store-supported type! You might wanna check you annotation setup at the converter implementation.
2020-07-02 03:12:01.771  WARN 32643 --- [           main] o.s.data.convert.CustomConversions       : Registering converter from class java.time.LocalDateTime to class java.time.Instant as reading converter although it doesn't convert from a store-supported type! You might wanna check you annotation setup at the converter implementation.
2020-07-02 03:12:01.771  WARN 32643 --- [           main] o.s.data.convert.CustomConversions       : Registering converter from class java.time.Instant to class java.time.LocalDateTime as reading converter although it doesn't convert from a store-supported type! You might wanna check you annotation setup at the converter implementation.
2020-07-02 03:12:02.134  INFO 32643 --- [           main] c.e.a.AccessingDataMongodbApplication    : Started AccessingDataMongodbApplication in 1.552 seconds (JVM running for 1.853)
2020-07-02 03:12:02.157  INFO 32643 --- [           main] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:2, serverValue:2}] to localhost:27017
Customers found with findAll():
-------------------------------
Customer[id=5efcd1f2b15c223a7dc2a9ce, firstName='Alice', lastName='Smith']
Customer[id=5efcd1f2b15c223a7dc2a9cf, firstName='Bob', lastName='Smith']

Customer found with findByFirstName('Alice'):
--------------------------------
Customer[id=5efcd1f2b15c223a7dc2a9ce, firstName='Alice', lastName='Smith']
Customers found with findByLastName('Smith'):
--------------------------------
Customer[id=5efcd1f2b15c223a7dc2a9ce, firstName='Alice', lastName='Smith']
Customer[id=5efcd1f2b15c223a7dc2a9cf, firstName='Bob', lastName='Smith']
2020-07-02 03:12:02.270  INFO 32643 --- [extShutdownHook] org.mongodb.driver.connection            : Closed connection [connectionId{localValue:2, serverValue:2}] to localhost:27017 because the pool has been closed.

BUILD SUCCESSFUL in 53s
2 actionable tasks: 2 executed

我要用mongo命令来查看内部。

$ mongo
MongoDB shell version v3.6.8
connecting to: mongodb://127.0.0.1:27017
Implicit session: session { "id" : UUID("2648d101-f236-4f56-bc3d-7250d32ef9a2") }
MongoDB server version: 3.6.8
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
        http://docs.mongodb.org/
Questions? Try the support group
        http://groups.google.com/group/mongodb-user
Server has startup warnings: 
2020-07-02T02:54:56.366+0900 I STORAGE  [initandlisten] 
2020-07-02T02:54:56.366+0900 I STORAGE  [initandlisten] ** WARNING: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine
2020-07-02T02:54:56.366+0900 I STORAGE  [initandlisten] **          See http://dochub.mongodb.org/core/prodnotes-filesystem
2020-07-02T02:54:57.070+0900 I CONTROL  [initandlisten] 
2020-07-02T02:54:57.070+0900 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2020-07-02T02:54:57.070+0900 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2020-07-02T02:54:57.070+0900 I CONTROL  [initandlisten] 
2020-07-02T02:54:57.070+0900 I CONTROL  [initandlisten] ** WARNING: This server is bound to localhost.
2020-07-02T02:54:57.070+0900 I CONTROL  [initandlisten] **          Remote systems will be unable to connect to this server. 
2020-07-02T02:54:57.070+0900 I CONTROL  [initandlisten] **          Start the server with --bind_ip <address> to specify which IP 
2020-07-02T02:54:57.070+0900 I CONTROL  [initandlisten] **          addresses it should serve responses from, or with --bind_ip_all to
2020-07-02T02:54:57.070+0900 I CONTROL  [initandlisten] **          bind to all interfaces. If this behavior is desired, start the
2020-07-02T02:54:57.070+0900 I CONTROL  [initandlisten] **          server with --bind_ip 127.0.0.1 to disable this warning.
2020-07-02T02:54:57.070+0900 I CONTROL  [initandlisten] 
2020-07-02T02:54:57.071+0900 I CONTROL  [initandlisten] 
2020-07-02T02:54:57.071+0900 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2020-07-02T02:54:57.071+0900 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2020-07-02T02:54:57.071+0900 I CONTROL  [initandlisten] 
> db.customer.find()
{ "_id" : ObjectId("5efcd1f2b15c223a7dc2a9ce"), "firstName" : "Alice", "lastName" : "Smith", "_class" : "com.example.accessingdatamongodb.Customer" }
{ "_id" : ObjectId("5efcd1f2b15c223a7dc2a9cf"), "firstName" : "Bob", "lastName" : "Smith", "_class" : "com.example.accessingdatamongodb.Customer" }
> 

进来了。

在这个阶段,教程还未连接到 MongoDB 数据库。目前已经实现的数据访问只有以下两个部分。

package com.example.accessingdatamongodb;

import org.springframework.data.annotation.Id;

public class Customer {
    @Id
    public String id;
    public String firstName;
    public String lastName;
    public Customer() {}
    public Customer(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    @Override
    public String toString() {
        return String.format(
                "Customer[id=%s, firstName='%s', lastName='%s']",
                id, firstName, lastName);
    }
}
package com.example.accessingdatamongodb;

import java.util.List;
import org.springframework.data.mongodb.repository.MongoRepository;

public interface CustomerRepository extends MongoRepository<Customer, String> {
    public Customer findByFirstName(String firstName);
    public List<Customer> findByLastName(String lastName);
}

使用高级API Repository,因此实现非常简单。实际上,Spring Data MongoDB会自动生成实现CustomerRepository接口的类,并可使用save和find等方法。非常方便。(而使用低级API TemplateMongo,则可以进行更复杂的操作)

由于本次的主要目的是访问基于MongoDB核心创建的CosmosDB,因此我们将使用这个使用高级API的示例。

在Azure上创建CosmosDB。我们可以参考https://docs.microsoft.com/ja-jp/azure/cosmos-db/create-mongodb-java#create-a-database-account从Portal上快速创建。无需创建集合。

image.png

在示例代码中添加main/resources/application.properties,并添加”spring.data.mongodb.uri”,将先前复制的值粘贴进去。如果Mongo DB Driver版本是3.6或更高,则在末尾添加”&retrywrites=false”,因为Cosmos DB目前不支持可重试写入。

spring.data.mongodb.uri=<your_connection_string>&retrywrites=false

为了使用定义过的URL,我们需要创建一个配置文件。

package com.example.accessingdatamongodb;

import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CustomerRepositoryConfig {
    @Value("${spring.data.mongodb.uri:mongodb://localhost:27017}")
    public String connectionString;
    public @Bean MongoClient mongoClient() {
        return MongoClients.create(this.connectionString);
    }
}

我們將使用Gradle來執行。

$ gradle bootRun -Pargs=--debug

> Task :bootRun

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.0.RELEASE)

2020-07-02 04:54:56.451  INFO 3822 --- [           main] c.e.a.AccessingDataMongodbApplication    : Starting AccessingDataMongodbApplication on DESKTOP-N9T4CN3 with PID 3822 (XXX/gs-accessing-data-mongodb/complete/build/classes/java/main started by XXX in XXX/gs-accessing-data-mongodb/complete)
2020-07-02 04:54:56.456  INFO 3822 --- [           main] c.e.a.AccessingDataMongodbApplication    : No active profile set, falling back to default profiles: default
2020-07-02 04:54:57.370  INFO 3822 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data repositories in DEFAULT mode.
2020-07-02 04:54:57.497  INFO 3822 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 118ms. Found 1 repository interfaces.
2020-07-02 04:54:58.011  INFO 3822 --- [           main] org.mongodb.driver.cluster               : Cluster created with settings {hosts=[XXX:YYY], mode=MULTIPLE, requiredClusterType=REPLICA_SET, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500, requiredReplicaSetName='globaldb'}
2020-07-02 04:54:58.011  INFO 3822 --- [           main] org.mongodb.driver.cluster               : Adding discovered server XXX:YYY to client view of cluster
2020-07-02 04:54:58.244  WARN 3822 --- [           main] o.s.data.convert.CustomConversions       : Registering converter from class java.time.LocalDateTime to class java.time.Instant as reading converter although it doesn't convert from a store-supported type! You might wanna check you annotation setup at the converter implementation.
2020-07-02 04:54:58.245  WARN 3822 --- [           main] o.s.data.convert.CustomConversions       : Registering converter from class java.time.Instant to class java.time.LocalDateTime as reading converter although it doesn't convert from a store-supported type! You might wanna check you annotation setup at the converter implementation.
2020-07-02 04:54:58.316  WARN 3822 --- [           main] o.s.data.convert.CustomConversions       : Registering converter from class java.time.LocalDateTime to class java.time.Instant as reading converter although it doesn't convert from a store-supported type! You might wanna check you annotation setup at the converter implementation.
2020-07-02 04:54:58.317  WARN 3822 --- [           main] o.s.data.convert.CustomConversions       : Registering converter from class java.time.Instant to class java.time.LocalDateTime as reading converter although it doesn't convert from a store-supported type! You might wanna check you annotation setup at the converter implementation.
2020-07-02 04:54:58.912  INFO 3822 --- [           main] c.e.a.AccessingDataMongodbApplication    : Started AccessingDataMongodbApplication in 3.129 seconds (JVM running for 3.84)
2020-07-02 04:54:58.947  INFO 3822 --- [           main] org.mongodb.driver.cluster               : No server chosen by com.mongodb.client.internal.MongoClientDelegate$1@210386e0 from cluster description ClusterDescription{type=REPLICA_SET, connectionMode=MULTIPLE, serverDescriptions=[ServerDescription{address=XXX:YYY, type=UNKNOWN, state=CONNECTING}]}. Waiting for 30000 ms before timing out
2020-07-02 04:54:59.082  INFO 3822 --- [azure.com:10255] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:1, serverValue:1162392059}] to XXX:YYY
2020-07-02 04:54:59.097  INFO 3822 --- [azure.com:10255] org.mongodb.driver.cluster               : Monitor thread successfully connected to server with description ServerDescription{address=XXX:YYY, type=REPLICA_SET_PRIMARY, state=CONNECTED, ok=true, version=ServerVersion{versionList=[3, 6, 0]}, minWireVersion=0, maxWireVersion=6, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=12402600, setName='globaldb', canonicalAddress=XXX:YYY, hosts=[XXX:YYY], passives=[], arbiters=[], primary='XXX:YYY', tagSet=TagSet{[Tag{name='region', value='Japan East'}]}, electionId=null, setVersion=1, lastWriteDate=null, lastUpdateTimeNanos=134393982328436}
2020-07-02 04:54:59.100  INFO 3822 --- [azure.com:10255] org.mongodb.driver.cluster               : Adding discovered server XXX:YYY to client view of cluster
2020-07-02 04:54:59.103  INFO 3822 --- [azure.com:10255] org.mongodb.driver.cluster               : Server XXX:YYY is no longer a member of the replica set.  Removing from client view of cluster.
2020-07-02 04:54:59.105  INFO 3822 --- [azure.com:10255] org.mongodb.driver.cluster               : Canonical address XXX:YYY does not match server address.  Removing XXX:YYY from client view of cluster
2020-07-02 04:54:59.338  INFO 3822 --- [azure.com:10255] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:2, serverValue:689958399}] to XXX:YYY
2020-07-02 04:54:59.348  INFO 3822 --- [azure.com:10255] org.mongodb.driver.cluster               : Monitor thread successfully connected to server with description ServerDescription{address=XXX:YYY, type=REPLICA_SET_PRIMARY, state=CONNECTED, ok=true, version=ServerVersion{versionList=[3, 6, 0]}, minWireVersion=0, maxWireVersion=6, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=8755400, setName='globaldb', canonicalAddress=XXX:YYY, hosts=[XXX:YYY], passives=[], arbiters=[], primary='XXX:YYY', tagSet=TagSet{[Tag{name='region', value='Japan East'}]}, electionId=null, setVersion=1, lastWriteDate=null, lastUpdateTimeNanos=134394233832236}
2020-07-02 04:54:59.349  INFO 3822 --- [azure.com:10255] org.mongodb.driver.cluster               : Setting max set version to 1 from replica set primary XXX:YYY
2020-07-02 04:54:59.349  INFO 3822 --- [azure.com:10255] org.mongodb.driver.cluster               : Discovered replica set primary XXX:YYY
2020-07-02 04:54:59.603  INFO 3822 --- [           main] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:3, serverValue:1139365834}] to XXX:YYY
Customers found with findAll():
-------------------------------
Customer[id=5efcea13cac85c79009dba55, firstName='Alice', lastName='Smith']
Customer[id=5efcea15cac85c79009dba56, firstName='Bob', lastName='Smith']

Customer found with findByFirstName('Alice'):
--------------------------------
Customer[id=5efcea13cac85c79009dba55, firstName='Alice', lastName='Smith']
Customers found with findByLastName('Smith'):
--------------------------------
Customer[id=5efcea13cac85c79009dba55, firstName='Alice', lastName='Smith']
Customer[id=5efcea15cac85c79009dba56, firstName='Bob', lastName='Smith']
2020-07-02 04:55:01.231  INFO 3822 --- [extShutdownHook] org.mongodb.driver.connection            : Closed connection [connectionId{localValue:3, serverValue:1139365834}] to XXX:YYY because the pool has been closed.

BUILD SUCCESSFUL in 8s
3 actionable tasks: 2 executed, 1 up-to-date
image.png

你可以确认数据已经被创建了。

由于最近 Cosmos DB 提供了免费套餐,您可以轻松地尝试功能。请务必体验一下。

广告
将在 10 秒后关闭
bannerAds