Mybatis-Statistiken zur Ausführungszeit jeder SQL-Anweisung

Mybatis-Statistiken zur Ausführungszeit jeder SQL-Anweisung

Hintergrund

In letzter Zeit werde ich in Interviews häufig nach Datenbanktransaktionen gefragt. Normalerweise weiß ich nur, dass ich die Annotation @Transactional hinzufügen muss, und dann bin ich verwirrt. Ich stelle fest, dass dieser Teil sehr oft übersehen wird, aber Interviewer mögen solche Fragen, die nicht oft gestellt werden, aber sehr wichtig sind, um den Interviewer zu überraschen. Schluss mit dem Unsinn, kommen wir zur Sache.

Lösung 1: Aspektprogrammierung @Aspect

Diese Lösung umschließt hauptsächlich die Schnittstellenmethoden umgebend unter dem Mapper-Paket und berechnet dann die Zeitdifferenz davor und danach. Dies ist typisches AOP-Wissen. Obwohl diese Berechnung grob ist, ist sie auch eine Lösung. Die konkrete Methode ist wie folgt:

@Aspekt
@Komponente
@Slf4j
öffentliche Klasse MapperAspect {

  @AfterReturning("Ausführung(* cn.xbmchina.mybatissqltime.mapper.*Mapper.*(..))")
  öffentliche void logServiceAccess(JoinPoint joinPoint) {
    log.info("Abgeschlossen: " + joinPoint);
  }


  /**
   * Überwachen Sie alle öffentlichen Methoden von cn.xbmchina.mybatissqltime.mapper..*Mapper-Paket und seine Unterpakete*/
  @Pointcut("Ausführung(* cn.xbmchina.mybatissqltime.mapper.*Mapper.*(..))")
  private void PunktSchnittmethode() {
  }

  /**
   * Erklärung zur Benachrichtigung *
   * @param pjp
   * @zurückkehren
   * @throws Wurfobjekt
   */
  @Around("PunktSchnittMethode()")
  öffentliches Objekt doAround(ProceedingJoinPoint pjp) wirft Throwable {
    lang begin = System.nanoTime();
    Objekt obj = pjp.proceed();
    langes Ende = System.nanoTime();

    log.info("Aufruf der Mapper-Methode: {}, Parameter: {}, Ausführungszeit: {} Nanosekunden, benötigte Zeit: {} Millisekunden",
        pjp.getSignature().toString(), Arrays.toString(pjp.getArgs()),
        (Ende - Anfang), (Ende - Anfang) / 1000000);
    gibt Objekt zurück;
  }
}

Lösung 2: Mybatis-Plugin

Bei MyBatis werden Plug-Ins in den Erstellungsprozess der vier Hauptobjekte eingreifen. Das Plug-In kann den dynamischen Proxy-Mechanismus verwenden, um das Zielobjekt Schicht für Schicht zu umschließen und so den Effekt zu erzielen, das Zielobjekt abzufangen, bevor es die Zielmethode ausführt.

MyBatis ermöglicht das Abfangen von Aufrufen an bestimmten Punkten während der Ausführung einer zugeordneten Anweisung.

Standardmäßig erlaubt MyBatis Plugins, Methodenaufrufe abzufangen, darunter:

①Executor (Aktualisieren, Abfragen, FlushStatements, Commit, Rollback, GetTransaction, Schließen, IsClosed)
②ParameterHandler(Parameterobjekt abrufen, Parameter festlegen)
③ResultSetHandler(Ergebnissätze handhaben, Ausgabeparameter handhaben)
④StatementHandler (Vorbereiten, Parametrisieren, Batchverarbeiten, Aktualisieren, Abfragen)

Hier ist der Code:

importiere org.apache.ibatis.executor.statement.StatementHandler;
importiere org.apache.ibatis.mapping.BoundSql;
importiere org.apache.ibatis.mapping.ParameterMapping;
importiere org.apache.ibatis.plugin.Interceptor;
importiere org.apache.ibatis.plugin.Intercepts;
importiere org.apache.ibatis.plugin.Invocation;
importiere org.apache.ibatis.plugin.Plugin;
importiere org.apache.ibatis.plugin.Signature;
importiere org.apache.ibatis.session.ResultHandler;
importiere org.slf4j.Logger;
importiere org.slf4j.LoggerFactory;
importiere org.springframework.stereotype.Component;

importiere java.sql.Statement;
importiere java.util.List;
importiere java.util.Properties;

/**
 *Interceptor zur Aufzeichnung der SQL-Ausführungszeit*
 * @author null
 * 13. Dezember 2019 17:05:28
 */
@Intercepts({@Signature(Typ = StatementHandler.Klasse, Methode = "Abfrage", Argumente = {Statement.Klasse, ResultHandler.Klasse}),
    @Signature(Typ = StatementHandler.class, Methode = "update", Argumente = {Statement.class}),
    @Signature(Typ = StatementHandler.Klasse, Methode = "Batch", Argumente = {Statement.Klasse})})
