当前位置: 首页 > 知识库问答 >
问题:

如何在JDBI 3(SQL对象)中执行SQL语句之前修改它们

萧辰沛
2023-03-14

我想在JDBI 3 (SQL对象)中执行SQL语句之前拦截和修改它们。其原因是用模式名替换自定义令牌占位符。我发现这个线程,但它是为JDBI 2(使用Dropwizard

public class Product {
    private int id = -1;
    private String name = "";

    public Product() {
    }

    public Product(int id, String name) {
       this.id = id;
       this.name = name;
    }

    public int getId() {
       return this.id;
    }

    public void setId(int id) {
       this.id = id;
    }

    public String getName() {
       return this.name;
    }

    public void setName(String name) {
       this.name = name;
    }        
}

public class ProductMapper implements RowMapper<Product> {

    @Override
    public Product map(ResultSet r, StatementContext ctx) throws SQLException {
        Product product = new Product();

        product.setId(r.getInt("id"));
        product.setName(r.getString("name"));

        return product;
    }
}

@SchemaRewriterFactory
@UseClasspathSqlLocator
public interface ProductDao {

    /**
    * The sql query is located in resources ([package]/listProducts.sql)
    * listProducts.sql: SELECT PRODUCT_ID ID, NAME FROM :schema.PRODUCTS
    * @return
    */
   @SqlQuery
   @RegisterRowMapper(ProductMapper.class)
   List<Product> listProducts();

}


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@SqlStatementCustomizingAnnotation(SchemaRewriterFactory.SchemaRewriter.class)
public @interface SchemaRewriterFactory {

    public class SchemaRewriter implements SqlStatementCustomizerFactory {

        @Override
        public SqlStatementCustomizer createForMethod(Annotation annotation, Class<?> sqlObjectType, Method method) {
            return null;
        }

        @Override
        public SqlStatementParameterCustomizer createForParameter(Annotation annotation, Class<?> sqlObjectType, Method method, Parameter param, int index, Type paramType) {
            return null;
        }

        @Override
        public SqlStatementCustomizer createForType(Annotation annotation, Class<?> sqlObjectType) {
            return q -> q.addCustomizer(new StatementCustomizer() {

                @Override
                public void beforeBinding(PreparedStatement stmt, StatementContext ctx) throws SQLException {}

                @Override
                public void beforeExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException {                          
                    System.out.println(stmt.toString());
                    //TODO: HOW DO I MODIFY SQL (REPLACE TOKENS - :schema) BEFORE IT GETS EXECUTED?
                }

                @Override
                public void afterExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException { }


             });

        }

    }
}

我还发现了这个线程,它使用@定义(JDBI中的动态顺序SQL对象查询)处理自定义标签替换。如果可能,我想避免每次调用都传递额外的参数。任何帮助都将不胜感激!

共有2个答案

王渊
2023-03-14

我找到了一种方法来截取查询并在执行之前对其进行修改。

您必须使用自定义 StatementBuilder 构建一个 StatementBuilderFactory 实例。方法如下:

private fun getCustomStatementBuilderFactory(): StatementBuilderFactory =
            StatementBuilderFactory {
                object : DefaultStatementBuilder() {
                    override fun create(conn: Connection?,
                            sql: String?,
                            ctx: StatementContext?): PreparedStatement {
                        //Perform the modification here
                        val modifiedSql = "--Sample\n$sql"
                        return if (ctx!!.isReturningGeneratedKeys) {
                            val columnNames = ctx.generatedKeysColumnNames
                            if (columnNames != null && columnNames.size > 0) conn!!.prepareStatement(
                                    modifiedSql,
                                    columnNames) else conn!!.prepareStatement(sql, 1)
                        } else {
                            if (ctx.isConcurrentUpdatable) conn!!.prepareStatement(modifiedSql,
                                    1003,
                                    1008) else conn!!.prepareStatement(modifiedSql, 1003, 1007)
                        }
                    }
                }
            }

现在,将此 StatementBuilderFactory 实例设置为用于执行查询的 jdbi 实例。

Jdbi.create(dataSource).setStatementBuilderFactory(getCustomStatementBuilderFactory())

根据上面的例子,每个执行的查询在开始都有一个注释< code> - Sample。

任伟
2023-03-14

您可以为此使用String模板。

/**
  * The sql query is located in resources ([package]/listProducts.sql)
  * listProducts.sql: SELECT PRODUCT_ID ID, NAME FROM <schemaName>.PRODUCTS
  * @return
*/
@SqlQuery
@RegisterRowMapper(ProductMapper.class)
List<Product> listProducts(@Define("schemaName") String schemaName);

只需小心清理架构名称参数(可能的SQL注入)

 类似资料:
  • 问题内容: 我正在尝试使用HQL(hibernate查询语言)在两个表之间创建一个并集。此SQL脚本可在我的SQL服务器上正常运行: 问题是,当我尝试像这样在grails中运行它时: 我收到此错误: 如何在grails中运行上述SQL语句? 谢谢杰森 问题答案: HQL不支持联合。自2005年以来,Hibernate的JIRA中存在一个问题。

  • 问题内容: 大家好,我想执行我的SQL语句,但是我在synatx上遇到麻烦,有人可以帮助我了解我做错了什么吗? 谢谢,阿什。 问题答案: 您需要解决的最重要的事情是使用查询参数,而不是动态地构建字符串。这将提高性能,维护和安全性。 此外,您想使用较新的强类型ADO.Net对象。确保为添加使用指令。 注意此代码中的语句。完成连接后,他们将 确保 您的连接已关闭。这很重要,因为数据库连接是有限且不受管

  • 问题内容: 是否可以使用T-SQL执行存储在表中的SQL语句? 表中存储的语句是临时语句,可以是 SELECT TOP 100 * FROM ATable 到更复杂的语句: 我想执行从T-SQL声明的 @Query 变量。这可能吗?(我正在运行MSSQL 2005环境) 问题答案: 您可以使用 运行您的T-SQL 这是SQL Server 2005的MS docn的链接 http://msdn.m

  • 问题内容: 我想在 Java中 执行查询。 我创建一个连接。然后,我想执行一条语句,完成后关闭连接,但是我想通过连接执行一些插入语句,并在循环完成后关闭连接。 我能做些什么 ? 我的示例代码是: 当执行select语句()时,循环必须为两次,但是当()执行并完成时,则关闭连接并从类中返回。 问题答案: 以下示例使用&命令同时执行多个SQL命令。 结果: 以上代码示例将产生以下结果。结果可能会有所不

  • 下面给出一个例子来演示一下如何使用JDBC来执行各种SQL语句,其中包括DDL语句(建立数据库和数据表)、INSERT语句和SELECT语句。 1.程序分析说明 本程序首先创建一个mydb数据库(如果存在就不创建),然后创建一个用于保存图书信息的表t_books(如果存在,删除后再创建),最后向表中插入两条记录,并查询和显示其中的第2条记录。 2.代码编写 本程序使用了Statement接口的ex

  • 问题内容: 我正在尝试结合以下注释: 像下面的代码: @Before方法中的代码在@Sql批注中的脚本“ dml-parametro.sql”之后运行。 这样做对吗? 对于此解决方案,我使用@After而不是@Before,但我想在测试执行之前而不是之后cdelete表。 我不想使用@SqlConfig。我没有在测试级别上使用Transacional范围,因此我需要在每种测试方法中清除表。如果每个