Как распечатать аннотацию @SqlQuery в JDBI sql api

Я хочу знать, какой именно sql-запрос обрабатывается jdbi sql api для целей отладки. Мой класс интерфейса следующий

public inteface myinteface{
    @SqlQuery("select :c1 from tablename where cond = :cd")
    String returnMeValue(@Bind("c1") String c1, @Bind("cd") Integer cd);
}

а позже вызывается в другом классе как String result = myinterfaceclassobject.returnMeValue("Name",1);

Я не получаю ожидаемого ответа, поэтому хочу посмотреть, что на самом деле происходит с запросом sql. Итак, есть ли способ получить окончательный обработанный запрос?


person Dheerendra    schedule 09.05.2014    source источник
comment
есть тот же вопрос. Вы узнали, как это сделать?   -  person froderik    schedule 24.07.2014


Ответы (3)


Вы можете зарегистрировать sql, написав SqlCustomizer.

import org.skife.jdbi.v2.StatementContext;
import org.skife.jdbi.v2.sqlobject.SqlStatementCustomizer;
import org.skife.jdbi.v2.sqlobject.SqlStatementCustomizerFactory;
import org.skife.jdbi.v2.sqlobject.SqlStatementCustomizingAnnotation;
import org.skife.jdbi.v2.tweak.StatementCustomizer;

import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.SQLException;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@SqlStatementCustomizingAnnotation(LogSqlFactory.Factory.class)
public @interface LogSqlFactory {

    static class Factory implements SqlStatementCustomizerFactory {

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

        @Override
        public SqlStatementCustomizer createForType(Annotation annotation, Class sqlObjectType) {
            return q -> q.addStatementCustomizer(new StatementCustomizer() {
                @Override
                public void beforeExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException {
                    System.out.println(stmt.toString());
                }

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

                @Override
                public void cleanup(StatementContext ctx) throws SQLException { }
            });
        }

        @Override
        public SqlStatementCustomizer createForParameter(Annotation annotation, Class sqlObjectType, Method method, Object arg) {
            return null;
        }
    }

}

Просто включите эту аннотацию и используйте ее в SqlObject. В вашем случае используйте эту аннотацию следующим образом:

@LogSqlFactory 
public inteface myinteface{
@SqlQuery("select :c1 from tablename where cond = :cd")
    String returnMeValue(@Bind("c1") String c1, @Bind("cd") Integer cd);
}

Если вы используете пользовательские регистраторы для ведения журнала, то метод beforeExecution.

person Manikandan    schedule 30.05.2015
comment
Я пробовал это, но не работал. Есть ли какие-то предпосылки? - person Ana; 15.12.2017
comment
@Manikandan Я обнаружил, что ваш ответ не работает с более новыми версиями Jdbi, и скорректировал ваше решение здесь: stackoverflow.com/a/58763295/2986905 Не стесняйтесь интегрировать мою переделку в свой ответ, и я удалю свою. - person Rüdiger Herrmann; 08.11.2019

Основываясь на @Manikandan answer, который, как я обнаружил, не работает с Jdbi >= 3.10, я скорректировал LogSqlFactory следующим образом:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@SqlStatementCustomizingAnnotation(LogSqlFactory.Factory.class)
public @interface LogSqlFactory {

  class Factory implements SqlStatementCustomizerFactory {
    @Override
    public SqlStatementCustomizer createForType(Annotation annotation, Class sqlObjectType) {
      SqlLogger sqlLogger = new SqlLogger() {
        @Override
        public void logBeforeExecution(StatementContext context) {
          logSql(context);
        }
      };
      return statement -> statement.setSqlLogger(sqlLogger);
    }

    private static void logSql(StatementContext context) {
      System.out.println("Raw SQL:\n" + context.getRawSql());
      System.out.println("Parsed SQL:\n" + context.getParsedSql().getSql());
      System.out.println("Rendered SQL:\n" + context.getRenderedSql());
    }
  }
}

Аннотируйте свой интерфейс SqlObject с помощью LogSqlFactory, чтобы увидеть операторы SQL:

@LogSqlFactory 
public interface Dao {
  @SqlQuery("select * from t")
  List<?> selectAll();
}
person Rüdiger Herrmann    schedule 08.11.2019

Гораздо проще использовать что-то вроде log4jdbc, использование метода Manikandan также немного замедляет ваш код.

Однако, если вы все еще хотите использовать его, а уровень языка вашего проекта не поддерживает лямбда-выражения, вы можете использовать следующую модификацию:

  @Override
  public SqlStatementCustomizer createForType(Annotation annotation, final Class sqlObjectType) {

     return new SqlStatementCustomizer() {
        @Override
        public void apply(SQLStatement sqlStatement) throws SQLException {
           sqlStatement.addStatementCustomizer(new StatementCustomizer() {
              @Override
              public void beforeExecution(PreparedStatement stmt, StatementContext ctx) throws SQLException {
                 System.out.println(stmt.toString());
              }

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

              @Override
              public void cleanup(StatementContext ctx) throws SQLException {
              }
           });
        }
     };

  }

Однако не гарантируется, что stmt.toString() вернет оператор SQL, это зависит от реализации. Это не будет работать для SQLite.

person I_AM_PANDA    schedule 13.06.2015