<p>ما يعادل jdbi3 SQLLog؟</p>

تم إنشاؤها على ٨ ديسمبر ٢٠١٧  ·  13تعليقات  ·  مصدر: jdbi/jdbi

لقد كنت أتصفح ملف javadoc ومستند الموقع بالكامل ولكن لا يمكنني العثور على آلية بديلة لـ SQLLog. أستطيع أن أرى أن StatementContext بها بعض أساليب get * Sql ، ولكن لا يوجد بديل لـ DBI.setSQLLog. يتلقى TimingCollector العبارة statementcontext بحيث يمكن إجراؤها تقنيًا هناك ، ولكن يبدو أن هذا حل بديل نظرًا لاسم الواجهة.

feature improvement

التعليق الأكثر فائدة

بعد أن أمضيت بضع ساعات في تحديث مشروعي إلى jdbi3 الآن ، أجد TimingCollector حلاً ليس نصف سيئ في مشروعي ، مع 3 نقاط بسيطة فقط: إنه خطأ لغويًا ، يتم تنفيذه _ بعد_ الاستعلام بدلاً من قبل (لذلك إذا كان الاستعلام يتسبب في استثناء لن يكون هناك تسجيل له) ، وأنا غير قادر على الحصول على الحجج المسماة / الموضعية من ربط statementcontext.

-

لا علاقة له بهذه المشكلة تمامًا ولكن فيما يتعلق بموضوع قضاء بعض الوقت في التحديث إلى jdbi3 ، أريد فقط أن أقول إنني أحبه. الطريقة التي تعمل بها فئة Jdbi كمستودع تكوين يحتفظ بالمكونات الإضافية رائعة. كان مشروعي حتى الآن مبنيًا على استخدام jdbi بطريقة محددة جدًا ، وعادةً ما عملت ولكن لم تكن jdbi تعمل بطريقة jdbi. نظرًا لأن jdbi3 أجبرني على القيام بكل شيء بطريقة jdbi3 عن طريق إزالة بعض الحريات ، فقد تعلمت بعض الآليات البديلة مثل الحجج ، والبناء على العمود بدلاً من تعيين الصفوف ، وتحسين واجهة برمجة التطبيقات بطلاقة ، وهو مجرد عالم جديد تمامًا من الملاءمة بمجرد الانتهاء من إعداد كل شيء. لم أدرك حتى مدى الإحساس الذي يجعله نموذجك تقنيًا وعمليًا حتى الآن. رفاق عمل رائع ، شكرًا على صنع هذا :)

ال 13 كومينتر

أعتقد أننا أزلنا تجريد التسجيل هذا في JDBI3. إذا كنت ترغب في تمكين تسجيل SQL ، فأنت بحاجة إلى ذلك في تكوين تنفيذ SLF4J الخاص بك.

في SqlStatement
LOG.trace("Execute SQL \"{}\" in {}ms", sql, elapsedTime / 1000000L);

المشكلة هي أن هذا لا يترك لي الحرية في أن أقرر _كيف _ أريد أن يتم تسجيل استفساراتي: المستوى ، الصياغة ، الخام / المقدمة / المحللة sql ، الشروط ...

يقول موقع المستند أن TimingCollector لم يتم تجسيده بالكامل حتى الآن على أي حال ، لذا فإن الأفكار مرحب بها ، لذلك أعتقد أنني أقترح بموجب هذا إما إنشاء واجهة شقيقة لتسجيل الاستعلامات بدلاً من إضاعة الوقت ، أو إنشاء TimingCollector ليكون مخصصًا أيضًا لاستعلامات التسجيل.

نعم ، ليس لدينا واجهة رائعة لهذا الآن. ترك SQLLog القديم الكثير مما هو مرغوب فيه ، لذا قمنا بإزالته بينما سنحت لنا الفرصة ، لصالح بناء شيء أفضل.

بعد أن أمضيت بضع ساعات في تحديث مشروعي إلى jdbi3 الآن ، أجد TimingCollector حلاً ليس نصف سيئ في مشروعي ، مع 3 نقاط بسيطة فقط: إنه خطأ لغويًا ، يتم تنفيذه _ بعد_ الاستعلام بدلاً من قبل (لذلك إذا كان الاستعلام يتسبب في استثناء لن يكون هناك تسجيل له) ، وأنا غير قادر على الحصول على الحجج المسماة / الموضعية من ربط statementcontext.

