<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-sql-client-templates</artifactId>
<version>5.0.1</version>
</dependency>
SQL 客户端模板
SQL 客户端模板是一个小型库,旨在简化 SQL 查询的执行。
用法
要使用 SQL 客户端模板,请将以下依赖项添加到构建描述符的 dependencies 部分
-
Maven(在您的
pom.xml
中)
-
Gradle(在您的
build.gradle
文件中)
dependencies {
implementation 'io.vertx:vertx-sql-client-templates:5.0.1'
}
快速入门
以下是使用 SQL 模板的最简单方法。
SQL 模板使用命名参数,因此(默认情况下)接受映射作为参数源,而不是元组。
SQL 模板(默认情况下)生成 RowSet<Row>
,类似于客户端的 PreparedQuery
。实际上,模板是 PreparedQuery
的一个轻量级包装器。
Map<String, Object> parameters = Collections.singletonMap("id", 1);
SqlTemplate
.forQuery(client, "SELECT * FROM users WHERE id=#{id}")
.execute(parameters)
.onSuccess(users -> {
users.forEach(row -> {
System.out.println(row.getString("first_name") + " " + row.getString("last_name"));
});
});
当您需要执行插入或更新操作且不关心结果时,可以使用 SqlTemplate.forUpdate
替代
Map<String, Object> parameters = new HashMap<>();
parameters.put("id", 1);
parameters.put("firstName", "Dale");
parameters.put("lastName", "Cooper");
SqlTemplate
.forUpdate(client, "INSERT INTO users VALUES (#{id},#{firstName},#{lastName})")
.execute(parameters)
.onSuccess(v -> {
System.out.println("Successful update");
});
模板语法
模板语法使用 #{XXX}
,其中 XXX
是一个有效的 Java 标识符字符串(无关键字限制)。
您可以使用反斜杠字符 \
来转义任何 字符,即
\{foo}
将被解释为字符串 #{foo}
,而不是一个 foo
参数。
行映射
默认情况下,模板生成 Row
作为结果类型。
您可以提供自定义的 RowMapper
来实现行级别映射
RowMapper<User> ROW_USER_MAPPER = row -> {
User user = new User();
user.id = row.getInteger("id");
user.firstName = row.getString("firstName");
user.lastName = row.getString("lastName");
return user;
};
以实现行级别映射
SqlTemplate
.forQuery(client, "SELECT * FROM users WHERE id=#{id}")
.mapTo(ROW_USER_MAPPER)
.execute(Collections.singletonMap("id", 1))
.onSuccess(users -> {
users.forEach(user -> {
System.out.println(user.firstName + " " + user.lastName);
});
});
贫血 JSON 行映射
贫血 JSON 行映射是模板行字段与 JSON 对象之间使用 toJson
进行的简单映射
SqlTemplate
.forQuery(client, "SELECT * FROM users WHERE id=#{id}")
.mapTo(Row::toJson)
.execute(Collections.singletonMap("id", 1))
.onSuccess(users -> {
users.forEach(user -> {
System.out.println(user.encode());
});
});
参数映射
模板默认接受 Map<String, Object>
作为输入。
您可以提供自定义映射器
TupleMapper<User> PARAMETERS_USER_MAPPER = TupleMapper.mapper(user -> {
Map<String, Object> parameters = new HashMap<>();
parameters.put("id", user.id);
parameters.put("firstName", user.firstName);
parameters.put("lastName", user.lastName);
return parameters;
});
以实现参数映射
User user = new User();
user.id = 1;
user.firstName = "Dale";
user.firstName = "Cooper";
SqlTemplate
.forUpdate(client, "INSERT INTO users VALUES (#{id},#{firstName},#{lastName})")
.mapFrom(PARAMETERS_USER_MAPPER)
.execute(user)
.onSuccess(res -> {
System.out.println("User inserted");
});
您还可以轻松地执行批量操作
SqlTemplate
.forUpdate(client, "INSERT INTO users VALUES (#{id},#{firstName},#{lastName})")
.mapFrom(PARAMETERS_USER_MAPPER)
.executeBatch(users)
.onSuccess(res -> {
System.out.println("Users inserted");
});
贫血 JSON 参数映射
贫血 JSON 参数映射是模板参数与 JSON 对象之间进行的简单映射
JsonObject user = new JsonObject();
user.put("id", 1);
user.put("firstName", "Dale");
user.put("lastName", "Cooper");
SqlTemplate
.forUpdate(client, "INSERT INTO users VALUES (#{id},#{firstName},#{lastName})")
.mapFrom(TupleMapper.jsonObject())
.execute(user)
.onSuccess(res -> {
System.out.println("User inserted");
});
使用 Jackson databind 进行映射
您可以使用 Jackson databind 的功能进行映射。
您需要将 Jackson databind 依赖项添加到构建描述符的 dependencies 部分
-
Maven(在您的
pom.xml
中)
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
-
Gradle(在您的
build.gradle
文件中)
dependencies {
compile 'com.fasterxml.jackson.core:jackson-databind:${jackson.version}'
}
行映射是通过使用行键/值对创建 JsonObject
,然后调用 mapTo
,以 Jackson databind 将其映射到任何 Java 类来实现的。
SqlTemplate
.forQuery(client, "SELECT * FROM users WHERE id=#{id}")
.mapTo(User.class)
.execute(Collections.singletonMap("id", 1))
.onSuccess(users -> {
users.forEach(user -> {
System.out.println(user.firstName + " " + user.lastName);
});
});
同样,参数映射是通过使用 JsonObject.mapFrom
将对象映射到 JsonObject
,然后使用键/值对生成模板参数来实现的。
User u = new User();
u.id = 1;
SqlTemplate
.forUpdate(client, "INSERT INTO users VALUES (#{id},#{firstName},#{lastName})")
.mapFrom(User.class)
.execute(u)
.onSuccess(res -> {
System.out.println("User inserted");
});
Java 日期/时间 API 映射
您可以使用 jackson-modules-java8 Jackson 扩展来映射 java.time
类型。
您需要将 Jackson JSR 310 数据类型依赖项添加到构建描述符的 dependencies 部分
-
Maven(在您的
pom.xml
中)
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
-
Gradle(在您的
build.gradle
文件中)
dependencies {
compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:${jackson.version}'
}
然后您需要将时间模块注册到 Jackson ObjectMapper
ObjectMapper mapper = io.vertx.core.json.jackson.DatabindCodec.mapper();
mapper.registerModule(new JavaTimeModule());
您现在可以使用 java.time
类型,例如 LocalDateTime
public class LocalDateTimePojo {
public LocalDateTime localDateTime;
}
使用 Vert.x 数据对象进行映射
SQL 客户端模板组件可以为 Vert.x 数据对象生成映射函数。
Vert.x 数据对象是一个使用 @DataObject
注解的简单 Java bean 类。
@DataObject
class UserDataObject {
private long id;
private String firstName;
private String lastName;
public long getId() {
return id;
}
public void setId(long 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;
}
}
代码生成
任何用 @RowMapped
或 @ParametersMapped
注解的数据对象将触发相应映射器类的生成。
codegen 注解处理器在编译时生成这些类。这是 Java 编译器的一个特性,因此无需额外步骤,只需正确配置您的构建即可。
只需将 io.vertx:vertx-codegen:processor
和 io.vertx:vertx-sql-client-templates
依赖项添加到您的构建中。
以下是 Maven 的配置示例
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-codegen</artifactId>
<version>5.0.1</version>
<classifier>processor</classifier>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-sql-client-templates</artifactId>
<version>5.0.1</version>
</dependency>
此功能也可用于 Gradle
annotationProcessor "io.vertx:vertx-codegen:5.0.1:processor"
compile "io.vertx:vertx-sql-client-templates:5.0.1"
IDE 通常支持注解处理器。
codegen processor
分类器通过 META-INF/services
插件机制,为 jar 添加服务代理注解处理器的自动配置。
如果您愿意,也可以将其与常规 jar 一起使用,但那时您需要显式声明注解处理器,例如在 Maven 中
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessors>
<annotationProcessor>io.vertx.codegen.CodeGenProcessor</annotationProcessor>
</annotationProcessors>
</configuration>
</plugin>
行映射
您可以通过使用 @RowMapped
注解数据对象来生成行映射器。
@DataObject
@RowMapped
class UserDataObject {
private long id;
private String firstName;
private String lastName;
public long getId() {
return id;
}
public void setId(long 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;
}
}
默认情况下,每个列名都与数据对象属性绑定,例如 userName
属性绑定到 userName
列。
您可以使用 @Column
注解来自定义名称。
@DataObject
@RowMapped
class UserDataObject {
private long id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
public long getId() {
return id;
}
public void setId(long 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;
}
}
您可以注解字段、getter 或 setter。
生成的映射器可用于执行行映射,如行映射章节中所述。
SqlTemplate
.forQuery(client, "SELECT * FROM users WHERE id=#{id}")
.mapTo(UserDataObjectRowMapper.INSTANCE)
.execute(Collections.singletonMap("id", 1))
.onSuccess(users -> {
users.forEach(user -> {
System.out.println(user.getFirstName() + " " + user.getLastName());
});
});
参数映射
您可以通过使用 @ParametersMapped
注解数据对象来生成参数映射器。
@DataObject
@ParametersMapped
class UserDataObject {
private long id;
private String firstName;
private String lastName;
public long getId() {
return id;
}
public void setId(long 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;
}
}
默认情况下,每个参数都与数据对象属性绑定,例如 userName
属性绑定到 userName
参数。
您可以使用 @TemplateParameter
注解来自定义名称。
@DataObject
@ParametersMapped
class UserDataObject {
private long id;
@TemplateParameter(name = "first_name")
private String firstName;
@TemplateParameter(name = "last_name")
private String lastName;
public long getId() {
return id;
}
public void setId(long 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;
}
}
您可以注解字段、getter 或 setter。
生成的映射器可用于执行参数映射,如参数映射章节中所述。
UserDataObject user = new UserDataObject().setId(1);
SqlTemplate
.forQuery(client, "SELECT * FROM users WHERE id=#{id}")
.mapFrom(UserDataObjectParamMapper.INSTANCE)
.execute(user)
.onSuccess(users -> {
users.forEach(row -> {
System.out.println(row.getString("firstName") + " " + row.getString("lastName"));
});
});
Java 枚举类型映射
当客户端支持时(例如 Reactive PostgreSQL 客户端),您可以映射 Java 枚举类型。
通常,Java 枚举类型被映射为字符串/数字,也可能映射为自定义数据库枚举类型。
命名格式
默认模板对参数和列使用相同的命名大小写。您可以在 Column
和 TemplateParameter
注解中覆盖默认名称,并使用您喜欢的格式。
您还可以在 RowMapped
和 ParametersMapped
注解中配置映射器的特定格式大小写
@DataObject
@RowMapped(formatter = SnakeCase.class)
@ParametersMapped(formatter = QualifiedCase.class)
class UserDataObject {
// ...
}
可以使用以下命名大小写
-
CamelCase
(大驼峰命名法) :FirstName
-
LowerCamelCase
(小驼峰命名法) :firstName
- 类似于大驼峰命名法但以小写字母开头,这是默认情况 -
SnakeCase
(蛇形命名法) :first_name
-
KebabCase
(烤串命名法) :first-name
-
QualifiedCase
(限定命名法) :first.name