@Komponente
öffentliche Klasse SqlExecuteTimeCountInterceptor implementiert Interceptor {

  privater statischer Logger-Logger = LoggerFactory.getLogger(SqlExecuteTimeCountInterceptor.class);

  /**
   * Maximale Länge des ausgedruckten Parameterstrings */
  private endgültige statische int MAX_PARAM_LENGTH = 50;

  /**
   * Maximale SQL-Länge des Datensatzes */
  private endgültige statische int MAX_SQL_LENGTH = 200;


  @Überschreiben
  öffentliches Objekt abfangen (Aufruf Aufruf) wirft Throwable {
    Objektziel = Aufruf.getTarget();
    lange Startzeit = System.currentTimeMillis();
    StatementHandler statementHandler = (StatementHandler) Ziel;
    versuchen {
      Aufruf zurückgeben.fortfahren();
    Endlich
      lange endTime = System.currentTimeMillis();
      lange Zeitanzahl = Endzeit – Startzeit;

      BoundSql boundSql = statementHandler.getBoundSql();
      : Zeichenfolge sql = boundSql.getSql();
      ObjektparameterObject = boundSql.getParameterObject();
      Liste<ParameterMapping> parameterMappingList = boundSql.getParameterMappings();

      // SQL-Anweisung formatieren, Zeilenumbrüche entfernen und Parameter ersetzen sql = formatSQL(sql, parameterObject, parameterMappingList);

      logger.info("SQL ausführen: [, {}] Ausführungszeit [{} ms]", sql, timeCount);
    }
  }


  /**
   * SQL-Anweisungen formatieren/verschönern*
   * @param sql SQL-Anweisung * @param ParameterObject-Parameter Map
   * @param parameterMappingList Parameterliste
   * @return-formatiertes SQL
   */
  privater String formatSQL(String sql, Objekt Parameterobjekt, Liste<ParameterMapping> ParameterMappingList) {
    // Beurteilung des leeren SQL-Strings bei der Eingabe, wenn (sql == null || sql.length() == 0) {
      zurückkehren "";
    }
    // SQL verschönern
    sql = verschönernSql(sql);
    // In dem Szenario, in dem keine Parameter übergeben werden, verschönern Sie einfach das SQL und geben Sie es zurück, wenn (parameterObject == null || parameterMappingList == null || parameterMappingList.size() == 0) {
      SQL zurückgeben;
    }
    gibt LimitSQLLength(sql) zurück;
  }


  /**
   * Gibt die SQL-Anweisung nach der Längenbeschränkung zurück*
   *
   * @param sql ursprüngliche SQL-Anweisung*/
  private Zeichenfolge LimitSQLLength(Zeichenfolge sql) {
    wenn (sql == null || sql.length() == 0) {
      zurückkehren "";
    }
    wenn (sql.length() > MAX_SQL_LENGTH) {
      gibt sql.substring(0, MAX_SQL_LENGTH) zurück;
    } anders {
      SQL zurückgeben;
    }
  }


  @Überschreiben
  öffentliches Objekt-Plugin (Objektziel) {
    gibt Plugin.wrap(Ziel, dies) zurück;
  }

  @Überschreiben
  public void setProperties(Eigenschaften Eigenschaften) {

  }




  /**
   * Ersetzen Sie den entsprechenden Wert in SQL, behalten Sie nur die ersten 50 Zeichen*
   * @param sql SQL-Anweisung* @param valueOf ? entsprechender Wert*/
  privater String Ersetzungswert(String sql, String Wert von) {
    //Wenn es mehr als 50 Zeichen sind, nimm nur die ersten 50 if (valueOf != null && valueOf.length() > MAX_PARAM_LENGTH) {
      Wert von = Wert von.Teilzeichenfolge (0, MAX_PARAM_LENGTH);
    }
    sql = sql.replaceFirst("\\?", Wert von);
    SQL zurückgeben;
  }

  /**
   * SQL verschönern
   *
   * @param sql SQL-Anweisung */
  privater String beautifySql(String sql) {
    sql = sql.replaceAll("[\\s\n ]+", " ");
    SQL zurückgeben;
  }
 }

Lösung 3: Druid direkt verwenden

Dies ist die Art von Frage, die wir am häufigsten verwenden, aber in einem Vorstellungsgespräch brauchen Sie sie nur einmal zu sagen, und ich denke, Sie müssen nicht mehr danach fragen.

Die Konfigurationsdatei application.yml von Springboot+druid lautet wie folgt:

