Amazon DynamoDB是什么?
Amazon DynamoDB是一种高可伸缩、高性能、无服务器的NoSQL(非关系型)数据库,由Amazon Web Services(AWS)提供。该服务支持数据存储和检索,以及支持多种数据模型,包括文档、键值、列族和图形方式。
DynamoDB使用分布式架构,可以在需要时自动缩放系统,支持弹性容量和自动分片,可扩展性非常高,使其能够支持大规模应用程序和高流量网站。此外,DynamoDB提供了全面的安全功能,包括身份验证和授权、加密和数据审计。它还提供了可扩展的API,支持多种编程语言。
DynamoDB的主要功能包括:
-
可伸缩性:能够按需自动缩放容量和吞吐量,以适应不断变化的应用程序需求。
-
高可用性:支持多个区域同步复制,保证数据的高可靠性和可用性。
-
灵活性:支持多种数据模型以满足不同的应用程序需求。
-
安全性:提供可定制的身份验证和授权,支持加密和数据审计。
总之,DynamoDB是一种强大的NoSQL数据库,非常适合面向云的应用程序和高流量网站。它提供了高可伸缩性、高性能和全面的安全功能,使其成为一种流行的云数据库服务。
Amazon DynamoDB能干什么?
Java NoSQL数据库Amazon DynamoDB通常用于存储大规模的非关系型数据,提供高效的读写性能和可扩展性。它可以运行在云端环境中,如亚马逊的AWS云平台,也可以在私有云或本地计算机上运行。DynamoDB是基于键值对存储的,这意味着它使用唯一的键来查找和访问数据。
DynamoDB通常用于以下场景:DynamoDB通常用于以下场景:
-
Web应用程序:DynamoDB可以用于存储用户数据、日志数据、商品数据、计划任务等等。
-
游戏开发:DynamoDB可以用于存储游戏数据、玩家数据、日志等,提供高效的读写性能和可扩展性,支持实时查询数据。
-
移动应用:DynamoDB可以用于存储用户数据、位置数据、设备信息等,可以提供快速的响应时间,确保用户满意度。
-
物联网应用:DynamoDB可以用于存储和处理传感器数据、设备信息和控制指令等,支持快速访问和实时查询。
DynamoDB解决了传统数据库的以下问题:
-
集中式存储限制:传统数据库通常采用集中式存储,会造成单点故障和性能瓶颈。
-
数据库扩展困难:传统数据库需要手动分区和分布式,需要很多时间和精力来扩展。
-
SQL语句复杂度高:传统数据库需要复杂的SQL语句来查询和管理数据,对非技术人员不友好。
-
大数据查询困难:传统数据库在处理大规模数据时,会遇到性能问题和存储限制。
总之,DynamoDB是一个高效、可扩展、灵活和易用的NoSQL数据库,能够满足各种大规模数据存储和处理需求,是云计算时代的数据存储和管理工具。
面试题
1. 什么是Amazon DynamoDB?
答:Amazon DynamoDB 是一种面向文档的 NoSQL 数据库,能够支持高效的低延迟数据读写,并具有自动化的横向扩展和可靠性。它是 Amazon Web Services (AWS) 的一部分,是一种完全托管的云服务。
2. DynamoDB 的分区键是什么,如何选择分区键?
答:DynamoDB 使用分区键来将数据划分为多个分区,并在多个服务器之间分配负载,进而实现数据的横向扩展。选择分区键时需要考虑以下因素:
- 数据的访问模式:选择经常用于查询和更新的键作为分区键,可以最大化查询和更新的分布式性能。
- 数据均衡性:分区键需要保证数据在分区之间均匀分布,避免某个分区的负载过大。
- 数据扩展性:分区键需要容易添加新的分区以满足未来的增长需求。
3. 如何使用Java SDK 连接 DynamoDB?
答:使用 Java SDK 连接 DynamoDB 需要进行以下步骤:
- 创建 AmazonDynamoDB 对象:可以使用 SDK 提供的 AmazonDynamoDBClientBuilder 类创建 AmazonDynamoDB 对象。
- 创建表格对象:可以使用 SDK 提供的 CreateTableRequest 类定义表格的架构,并使用 AmazonDynamoDBClient.createTable() 方法创建表格。
- 添加数据对象:可以使用 SDK 提供的 PutItemRequest 类添加数据到表格中,并使用 AmazonDynamoDBClient.putItem() 方法添加数据。
- 查询数据对象:可以使用 SDK 提供的 GetItemRequest 类查询数据,并使用 AmazonDynamoDBClient.getItem() 方法查询数据。
示例代码如下:
// 创建 AmazonDynamoDB 对象
AmazonDynamoDB dynamoDB = AmazonDynamoDBClientBuilder.standard().withRegion(Regions.US_WEST_2).build();
// 创建表格对象
CreateTableRequest request = new CreateTableRequest()
.withAttributeDefinitions(new AttributeDefinition("id", ScalarAttributeType.S))
.withKeySchema(new KeySchemaElement("id", KeyType.HASH))
.withProvisionedThroughput(new ProvisionedThroughput(5L, 5L))
.withTableName("sample-table");
dynamoDB.createTable(request);
// 添加数据对象
Map<String, AttributeValue> item = new HashMap<>();
item.put("id", new AttributeValue("test-id"));
item.put("name", new AttributeValue("test-name"));
PutItemRequest putRequest = new PutItemRequest("sample-table", item);
dynamoDB.putItem(putRequest);
// 查询数据对象
Map<String, AttributeValue> key = new HashMap<>();
key.put("id", new AttributeValue("test-id"));
GetItemRequest getRequest = new GetItemRequest("sample-table", key);
Map<String, AttributeValue> result = dynamoDB.getItem(getRequest).getItem();
String name = result.get("name").getS();
4. 如何使用 DynamoDB 进行数据分页?
答:DynamoDB 支持一种特殊的分页机制,称为“分页令牌”。分页令牌是一种指示查询的结果从何处继续的特殊标识符。使用分页令牌需要执行以下步骤:
- 在查询中使用 SDK 提供的 withExclusiveStartKey() 方法设置上一个查询的最后一条记录,作为下一个查询的起始记录。
- 在查询的结果中检查是否存在 LastEvaluatedKey 属性,如果存在,表示还有更多的结果未返回,需要继续查询。
示例代码如下:
// 创建 DynamoDB 对象
AmazonDynamoDB dynamoDB = AmazonDynamoDBClientBuilder.standard().withRegion(Regions.US_WEST_2).build();
// 查询第一页数据
Map<String, AttributeValue> exclusiveStartKey = null;
QueryResult result = null;
do {
QueryRequest request = new QueryRequest("sample-table")
.withExclusiveStartKey(exclusiveStartKey)
.withKeyConditionExpression("id = :val")
.withExpressionAttributeValues(Collections.singletonMap(":val", new AttributeValue("test-id")))
.withLimit(10);
result = dynamoDB.query(request);
for (Map<String, AttributeValue> item : result.getItems()) {
System.out.println(item.get("name").getS());
}
exclusiveStartKey = result.getLastEvaluatedKey();
} while (result.getLastEvaluatedKey() != null);
5. 如何在 DynamoDB 中执行原子计数操作?
答:在 DynamoDB 中执行原子计数操作需要使用 SDK 提供的 AtomicCounter 类,在一个特定的键上自增或自减一个或多个值。示例代码如下:
// 创建 DynamoDB 对象
AmazonDynamoDB dynamoDB = AmazonDynamoDBClientBuilder.standard().withRegion(Regions.US_WEST_2).build();
// 自增一个计数器
UpdateItemRequest request = new UpdateItemRequest()
.withTableName("sample-table")
.withKey(Collections.singletonMap("id", new AttributeValue("test-id")))
.withUpdateExpression("SET #c = #c + :val")
.withConditionExpression("attribute_exists(id)")
.addExpressionAttributeNamesEntry("#c", "counter")
.addExpressionAttributeValuesEntry(":val", new AttributeValue().withN("1"))
.withReturnValues(ReturnValue.ALL_NEW);
Map<String, AttributeValue> result = dynamoDB.updateItem(request).getAttributes();
Long counter = Long.parseLong(result.get("counter").getN());
6. 如何使用 DynamoDB 进行数据批量处理?
答:DynamoDB 支持使用批处理机制,将多个操作集合在一起进行原子性处理。使用批处理需要执行以下步骤:
- 创建 BatchWriteItemRequest 对象,并使用 addTableWriteItemEntries() 方法添加需要处理的表格和操作。
- 调用 AmazonDynamoDBClient.batchWriteItem() 方法执行批量操作。
示例代码如下:
// 创建 DynamoDB 对象
AmazonDynamoDB dynamoDB = AmazonDynamoDBClientBuilder.standard().withRegion(Regions.US_WEST_2).build();
// 批量添加多个数据对象
Map<String, List<WriteRequest>> requestItems = new HashMap<>();
List<WriteRequest> requests = new ArrayList<>();
Map<String, AttributeValue> item1 = new HashMap<>();
item1.put("id", new AttributeValue("test-id-1"));
item1.put("name", new AttributeValue("test-name-1"));
WriteRequest writeRequest1 = new WriteRequest(item1).withPutRequest(new PutRequest());
requests.add(writeRequest1);
Map<String, AttributeValue> item2 = new HashMap<>();
item2.put("id", new AttributeValue("test-id-2"));
item2.put("name", new AttributeValue("test-name-2"));
WriteRequest writeRequest2 = new WriteRequest(item2).withPutRequest(new PutRequest());
requests.add(writeRequest2);
requestItems.put("sample-table", requests);
BatchWriteItemRequest batchRequest = new BatchWriteItemRequest(requestItems);
dynamoDB.batchWriteItem(batchRequest);
7. 如何在 DynamoDB 中使用条件更新?
答:在 DynamoDB 中使用条件更新需要在更新操作中设置 UpdateExpression 表达式和 ConditionExpression 条件表达式。条件更新可以确保在更新数据时只有在满足指定条件时才执行更新。示例代码如下:
// 创建 DynamoDB 对象
AmazonDynamoDB dynamoDB = AmazonDynamoDBClientBuilder.standard().withRegion(Regions.US_WEST_2).build();
// 条件更新一个计数器
UpdateItemRequest request = new UpdateItemRequest()
.withTableName("sample-table")
.withKey(Collections.singletonMap("id", new AttributeValue("test-id")))
.withUpdateExpression("SET #c = #c + :val")
.withConditionExpression("attribute_exists(id) AND #c < :max")
.addExpressionAttributeNamesEntry("#c", "counter")
.addExpressionAttributeValuesEntry(":val", new AttributeValue().withN("1"))
.addExpressionAttributeValuesEntry(":max", new AttributeValue().withN("100"))
.withReturnValues(ReturnValue.ALL_NEW);
Map<String, AttributeValue> result = dynamoDB.updateItem(request).getAttributes();
Long counter = Long.parseLong(result.get("counter").getN());
8. 如何在 DynamoDB 中实现分布式锁?
答:在 DynamoDB 中实现分布式锁需要使用条件更新和一个带有唯一约束条件的表格,可以在锁定时尝试添加一个特定的锁ID,而在解锁时尝试删除该锁ID。使用分布式锁需要执行以下步骤:
- 在锁定时尝试添加一个包含锁ID的项目并使用条件表达式确保该项不存在。
- 在解锁时尝试删除包含锁ID的项目,并使用条件表达式确保该项存在且锁ID匹配。
示例代码如下:
// 创建 DynamoDB 对象
AmazonDynamoDB dynamoDB = AmazonDynamoDBClientBuilder.standard().withRegion(Regions.US_WEST_2).build();
// 锁定一个资源
Map<String, AttributeValue> item = new HashMap<>();
item.put("resource", new AttributeValue("test-resource"));
item.put("lock-id", new AttributeValue("test-lock-id"));
PutItemRequest putRequest = new PutItemRequest("sample-table", item)
.withConditionExpression("attribute_not_exists(resource)");
try {
dynamoDB.putItem(putRequest);
} catch (ConditionalCheckFailedException e) {
throw new RuntimeException("Failed to acquire lock", e);
}
// 解锁一个资源
DeleteItemRequest deleteRequest = new DeleteItemRequest("sample-table", Collections.singletonMap("resource", new AttributeValue("test-resource")))
.withConditionExpression("lock-id = :id")
.addExpressionAttributeValuesEntry(":id", new AttributeValue("test-lock-id"));
try {
dynamoDB.deleteItem(deleteRequest);
} catch (ConditionalCheckFailedException e) {
throw new RuntimeException("Failed to release lock", e);
}
Win系统安装Amazon DynamoDB的步骤和教程
步骤一:下载 Amazon DynamoDB
第一步:访问 https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html,下载 Amazon DynamoDB。
步骤二:解压 DynamoDB
将下载好的 DynamoDB 文件压缩包解压,解压后可以得到一个文件夹,其中包含了 DynamoDB 的程序文件及相关资源文件。
步骤三:启动 DynamoDB
在解压出来的 DynamoDB 文件夹中,找到 DynamoDBLocal.jar 程序文件,并且在命令行中输入下面这条命令启动 DynamoDB。
java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb
解析:
java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb
这条命令表示启动一个本地的 DynamoDB 实例,其中:
-Djava.library.path=./DynamoDBLocal_lib:指定 DynamoDB 根目录下的 DynamoDBLocal_lib,这是 DynamoDB 所需使用的本地库路径。
-jar DynamoDBLocal.jar:表示启动 DynamoDBLocal.jar。
-sharedDb:表示共享一个数据库。
步骤四:使用 DynamoDB
启动成功后,可以通过运行命令行命令来使用 DynamoDB。运行如下命令:
aws dynamodb list-tables --endpoint-url http://localhost:8000
解析:
这条命令的作用是列出本地 DynamoDB 实例中的所有表,其中:
aws dynamodb list-tables 表示列出 DynamoDB 实例中的所有表。
--endpoint-url http://localhost:8000 指定 DynamoDB 服务所在的地址为 http://localhost:8000,也就是本地启动的 DynamoDB 实例服务。
步骤五:停止 DynamoDB
在关闭本地 DynamoDB 实例时,在命令行中按 Ctrl+C。
Linux系统安装Amazon DynamoDB的步骤和教程
步骤一:下载 Amazon DynamoDB
访问 https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html,下载 Amazon DynamoDB。
步骤二:解压 DynamoDB
在终端中运行下面的命令来解压 DynamoDB。
tar -zxvf DynamoDB_local_latest.tar.gz
解析:
tar -zxvf DynamoDB_local_latest.tar.gz:表示将 DynamoDB_local_latest.tar.gz 这个文件解压,并且 -z 表示解压缩 gz 格式文件,-x 表示解包,-v 表示显示解压细节,-f 指定压缩包。
步骤三:启动 DynamoDB
在启动 DynamoDB 之前,可以先确认一下 Java 是否已经安装。
java -version
如果没有安装 Java,可以通过下面的命令来安装:
sudo apt-get update sudo apt-get install openjdk-8-jdk
Java 安装成功后,使用下面的命令启动 DynamoDB。
java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb
解析:
java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb
这条命令表示启动一个本地的 DynamoDB 实例,其中:
-Djava.library.path=./DynamoDBLocal_lib:指定 DynamoDB 根目录下的 DynamoDBLocal_lib,这是 DynamoDB 所需使用的本地库路径。
-jar DynamoDBLocal.jar:表示启动 DynamoDBLocal.jar。
-sharedDb:表示共享一个数据库。
步骤四:使用 DynamoDB
启动成功后,可以通过运行命令行命令来使用 DynamoDB。运行如下命令:
aws dynamodb list-tables --endpoint-url http://localhost:8000
解析:
这条命令的作用是列出本地 DynamoDB 实例中的所有表,其中:
aws dynamodb list-tables 表示列出 DynamoDB 实例中的所有表。
--endpoint-url http://localhost:8000 指定 DynamoDB 服务所在的地址为 http://localhost:8000,也就是本地启动的 DynamoDB 实例服务。
步骤五:停止 DynamoDB
在打开 DynamoDB 实例的终端中,按 Ctrl+C 关闭本地 DynamoDB 实例。
Docker安装Amazon DynamoDB的步骤和教程
步骤一:创建 Docker 容器
使用 Docker 创建一个容器来托管 DynamoDB。执行如下命令:
docker run -p 8000:8000 amazon/dynamodb-local
注意:在执行此命令之前,请确保已经安装并启动了 Docker。
解析:
docker run -p 8000:8000 amazon/dynamodb-local
这条命令会拉取 Amazon DynamoDB 命令行客户端镜像,然后使用该镜像运行一个名为 dynamodb 的容器。-p 8000:8000 表示将容器的 8000 端口映射到本地的 8000 端口。
步骤二:使用 DynamoDB
容器运行后,通过下面的命令来列出 DynamoDB 中的表格:
aws dynamodb list-tables --endpoint-url http://localhost:8000
如果你在本地机器上安装了 AWS 命令行客户端,那么这条命令将会在 DynamoDB 中列出所有的表格。
步骤三:停止 Docker 容器
使用以下命令停止并删除 DynamoDB 容器。
docker stop dynamodb && docker rm dynamodb
解析:
docker stop dynamodb:停止名为 dynamodb 的容器。
&&:表示执行下一个命令。
docker rm dynamodb:命令将 Docker 中的名为 dynamodb 的容器删除。
容易出现的问题
- 问题:使用DynamoDB时出现错误:Unable to load AWS credentials from any provider in the chain
原因:没有正确配置AWS凭证,即Access Key ID和Secret Access Key。
解决办法:在代码中添加以下代码来设置AWS凭证:
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
.withRegion(Regions.US_EAST_1)
.withCredentials(new AWSStaticCredentialsProvider(
new BasicAWSCredentials("accessKey", "secretKey")))
.build();
- 问题:在使用DynamoDB时收到错误消息:The security token included in the request is invalid
原因:AWS凭证无效或已过期。
解决办法:使用新的AWS凭证或更新现有的凭证。或者,可以尝试使用IAM用户凭证而不是根凭证。
- 问题:在使用DynamoDB时出现错误:The provided key element does not match the schema
原因:请求中的键名与DynamoDB表中的键名不匹配。
解决办法:确保请求中使用的键名与DynamoDB表中使用的键名完全匹配。
- 问题:在使用DynamoDB时出现错误:ProvisionedThroughputExceededException
原因:超过了DynamoDB表的吞吐量限制。
解决办法:增加表的吞吐量或减少对表的请求。可以使用DynamoDB的自动缩放功能来自动调整吞吐量。
- 问题:在使用DynamoDB时遇到错误:ResourceNotFoundException
原因:请求的DynamoDB表不存在。
解决办法:确认表名是否正确,或者创建一个新的DynamoDB表。
使用Java SDK操作DynamoDB的示例
以下是使用Java SDK创建DynamoDB表的示例代码:
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
String tableName = "ExampleTable";
List<AttributeDefinition> attributeDefinitions = new ArrayList<>();
attributeDefinitions.add(new AttributeDefinition("id", ScalarAttributeType.S));
attributeDefinitions.add(new AttributeDefinition("timestamp", ScalarAttributeType.N));
List<KeySchemaElement> keySchema = new ArrayList<>();
keySchema.add(new KeySchemaElement("id", KeyType.HASH));
keySchema.add(new KeySchemaElement("timestamp", KeyType.RANGE));
ProvisionedThroughput provisionedThroughput = new ProvisionedThroughput(10L, 10L);
CreateTableRequest createTableRequest = new CreateTableRequest(tableName, attributeDefinitions, keySchema, provisionedThroughput);
Table table = Table.createTable(client, createTableRequest);
System.out.println("Table created successfully.");
步骤:
- 在pom.xml文件中添加以下依赖:
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-dynamodb</artifactId>
<version>1.11.690</version>
</dependency>
<dependency>
<groupId>com.github.derjust</groupId>
<artifactId>spring-data-dynamodb</artifactId>
<version>5.1.0</version>
</dependency>
- 在application.properties文件中添加以下配置:
amazon.dynamodb.endpoint=<Your Endpoint>
amazon.aws.accesskey=<Your Access Key>
amazon.aws.secretkey=<Your Secret Key>
amazon.aws.region=<Your Region>
- 创建DynamoDB相关的实体类和DAO层接口,以及实现类,如下所示:
Book.java
@Data
@NoArgsConstructor
@AllArgsConstructor
@DynamoDBTable(tableName = "Book")
public class Book {
@DynamoDBHashKey(attributeName = "Isbn")
private String isbn;
@DynamoDBAttribute(attributeName = "Title")
private String title;
@DynamoDBAttribute(attributeName = "Author")
private String author;
@DynamoDBAttribute(attributeName = "Price")
private double price;
@DynamoDBAttribute(attributeName = "Category")
private String category;
}
BookRepository.java
@Repository
public interface BookRepository extends DynamoDBRepository<Book, String> {
}
BookRepositoryImpl.java
@Repository
public class BookRepositoryImpl implements BookRepository {
private DynamoDBMapper dynamoDBMapper;
@Autowired
public BookRepositoryImpl(DynamoDBMapper dynamoDBMapper) {
this.dynamoDBMapper = dynamoDBMapper;
}
@Override
public void save(Book book) {
dynamoDBMapper.save(book);
}
@Override
public Book findOne(String isbn) {
return dynamoDBMapper.load(Book.class, isbn);
}
@Override
public Iterable<Book> findAll() {
DynamoDBScanExpression scanExpression = new DynamoDBScanExpression();
return dynamoDBMapper.scan(Book.class, scanExpression);
}
@Override
public void delete(Book book) {
dynamoDBMapper.delete(book);
}
}
- 在启动类中添加以下注解:
@EnableDynamoDBRepositories(basePackages = "com.example.demo.repository")
完整代码:
- pom.xml文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-dynamodb</artifactId>
<version>1.11.690</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>com.github.derjust</groupId>
<artifactId>spring-data-dynamodb</artifactId>
<version>5.1.0</version>
</dependency>
</dependencies>
- application.properties文件
amazon.dynamodb.endpoint=<Your Endpoint>
amazon.aws.accesskey=<Your Access Key>
amazon.aws.secretkey=<Your Secret Key>
amazon.aws.region=<Your Region>
- 实体类和DAO层
Book.java
@Data
@NoArgsConstructor
@AllArgsConstructor
@DynamoDBTable(tableName = "Book")
public class Book {
@DynamoDBHashKey(attributeName = "Isbn")
private String isbn;
@DynamoDBAttribute(attributeName = "Title")
private String title;
@DynamoDBAttribute(attributeName = "Author")
private String author;
@DynamoDBAttribute(attributeName = "Price")
private double price;
@DynamoDBAttribute(attributeName = "Category")
private String category;
}
BookRepository.java
@Repository
public interface BookRepository extends DynamoDBRepository<Book, String> {
}
BookRepositoryImpl.java
@Repository
public class BookRepositoryImpl implements BookRepository {
private DynamoDBMapper dynamoDBMapper;
@Autowired
public BookRepositoryImpl(DynamoDBMapper dynamoDBMapper) {
this.dynamoDBMapper = dynamoDBMapper;
}
@Override
public void save(Book book) {
dynamoDBMapper.save(book);
}
@Override
public Book findOne(String isbn) {
return dynamoDBMapper.load(Book.class, isbn);
}
@Override
public Iterable<Book> findAll() {
DynamoDBScanExpression scanExpression = new DynamoDBScanExpression();
return dynamoDBMapper.scan(Book.class, scanExpression);
}
@Override
public void delete(Book book) {
dynamoDBMapper.delete(book);
}
}
- 启动类
@SpringBootApplication
@EnableDynamoDBRepositories(basePackages = "com.example.demo.repository")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
文章评论