3 Häufige Probleme mit dem Ruhezustand und wie Sie sie in Ihrer Protokolldatei finden

1. Einführung

Sie haben wahrscheinlich einige der Beschwerden über schlechte Hibernate-Leistung gelesen oder Sie haben mit einigen von ihnen selbst zu kämpfen. Ich benutze Hibernate seit mehr als 15 Jahren und habe mehr als genug davon erfahren.

Im Laufe der Jahre habe ich gelernt, dass diese Probleme vermieden werden können und Sie viele davon in Ihrer Protokolldatei finden. In diesem Beitrag möchte ich Ihnen zeigen, wie Sie 3 davon finden und beheben können.

2. Finden und Beheben von Leistungsproblemen

2.1. SQL-Anweisungen in der Produktion protokollieren

Das erste Leistungsproblem ist sehr leicht zu erkennen und wird oft ignoriert.

Es ist die Protokollierung von SQL-Anweisungen in einer Produktionsumgebung.

Das Schreiben einiger Protokollanweisungen hört sich nicht nach einer großen Sache an, und es gibt viele Anwendungen, die genau das tun. Dies ist jedoch äußerst ineffizient, insbesondere über System.out.println , da Hibernate dies tut, wenn Sie den show sql -Parameter in Ihrer Hibernate-Konfiguration auf true__ setzen:

Hibernate: select
    order0__.id as id1__2__,
    order0__.orderNumber as orderNum2__2__,
    order0__.version as version3__2__
  from purchaseOrder order0__
Hibernate: select
    items0__.order__id as order__id4__0__0__,
    items0__.id as id1__0__0__,
    items0__.id as id1__0__1__,
    items0__.order__id as order__id4__0__1__,
    items0__.product__id as product__5__0__1__,
    items0__.quantity as quantity2__0__1__,
    items0__.version as version3__0__1__
  from OrderItem items0__
  where items0__.order__id=?
Hibernate: select
    items0__.order__id as order__id4__0__0__,
    items0__.id as id1__0__0__,
    items0__.id as id1__0__1__,
    items0__.order__id as order__id4__0__1__,
    items0__.product__id as product__5__0__1__,
    items0__.quantity as quantity2__0__1__,
    items0__.version as version3__0__1__
  from OrderItem items0__
  where items0__.order__id=?
Hibernate: select
    items0__.order__id as order__id4__0__0__,
    items0__.id as id1__0__0__,
    items0__.id as id1__0__1__,
    items0__.order__id as order__id4__0__1__,
    items0__.product__id as product__5__0__1__,
    items0__.quantity as quantity2__0__1__,
    items0__.version as version3__0__1__
  from OrderItem items0__
  where items0__.order__id=?

In einem meiner Projekte habe ich die Leistung innerhalb weniger Minuten um 20% verbessert, indem show sql auf false__ gesetzt wurde. Das ist die Art von Erfolg, die Sie gerne beim nächsten Stand-up-Meeting melden möchten

Es ist ziemlich offensichtlich, wie Sie dieses Leistungsproblem beheben können. Öffnen Sie einfach Ihre Konfiguration (z. B. Ihre persistence.xml-Datei) und setzen Sie den Parameter show sql auf false__. Diese Informationen benötigen Sie in der Produktion sowieso nicht.

Möglicherweise benötigen Sie sie jedoch während der Entwicklung. Wenn Sie dies nicht tun, verwenden Sie zwei verschiedene Hibernate-Konfigurationen (was Sie nicht tun sollten). Sie haben auch die SQL-Anweisungsprotokollierung dort deaktiviert. Die Lösung hierfür ist die Verwendung von 2 verschiedenen log-Konfigurationen für Entwicklung und Produktion, die für die spezifischen Anforderungen der Laufzeitumgebung optimiert sind.

  • Entwicklungskonfiguration **

Die Entwicklungskonfiguration sollte so viele nützliche Informationen wie möglich enthalten, damit Sie sehen können, wie Hibernate mit der Datenbank interagiert. Sie sollten daher mindestens die generierten SQL-Anweisungen in Ihrer Entwicklungskonfiguration protokollieren. Sie können dies tun, indem Sie die DEBUG -Nachricht für die Kategorie org.hibernate.SQL aktivieren. Wenn Sie auch die Werte Ihrer Bindeparameter sehen möchten, müssen Sie die Protokollebene von org.hibernate.type.descriptor.sql auf TRACE setzen:

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p[%c]- %m%n
log4j.rootLogger=info, stdout

# basic log level for all messages
log4j.logger.org.hibernate=info