Frühling:
  Datenquelle:
    URL: jdbc:mysql://localhost:3306/testdb1?characterEncoding=utf-8&useUnicode=true&useSSL=false&serverTimezone=UTC
    Treiberklassenname: com.mysql.jdbc.Driver # mysql8.0 und davor wurde com.mysql.jdbc.Driver verwendet
    Benutzername: root
    Passwort: root
    Plattform: MySQL
    #Durch diese Konfiguration wird der Druidenverbindungspool in unsere Konfiguration eingeführt. Spring wird sein Bestes tun, um den Typ zu bestimmen und dann die Treiberklasse entsprechend der Situation anzupassen.
    Typ: com.alibaba.druid.pool.DruidDataSource
    Druide:
      initial-size: 5 # Initialisierungsgrößemin-idle: 5 # Minimummax-active: 100 # Maximummax-wait: 60000 # Konfigurieren Sie das Timeout für das Warten auf den Verbindungsaufbautime-between-eviction-runs-millis: 60000 # Konfigurieren Sie das Intervall in Millisekunden für die Überprüfung und Erkennung inaktiver Verbindungen, die geschlossen werden müssenmin-evictable-idle-time-millis: 300000 # Geben Sie die Mindestinaktivitätszeit in Millisekunden an, in der eine inaktive Verbindung gelöscht wirdvalidationQuery: select 'x'
      test-while-idle: true # Ob ein Verbindungstest durchgeführt werden soll, wenn die Verbindung im Leerlauf isttest-on-borrow: false # Ob die Verbindung getestet werden soll, wenn eine Verbindung vom Verbindungspool ausgeliehen wirdtest-on-return: false # Ob die Verbindung getestet werden soll, wenn sie an den Verbindungspool zurückgegeben wirdfilters: config,wall,stat # Filter zum Abfangen von Überwachungsstatistiken konfigurieren. Nach dem Entfernen kann die Überwachungsschnittstelle SQL nicht mehr gezählt werden. „wall“ wird für FirewallpoolPreparedStatements verwendet: true # PSCache einschalten und die Größe von PSCache für jede Verbindung angebenmaxPoolPreparedStatementPerConnectionSize: 20
      maxOpenPreparedStatements: 20
      # Aktivieren Sie die Funktion mergeSql über die Eigenschaft connectProperties; langsamer SQL-Datensatz connectionProperties: druid.stat.slowSqlMillis=200;druid.stat.logSlowSql=true;config.decrypt=false
       #Überwachungsdaten aus mehreren DruidDataSources zusammenführen#use-global-data-source-stat: true
      # WebStatFilter-Konfiguration. Anweisungen finden Sie im Druid Wiki unter „Configuration_Configure WebStatFilter“.
      Web-Statistik-Filter:
        aktiviert: true #Ob StatFilter aktiviert werden soll. Der Standardwert ist true.
        URL-Muster: /*
        Ausschlüsse: /druid/*,*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico
        Sitzungsstatistik aktivieren: wahr
        Sitzungsstatistik-Maximalanzahl: 10
      #StatViewServlet-Konfiguration, Anweisungen finden Sie im Druid Wiki, configure_StatViewServletConfigure stat-view-servlet:
        aktiviert: true #Ob StatViewServlet aktiviert werden soll. Der Standardwert ist true.
        URL-Muster: /druid/*
        Reset-Aktivieren: wahr
        Login-Benutzername: admin
        Login-Passwort: admin

Zusammenfassen

Das Obige ist der vollständige Inhalt dieses Artikels. Ich hoffe, er wird für jedermanns Studium hilfreich sein. Ich hoffe auch, dass jeder 123WORDPRESS.COM unterstützen wird.

Das könnte Sie auch interessieren:
  • Mybatis-Plugin: Print SQL und seine Implementierungsmethode zur Ausführungszeit
  • Java verwendet den Mybatis-Interceptor, um beispielsweise die SQL-Ausführungszeit zu zählen

<<:  JS implementiert Städtelisteneffekt basierend auf VUE-Komponente

>>:  Detaillierte Erläuterung verschiedener Möglichkeiten zum Abrufen der PID (TID, LWP) von Linux-Threads

Artikel empfehlen

So halten Sie eine lange Verbindung aufrecht, wenn Sie den Nginx-Reverse-Proxy verwenden

· 【Szenenbeschreibung】 Nach HTTP1.1 unterstützt d...

Detaillierte Erläuterung des Lese-Commits der MySQL-Transaktionsisolationsebene

MySQL-Transaktionsisolationsebene anzeigen mysql&...

Eine vollständige Aufzeichnung eines Mysql-Deadlock-Fehlerbehebungsprozesses

Vorwort Die Datenbank-Deadlocks, die ich zuvor er...

Detaillierte Erklärung der grundlegenden Interaktion von Javascript

Inhaltsverzeichnis 1. So erhalten Sie Elemente Ho...

Welche Bilddateiformate gibt es und wie wählt man sie aus?

1. Welche drei Formate? Dies sind: gif, jpg und pn...

Linux-Befehl „exa“ (bessere Dateianzeige als „ls“)

Installieren Befolgen Sie zur Installation die RE...

Vue-Tutorial zur erweiterten Verwendung dynamischer Komponenten

Inhaltsverzeichnis Grundlegende Beschreibung AST-...

Docker-Port-Mapping und externe Unzugänglichkeitsprobleme

Der Docker-Container stellt Dienste bereit und la...

Schritte zur Installation von MySQL 8.0.23 unter Centos7 (Anfängerstufe)

Lassen Sie mich zunächst kurz erklären, was MySQL...

So installieren Sie Element UI und verwenden Vektorgrafiken in vue3.0

Hier konzentrieren wir uns nur auf die Installati...

Schreiben Sie einen formellen Blog mit XHTML CSS

Der vollständige Name von Blog sollte Weblog sein...