ExecuteListener
SPI 来执行外部 API 调用作为预提交挂钩。我的目标是使用一些插入的值调用网络调用(逻辑将根据每个表编写),如果失败,事务应该回滚。这是我首先尝试的:
使用
ExecuteContext
实例,我可以访问查询、SQL 语句、参数。但是,如果不解析字符串 SQL 语句,我就无法知道表名是什么。
public class WriteListener implements ExecuteListener {
@Override
public void end(ExecuteContext ctx) {
if (ctx.type() == ExecuteType.WRITE) {
// extract table, rows and their values
final org.jooq.Query query = ctx.query(); // tried to cast to InsertQuery too
final org.jooq.Record record = ctx.record(); // can't access the values
// etc..
}
ExecuteListener.super.end(ctx);
}
}
另一个选择是尝试使用实验性 API QOM
:
public class WriteListener implements ExecuteListener {
@Override
public void end(ExecuteContext ctx) {
if (ctx.query() instanceof QOM.Insert insert) {
final Table table = insert.$into();
final var cols = insert.$columns();
final var rows = insert.$values();
// can't extract row values!
}
ExecuteListener.super.end(ctx);
}
}
我能够读取表格、列和字段。但是,如果没有反射就无法提取值。最终目标是将记录转换为代码生成记录类型之一,在其中我可以获得强类型对象,并且会填充值。我不确定今天是否可能。理想情况下,寻找以下代码:
public class WriteListener implements ExecuteListener {
@Override
public void end(ExecuteContext ctx) {
if (ctx.type() == ExecuteType.WRITE) {
// NOTE: THIS DOES NOT WORK, IT'S AN IDEA ONLY.
if (ctx.record() instanceof MyTableRowRecord record) {
final DateTime createdAt = record.CREATED_AT;
// invoke an external API call with the table name, and the created at value.
}
}
ExecuteListener.super.end(ctx);
}
}
值得一提的是,我使用的是社区版,但如果这是另一层的 API,我愿意升级。
我能够读取表格、列和字段。但是,如果没有反射就无法提取值。为什么需要反射来访问字段/值? 返回
Row
类型的列表,其中提供 Row.$fields()
,每个 Field
可以是 Param
(当然也可以是其他东西)。所以:
for (Row row : insert.$values()) {
for (Field<?> field : row.$fields()) {
if (field instanceof Param<?> param) {
// ...
}
}
}
最终目标是将记录转换为代码生成记录类型之一,在其中我可以获得强类型对象,并且会填充值。
ExecuteListener
SPI 不知道任何“强类型对象”,例如
UpdatableRecord
类型。假设您最初调用的是这样的:
MyTableRowRecord record = ...
record.insert();
这将在生成 RecordListener
语句之前触发
INSERT
SPI,该语句的执行随后会触发
ExecuteListener
SPI。但同样,后者不知道记录,而前者仅针对
UpdatableRecord
操作被调用。