您的第二个 Quarkus 应用程序
本教程将展示如何创建一个应用程序,该应用程序可以写入和读取数据库。 你将使用 Dev Services,因此你实际上无需自己下载、配置甚至启动数据库。 你还将使用 Panache (Hibernate ORM 之上的一个层),以简化数据的读取和写入。
本指南可以帮助你:
-
向数据库读取和写入对象
-
以零配置开发和测试服务
先决条件
要完成本指南,您需要
-
大约 30 分钟
-
一个 IDE
-
已安装 JDK 17+ 并正确配置了
JAVA_HOME
-
Apache Maven 3.9.9
-
一个正常工作的容器运行时(Docker 或 Podman)
-
如果您想使用它,可以选择 Quarkus CLI
本教程建立在你学习编写第一个 Quarkus 应用程序的基础上。 你将不需要该应用程序的代码,但请确保你理解了这些概念。
2. 设置交互式应用程序
2.1. 引导项目
创建新 Quarkus 项目的最简单方法是打开终端并运行以下命令
对于 Windows 用户
-
如果使用 cmd,(不要使用反斜杠
\
并将所有内容放在同一行上) -
如果使用 Powershell,请将
-D
参数括在双引号中,例如"-DprojectArtifactId=getting-started-dev-services"
有关生成的应用程序内容的说明,请参阅第一个应用程序指南。
2.2. 运行应用程序
在开发模式下启动应用程序
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
应用程序启动后,访问https://:8080/hello。 它应该显示“Hello from Quarkus REST”消息。
3. 添加持久性
3.1. 创建 Panache 实体
-
要添加持久性库,请运行
quarkus extension add hibernate-orm-panache,jdbc-postgresql
./mvnw quarkus:add-extension -Dextensions='hibernate-orm-panache,jdbc-postgresql'
./gradlew addExtension --extensions='hibernate-orm-panache,jdbc-postgresql'
应用程序将记录它问候的人的姓名。 通过创建 Greeting.java
类来定义一个实体。 添加以下内容
import io.quarkus.hibernate.orm.panache.PanacheEntity;
import jakarta.persistence.Entity;
@Entity
public class Greeting extends PanacheEntity {
public String name;
}
该实体使用了 Panache,它是 Hibernate ORM 之上的一个层。 扩展 PanacheEntity
会引入一系列用于读取、写入和查找数据的方法。 因为所有数据访问方法都在 Greeting
实体上,而不是在单独的数据访问类上,所以这是活动记录模式的一个示例。
Greeting
表将有一列,一个名为 name
的字段。
3.2. 写入数据
要使用新实体,请更新 hello
方法以开始写入一些数据。
将方法更改为以下内容
@GET
@Transactional
@Produces(MediaType.TEXT_PLAIN)
public String hello(@QueryParam("name") String name) {
Greeting greeting = new Greeting();
greeting.name = name;
greeting.persist();
return "Hello " + name;
}
不要忘记 @Transactional
注释,它确保写入操作被包装在一个事务中。
GET 请求不应更改应用程序状态。 通常,你不应该在 GET REST 方法中执行状态更新,但在这里它使尝试各种操作变得更简单。 让我们假设正在写入的内容是日志记录“副作用”,而不是有意义的状态更改! |
通过访问 https://:8080/hello?name=Bloom 来试用更新后的端点。 你应该看到“Hello Bloom”消息。
3.3. 读取数据
尽管新的持久性代码似乎运行良好,没有任何错误,但你如何知道任何内容正在被写入数据库?
向 GreetingResource
添加第二个 REST 方法。
@GET
@Path("names")
@Produces(MediaType.TEXT_PLAIN)
public String names() {
List<Greeting> greetings = Greeting.listAll();
String names = greetings.stream().map(g-> g.name)
.collect(Collectors.joining (", "));
return "I've said hello to " + names;
}
要尝试一下,请访问 https://:8080/hello?name=Bloom,然后访问 https://:8080/hello/names。
你应该看到以下消息:“I’ve said hello to Bloom”。
需要一个容器运行时。
不要忘记你需要有一个可用的容器运行时,否则你会在 Quarkus 日志中开始看到故障。 |
4. 开发服务
读取和写入数据库似乎运行良好,但这有点出乎意料。 PostgreSQL 数据库从哪里来的? 你没有设置任何内容。
数据库正在使用 Dev Services 进行管理。 Dev Services 负责停止和启动你的应用程序所需的服务。 因为你包含了 jdbc-postgresql
依赖项,所以数据库是一个容器化的 PostgreSQL 数据库。 如果你添加了 jdbc-mysql
,你将获得一个容器化的 MySQL 数据库。
如果你愿意,可以使用你的容器工具来查看正在运行的容器。 例如,如果你正在使用 Docker,请运行 docker ps
,对于 podman,请运行 podman ps
。 你应该看到如下内容
ff88dcedd899 docker.io/library/postgres:14 postgres -c fsync... 20 minutes ago Up 20 minutes 0.0.0.0:34789->5432/tcp nostalgic_bassi
停止 Quarkus 并再次运行 docker ps
。 你应该看到没有任何内容在运行(容器可能需要一些时间才能关闭)。 当你的应用程序停止时,Quarkus 将自动停止容器。
4.1. 初始化服务
如果你进一步研究你的代码,你可能会注意到,有时在进行应用程序更改后,https://:8080/hello/names 不会列出任何名称。 发生了什么? 默认情况下,在开发模式下,使用 Dev Services 数据库,Quarkus 将 Hibernate ORM 数据库模式管理策略配置为 drop-and-create
。 有关更多详细信息,请参阅 Hibernate 配置参考。 如果代码更改触发应用程序重新启动,数据库表将被删除,然后重新创建。
这很方便,但是如果你希望数据库始终具有内容怎么办? 这会使测试更容易。 如果你提供一个 import.sql
文件,Quarkus 将使用它在每次启动时初始化数据库。
-
在你的项目中创建一个
src/main/resources/import.sql
文件 -
添加以下 SQL 语句
INSERT INTO Greeting(id, name)
VALUES (nextval('Greeting_SEQ'), 'Alice');
INSERT INTO Greeting(id, name)
VALUES (nextval('Greeting_SEQ'), 'Bob');
现在,在你的开发模式会话中按 s
,强制完全重新启动。 然后访问 https://:8080/hello/names。
你会看到 Alice 和 Bob 始终包含在名称列表中。
5. 控制开发服务
5.1. 改用外部数据库
如果你更喜欢使用自己管理的外部数据库怎么办? 将以下内容添加到 src/main/resources/application.properties
# configure your datasource
quarkus.datasource.db-kind = postgresql
quarkus.datasource.username = leopold
quarkus.datasource.password = bloom
quarkus.datasource.jdbc.url = jdbc:postgresql://:5432/mydatabase
这告诉 Quarkus 你不希望它启动 Dev Service,因为你有自己的数据库。 你无需担心启动数据库,因为你只是在了解如何更改配置。
访问 https://:8080/hello/names。 你将得到一个红色错误屏幕,而不是名称列表。 在 Quarkus 运行的终端中,你将看到以下堆栈错误消息
2023-06-28 19:18:22,880 ERROR [io.qua.ver.htt.run.QuarkusErrorHandler] (executor-thread-1) HTTP Request to /hello?name=fred failed, error id: 4f9b5ce6-3b08-41c5-af36-24eee4d1dd2b-2: org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection [Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.] [n/a] at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:98) at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:56) ...
这是有道理的;你已经禁用了数据库 Dev Service,但你没有启动自己的数据库。
5.2. 使用配置文件
除非你愿意,否则不要担心设置外部数据库来解决连接错误。 相反,你将返回使用 Dev Service。 它使生活变得轻松!
但是生产环境呢? 你不会希望在生产环境中使用 Dev Services。 事实上,Quarkus 只会在开发和测试模式下启动 Dev Services。
如果可以配置一个外部数据库,但仅在生产环境中使用,以便你仍然可以在其他时间使用 Dev Services,那不是很好吗?
在数据库配置中添加 %prod.
前缀。 这意味着配置仅适用于 prod 配置文件
配置应如下所示
# configure your datasource
%prod.quarkus.datasource.db-kind = postgresql
%prod.quarkus.datasource.username = leopold
%prod.quarkus.datasource.password = bloom
%prod.quarkus.datasource.jdbc.url = jdbc:postgresql://:5432/mydatabase
现在,外部数据库将在生产模式下使用,而 Dev Services 将在开发和测试模式下使用。
检查 https://:8080/hello/names。 它应该再次工作,因为 Dev Services 已重新启用。 请注意,对于这些更改,无需重新启动 Quarkus。