给定一个 jooq 查询如何找到所涉及的表?
Posted
技术标签:
【中文标题】给定一个 jooq 查询如何找到所涉及的表?【英文标题】:Given a jooq query how do find the tables involved? 【发布时间】:2021-10-08 05:16:26 【问题描述】:我目前正在使用DefaultExecuteListener 挂钩到 jooq 查询生命周期。如何可靠地确定查询是否为 select 语句以及 select 中涉及哪些表(org.jooq.Table)?
@Override
public void executeStart(ExecuteContext context)
Set<Table> tables = new HashSet<>();
if (context.query() != null)
context.query(); // How do you check if this is a select statement and retrieve the tables involved?
【问题讨论】:
【参考方案1】:如何可靠地确定查询是否为选择语句
您可以在ExecuteListener
中通过检查context.query() instanceof Select
来做到这一点
select 中涉及到哪些表(org.jooq.Table)?
从 jOOQ 3.15 开始,在 SQL 生成期间访问表达式树的最佳方法是实现 VisitListener
。本文展示了一个广泛的 how to implement client side row level security in jOOQ 示例。你需要的会更少。在最简单的情况下,这可能就足够了:
class TableCollector implements DefaultVisitListener
Set<Table<?>> tables = new HashSet<>();
@Override
public void visitStart(VisitContext ctx)
if (ctx.queryPart() instanceof Table)
tables.add(ctx.queryPart());
现在,您只需将这两者粘合在一起即可。
【讨论】:
您能否详细说明如何将 VisitListener 的调用与同一查询上的 ExecuteListener 调用关联起来? 澄清一下:我需要在执行时涉及的表。 @ScottWiedemann:缓慢但简单的解决方案:您可以使用具有来自ExecuteListener
的VisitListener
的派生配置重新呈现查询。更快但更棘手的解决方案:为两个听众找到某种方式进行交流,例如使用一些线程局部变量,或一些队列等......【参考方案2】:
通过使用 VisitListener
并结合 ExecuteListener
,我能够在执行时获取查询中涉及的 Jooq 表 (org.jooq.Table):
import org.jooq.Table;
import org.jooq.VisitContext;
import org.jooq.impl.DefaultVisitListener;
import java.util.HashSet;
import java.util.concurrent.ConcurrentHashMap;
public class TableCollector extends DefaultVisitListener
private final static ConcurrentHashMap<String, HashSet<Table<?>>> queryToTables = new ConcurrentHashMap<>();
public static HashSet<Table<?>> getTables(String sqlQuery)
return queryToTables.get(sqlQuery);
private <T> T getDataValue(VisitContext context, String key, T defaultValue)
T value = (T) context.data(key);
if (value == null)
value = defaultValue;
return value;
private <T> T putDataValue(VisitContext context, String key, T value)
return (T) context.data(key, value);
@Override
public void visitStart(VisitContext context)
Integer stackSize = getDataValue(context, "stackSize", 0);
stackSize++;
putDataValue(context, "stackSize", stackSize);
if (context.queryPart() instanceof Table)
Table<?> table = (Table<?>) context.queryPart();
HashSet<Table<?>> tables = getDataValue(context, "tables", new HashSet<>());
tables.add(table);
putDataValue(context, "tables", tables);
@Override
public void visitEnd(VisitContext context)
Integer stackSize = getDataValue(context, "stackSize", -1);
stackSize--;
putDataValue(context, "stackSize", stackSize);
if (stackSize == 0)
HashSet<Table<?>> tables = getDataValue(context, "tables", new HashSet<>());
String sql = context.context().render();
if (sql != null)
queryToTables.put(sql, new HashSet<>(tables));
tables.clear();
putDataValue(context, "tables", tables);
import org.jooq.ExecuteContext;
import org.jooq.Query;
import org.jooq.Table;
import org.jooq.impl.DefaultExecuteListener;
import java.util.HashSet;
import java.util.Set;
public class TableExecuteListener extends DefaultExecuteListener
@Override
public void executeStart(ExecuteContext context)
super.executeStart(context);
// pull the tables from the @link TableCollector for this query
final Set<Table<?>> tablesInQuery = new HashSet<>();
if (context.query() != null)
tablesInQuery.addAll(TableCollector.getTables(context.sql()));
else
for (Query query : context.batchQueries())
tablesInQuery.addAll(TableCollector.getTables(query.getSQL()));
【讨论】:
以上是关于给定一个 jooq 查询如何找到所涉及的表?的主要内容,如果未能解决你的问题,请参考以下文章
Jooq 中的条件 onDuplicateKeyUpdate