-

لا علاقة له بهذه المشكلة تمامًا ولكن فيما يتعلق بموضوع قضاء بعض الوقت في التحديث إلى jdbi3 ، أريد فقط أن أقول إنني أحبه. الطريقة التي تعمل بها فئة Jdbi كمستودع تكوين يحتفظ بالمكونات الإضافية رائعة. كان مشروعي حتى الآن مبنيًا على استخدام jdbi بطريقة محددة جدًا ، وعادةً ما عملت ولكن لم تكن jdbi تعمل بطريقة jdbi. نظرًا لأن jdbi3 أجبرني على القيام بكل شيء بطريقة jdbi3 عن طريق إزالة بعض الحريات ، فقد تعلمت بعض الآليات البديلة مثل الحجج ، والبناء على العمود بدلاً من تعيين الصفوف ، وتحسين واجهة برمجة التطبيقات بطلاقة ، وهو مجرد عالم جديد تمامًا من الملاءمة بمجرد الانتهاء من إعداد كل شيء. لم أدرك حتى مدى الإحساس الذي يجعله نموذجك تقنيًا وعمليًا حتى الآن. رفاق عمل رائع ، شكرًا على صنع هذا :)

شكرا لردود الفعل اللطيفة! هل تمانع في تجميع الطرق التي تريد استخدام SqlLog / TimingCollector بها في هذه التذكرة كبداية لمستند تصميم؟ سيكون من الجيد توضيح بعض حالات الاستخدام الفعلية ، حتى نتمكن من التأكد من حل المشكلات الفعلية.

رسم سريع للشفرة الزائفة جافا:

public interface Jdbi {
    void registerSqlLogger(SqlLogger logger);

    void registerSqlLoggerFactory(SqlLoggerFactory factory);
}

public interface SqlLogger {
    void logBeforeExecution(StatementContext context);

    void logAfterExecution(StatementContext context, long nanos);

    void logException(StatementContext context, Exception ex);
}

public interface SqlLoggerFactory {
    // the sqlObject, if any
    Optional<SqlLogger> build(<strong i="6">@Nullable</strong> SqlObject extension, <strong i="7">@Nullable</strong> Class extensionClass);
}

public interface StatementContext {
    // "select * from x where foo = 'bar'"
    String getNormalizedSql();

    // "select * from x where foo = ?"
    // "select * from x where foo = :bar"
    String getParamaterizedSql();

    List<Object> getPositionalArgs();

    Map<String, Object> getNamedArgs();

    ParamsType getParamsType();

    enum ParamsType {
        NONE, POSITIONAL, NAMED
    }
}
public class Main {
    public static void main(String[] args) {
        Jdbi jdbi = Jdbi.create();
        jdbi.registerSqlLoggerFactory((sqlObject, sqlObjectClass) -> new SqlLogger() {
            private final Logger logger = LoggerFactory.getLogger(sqlObject != null? sqlObjectClass: MyApp.class);

            <strong i="10">@Override</strong>
            void before(StatementContext context) {
                String params;
                switch (context.getParamsType()) {
                    case NONE:
                        params = "N/A";
                    case POSITIONAL:
                        params = context.getPositionalArgs().toString();
                    case NAMED:
                        params = toKeyValueString(context.getNamedArgs());
                }
                logger.debug(Markers.SQL, "query: {}, params: {}", context.getParameterizedSql(), params);
            }

            <strong i="11">@Override</strong>
            void after(StatementContext context, long nanos) {
                logger.trace(Markers.SQL, "query {} took {}ns", context.getNormalizedSql, nanos);
            }

            <strong i="12">@Override</strong>
            void exception(StatementContext context, Exception ex) {
                logger.error(Markers.SQL, context.getNormalizedSql(), e);
            }
        });
    }
}