# SQL statements and parameters
log4j.logger.org.hibernate.SQL=debug
log4j.logger.org.hibernate.type.descriptor.sql=trace

Der folgende Codeausschnitt zeigt einige Beispielprotokollnachrichten, die Hibernate mit dieser Protokollkonfiguration schreibt. Wie Sie sehen, erhalten Sie detaillierte Informationen zur ausgeführten SQL-Abfrage sowie alle gesetzten und abgerufenen Parameterwerte:

23:03:22,246 DEBUG SQL:92 - select
    order0__.id as id1__2__,
    order0__.orderNumber as orderNum2__2__,
    order0__.version as version3__2__
  from purchaseOrder order0__
  where order0__.id=1
23:03:22,254 TRACE BasicExtractor:61 - extracted value ([id1__2__]:[BIGINT]) -[1]23:03:22,261 TRACE BasicExtractor:61 - extracted value ([orderNum2__2__]:[VARCHAR]) -[order1]23:03:22,263 TRACE BasicExtractor:61 - extracted value ([version3__2__]:[INTEGER]) -[0]----

Der Ruhezustand liefert Ihnen viel mehr interne Informationen zu einer __Session__, wenn Sie die Statistiken für den Ruhezustand aktivieren. Sie können dies tun, indem Sie die Systemeigenschaft __hibernate.generate__statistics__ auf true setzen.

Bitte aktivieren Sie jedoch nur die Statistiken Ihrer Entwicklungs- oder Testumgebung. Das Sammeln all dieser Informationen verlangsamt Ihre Anwendung und Sie können Ihre Leistungsprobleme selbst erzeugen, wenn Sie dies in der Produktion aktivieren.

Einige Beispielstatistiken finden Sie im folgenden Code-Snippet:

[source,text,gutter:,true]

23:04:12,123 INFO StatisticalLoggingSessionEventListener:258 - Session Metrics { 23793 nanoseconds spent acquiring 1 JDBC connections; 0 nanoseconds spent releasing 0 JDBC connections; 394686 nanoseconds spent preparing 4 JDBC statements; 2528603 nanoseconds spent executing 4 JDBC statements; 0 nanoseconds spent executing 0 JDBC batches; 0 nanoseconds spent performing 0 L2C puts; 0 nanoseconds spent performing 0 L2C hits; 0 nanoseconds spent performing 0 L2C misses; 9700599 nanoseconds spent executing 1 flushes (flushing a total of 9 entities and 3 collections); 42921 nanoseconds spent executing 1 partial-flushes (flushing a total of 0 entities and 0 collections) }

Ich verwende diese Statistiken regelmäßig in meiner täglichen Arbeit, um Leistungsprobleme zu ermitteln, bevor sie in der Produktion auftreten]genau das. Konzentrieren wir uns also auf die wichtigsten.

Die Zeilen 2 bis 5 zeigen an, wie viele JDBC-Verbindungen und Anweisungen Hibernate während dieser Sitzung verwendet wurden und wie viel Zeit dafür aufgewendet wurde. Sie sollten sich diese Werte immer ansehen und mit Ihren Erwartungen vergleichen.

Wenn es viel mehr Anweisungen gibt, als Sie erwartet haben, haben Sie höchstwahrscheinlich das häufigste Leistungsproblem, das n + 1 Problem auswählen. Sie finden es in fast allen Anwendungen und können zu großen Leistungsproblemen in einer größeren Datenbank führen. Ich erkläre dieses Problem im nächsten Abschnitt ausführlicher.

Die Zeilen 7 bis 9 zeigen, wie Hibernate mit dem Cache der zweiten Ebene interagierte.

Dies ist einer von http://www.thoughts-on-java.org/hibernate-performance-tuning-part-3 (3 Cache-Speicher für Hibernate), und speichert Entitäten in einer sitzungsunabhängigen Weise. Wenn Sie in Ihrer Anwendung die 2. Ebene verwenden, sollten Sie diese Statistiken immer überwachen, um zu sehen, ob der Ruhezustand die Entitäten von dort abruft.

**  Produktionskonfiguration **

Die Produktionskonfiguration sollte auf Leistung optimiert werden und Meldungen vermeiden, die nicht dringend erforderlich sind. Im Allgemeinen bedeutet dies, dass Sie nur Fehlermeldungen protokollieren sollten. Wenn Sie Log4j verwenden, können Sie dies mit der folgenden Konfiguration erreichen:

Wenn Sie Log4j verwenden, können Sie dies mit der folgenden Konfiguration erreichen:

[source,text,gutter:,true]

log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p[%c]- %m%n log4j.rootLogger=info, stdout