لما يستحق ، يسمح لك SqlStatementCustomizerFactory البسيط بتنفيذ ذلك من خلال التعليقات التوضيحية ، إما على طرق فردية أو واجهات كاملة. نعم ، إنها عرضة للنسيان ، وهذه مشكلة. لا أحتاج حاليًا إلى تسجيل دقيق للغاية للاستعلامات لأنها في الغالب مخصصة لتصحيح الأخطاء ، ويتم تشغيلها عندما أحتاج إلى ذلك ، ولكن يمكنك تجاوز قبل التنفيذ وبعد التنفيذ للتوقيت أيضًا. ليس من الصعب جدًا تمديده لأخذ فصل دراسي لإنشاء مثيل له بدلاً من ذلك.

<strong i="6">@NameBinding</strong>
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS)
@SqlStatementCustomizingAnnotation(WriteQueryToLogFactory::class)
annotation class WriteQueryToLog


class WriteQueryToLogFactory : SqlStatementCustomizerFactory {
    val log: Logger = LoggerFactory.getLogger("api.sql-statements")
    override fun createForType(annotation: Annotation?, sqlObjectType: Class<*>?): SqlStatementCustomizer {
        return SqlStatementCustomizer( { q -> q.addCustomizer(object: StatementCustomizer {
            override fun beforeExecution(stmt: PreparedStatement, ctx: StatementContext) {
                log.trace("Context: ${ctx.extensionMethod.type}.${ctx.extensionMethod.method.name}")
                log.trace("Statement: ${stmt.toString()}")
            }
        })})
    }
}

نعم ، هذا يعني أنه يمكنك الوصول إلى البيان بالكامل ويمكنك إفساده ، لكن هل هي مشكلة حقًا؟

pikzen يؤدي ذلك إلى تحمل العبء الأكبر ، ولكن اقتراحي كان حول جعل بيانات الاستعلام أكثر سهولة وإضافة طريقة onException أيضًا. لقد جربت أحد تلك التعليقات التوضيحية المخصصة في البداية أيضًا ، لكنني وجدت أنها محدودة للغاية بالنسبة لما أردت القيام به ، ولهذا السبب اقترحت كل هذا.

لقد ألقيت للتو نظرة أخرى ويبدو أن ParsedParameters و ParsedSql في منتصف الطريق إلى ما أود رؤيته. ParsedParameters يفتقد فقط طريقة للحصول على قيمة المعلمة من الاسم / الفهرس المقدم. أعتقد أن هذا سيجعل الصورة كاملة إلى حد كبير.

هل ألقيت نظرة على كائن StatementContext الذي تم تمريره إلى أداة التخصيص؟ يتيح لك الوصول إلى parsedSql rawSql و renderedSql لـ SQL ، بالإضافة إلى attributes يحتوي على معلمات الاستعلام.

أوافق على أن الحصول على شيء ما على استثناء سيكون أمرًا عمليًا ، لكن أليس من الأفضل تقديمه ببساطة من خلال تحسين واجهة StatementCustomizer الحالية وتكييف النواة؟

بالإضافة إلى attributes يحتوي على معلمات الاستعلام

هممم ، لا؟

image

المكان الوحيد للحصول على قيم معلمات الاستعلام AFAIK هو من خلال الانعكاس على الرابط:

Reflect.on(context.getBinding()).<HashMap<Integer, Argument>>get("named")

في الواقع ، سيئتي ، كنت أعني binding ، كنت أنظر إليه فقط من خلال مصحح الأخطاء ولم أدرك أنه لم يكن متاحًا من الخارج.

هناك عدد قليل من الأماكن التي تتوفر فيها ، نعم ، مواقع ملزمة / مسمى ، بيان.المعلمات القيم / المعلمات أنواع (على الرغم من أن هذا ليس بالضبط الأكثر عملية) وهي متاحة فقط من خلال التفكير. أنا

المعلمات المربوطة موجودة في getBinding() . attributes على سمات محددة من خلال define() هي السمات المضمنة في علامات <attr> في SQL.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

buremba picture buremba  ·  5تعليقات

goxr3plus picture goxr3plus  ·  4تعليقات

agavrilov76 picture agavrilov76  ·  5تعليقات

Shujito picture Shujito  ·  5تعليقات

Romqa picture Romqa  ·  5تعليقات