[JAVA] Sehen Sie sich das Verhalten von Entitätsaktualisierungen mit Spring Boot + Spring Data JPA an

Überblick

--Spring Boot + Spring Data Log-Ausgabe, um zu sehen, wie SQL-Anweisungen beim Aktualisieren von Entitäten mit JPA ausgegeben werden

Umgebung

Beispielcode

Dateiliste

├── build.gradle
├── settings.gradle
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           ├── Counter.java
        │           ├── CounterController.java
        │           ├── CounterRepository.java
        │           └── CounterService.java
        └── resources
            ├── application.properties
            └── data.sql

build.gradle

plugins {
  id 'org.springframework.boot' version '2.2.6.RELEASE'
  id 'io.spring.dependency-management' version '1.0.9.RELEASE'
  id 'java'
}

group = 'com.example'
version = '0.0.1'
sourceCompatibility = '11'

repositories {
  mavenCentral()
}

dependencies {
  // Spring
  implementation 'org.springframework.boot:spring-boot-starter-web'
  implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
  // Lombok
  compileOnly 'org.projectlombok:lombok'
  annotationProcessor 'org.projectlombok:lombok'
  // H2 Database
  runtimeOnly 'com.h2database:h2'
}

settings.gradle

rootProject.name = 'my-app'

src/main/resources/application.properties

application.properties


#H2 Datenbankeinstellungen
#AUTOCOMMIT bei ausgeschaltetem Autocommit=OFF
#TRACE zur Ausgabe von Protokollen_LEVEL_SYSTEM_OUT=Geben Sie 2 an
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false;AUTOCOMMIT=OFF;TRACE_LEVEL_SYSTEM_OUT=2
#Geben Sie an, dass Protokolle wie Spring Framework und Hibernate ORM ausgegeben werden sollen
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql=TRACE
logging.level.org.springframework.orm.jpa=DEBUG
logging.level.com.example=DEBUG
#Verwenden Sie nicht das Open EntityManager in View-Muster
spring.jpa.open-in-view=false

src/main/resources/data.sql

--Fügen Sie der DB Anfangsdaten hinzu
INSERT INTO counter (name, count, updated_at) VALUES ('mycounter', 0, LOCALTIMESTAMP);

src/main/java/com/example/Counter.java

Entitätsklasse.

package com.example;

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.Id;
import java.time.LocalDateTime;

/**
 *Entspricht einem Datensatz in der DB-Tabelle.
 */
@Data //Generieren Sie automatisch nützliche Methoden wie Getter Setter mit Lombok
@Entity //Als JPA-Einheit behandeln
public class Counter {

  //Zählername
  @Id //Lassen Sie JPA diese Variable als ID des Objekts erkennen
  private String name;

  //Zählerstand
  private int count;

  //Datum und Uhrzeit aktualisieren
  private LocalDateTime updatedAt;
}

src/main/java/com/example/CounterController.java

package com.example;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@SpringBootApplication
@RestController
@Slf4j // org.slf4j.Das statische Protokoll der endgültigen Variablen vom Typ Logger wird automatisch generiert
public class CounterController {

  public static void main(String[] args) {
    SpringApplication.run(CounterController.class, args);
  }

  @Autowired
  private CounterService service;

  @GetMapping("/counter/{name}")
  public Map counter(@PathVariable("name") String name) {

    //Zusammenzählen
    log.debug("Before: countup");
    Counter counter = service.countup(name);
    log.debug("After: countup");

    //JSON-Antwort generieren
    return Map.of(counter.getName(), counter.getCount());
  }
}

src/main/java/com/example/CounterService.java

package com.example;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.time.LocalDateTime;

@Service
@Slf4j // org.slf4j.Das statische Protokoll der endgültigen Variablen vom Typ Logger wird automatisch generiert
public class CounterService {

  @Autowired
  private CounterRepository repository;

  /**
   *Zähle den Zähler hoch.
   *
   * @Parametername Zählername
   * @Liste der Rückgabezähler
   */
  @Transactional //Starten Sie die Transaktion beim Methodenstart und legen Sie sie am Ende fest
  public Counter countup(String name) {

    //Holen Sie sich 1 Datensatz von DB
    log.debug("Before: getOne");
    Counter counter = repository.getOne(name);
    log.debug("After: getOne");

    //Anzahl aktualisieren
    log.debug("Before: setCount");
    counter.setCount(counter.getCount() + 1);
    log.debug("After: setCount");

    //Datum und Uhrzeit aktualisieren
    log.debug("Before: setUpdatedAt");
    counter.setUpdatedAt(LocalDateTime.now());
    log.debug("After: setUpdatedAt");

    //Holen Sie sich 1 Datensatz von DB
    log.debug("Before: getOne");
    Counter result = repository.getOne(name);
    log.debug("After: getOne");

    return result;
  }
}

src/main/java/com/example/CounterRepository.java

package com.example;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/**
 *Repository für DB-Zugriff.
 *Die von Spring Data JPA standardmäßig bereitgestellte Methode wird automatisch generiert.
 */
@Repository
public interface CounterRepository extends JpaRepository<Counter, String> { //Geben Sie die Entität und den Primärschlüsseltyp an
}

Ausführungsergebnis

Starten Sie die Spring Boot-Anwendung

Starten Sie die Spring Boot-Anwendung mit der Task gradle bootRun.

$ gradle bootRun

> Task :bootRun

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.6.RELEASE)

Wenn Sie sich das Spring Boot-Protokoll ansehen, sehen Sie, dass Hibernate ORM 5.4.12.Final verwendet wird.

org.hibernate.Version                    : HHH000412: Hibernate ORM core version 5.4.12.Final
o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.0.Final}
org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect

Aus der Definition der Entitätsklasse wird automatisch eine DB-Tabelle generiert.

org.hibernate.SQL                        : drop table counter if exists
org.hibernate.SQL                        : create table counter (name varchar(255) not null, count integer not null, updated_at timestamp, primary key (name))
o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'

H2 Datenbankprotokoll. Wie in data.sql beschrieben, wurde die insert-Anweisung ausgegeben.

2020-05-09 23:21:10 jdbc[3]: 
/*SQL */drop table counter if exists;
2020-05-09 23:21:10 jdbc[3]: 
/*SQL t:6*/create table counter (name varchar(255) not null, count integer not null, updated_at timestamp, primary key (name));
2020-05-09 23:21:10 jdbc[3]: 
/*SQL #:1 t:16*/INSERT INTO counter (name, count, updated_at) VALUES ('mycounter', 0, LOCALTIMESTAMP);

Überprüfen Sie das Verhalten bei CounterService # countup

Zugriff mit dem Befehl curl von einem anderen Terminal aus.

$ curl http://localhost:8080/counter/mycounter
{"mycounter":1}

Überprüfen Sie das Spring Boot-Protokoll. Beim Aufruf von CounterService # countup.

com.example.CounterController            : Before: countup
o.s.orm.jpa.JpaTransactionManager        : Creating new transaction with name [com.example.CounterService.countup]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
o.s.orm.jpa.JpaTransactionManager        : Opened new EntityManager [SessionImpl(1254645459<open>)] for JPA transaction
o.s.orm.jpa.JpaTransactionManager        : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@4ef360f9]

Beim Aufruf von CounterRepository # getOne.

com.example.CounterService               : Before: getOne
o.s.orm.jpa.JpaTransactionManager        : Found thread-bound EntityManager [SessionImpl(1254645459<open>)] for JPA transaction
o.s.orm.jpa.JpaTransactionManager        : Participating in existing transaction
com.example.CounterService               : After: getOne

Beim Aufruf von Counter # setCount. Es sieht so aus, als würden wir hier endlich eine Select-Anweisung abgeben.

com.example.CounterService               : Before: setCount
org.hibernate.SQL                        : select counter0_.name as name1_0_0_, counter0_.count as count2_0_0_, counter0_.updated_at as updated_3_0_0_ from counter counter0_ where counter0_.name=?
o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [mycounter]
o.h.type.descriptor.sql.BasicExtractor   : extracted value ([count2_0_0_] : [INTEGER]) - [0]
o.h.type.descriptor.sql.BasicExtractor   : extracted value ([updated_3_0_0_] : [TIMESTAMP]) - [2020-05-09T23:21:10.472636]
com.example.CounterService               : After: setCount

H2 Datenbankprotokoll.

2020-05-09 23:21:19 jdbc[3]: 
/*SQL l:153 #:1*/select counter0_.name as name1_0_0_, counter0_.count as count2_0_0_, counter0_.updated_at as updated_3_0_0_ from counter counter0_ where counter0_.name=? {1: 'mycounter'};
2020-05-09 23:21:19 jdbc[3]: 
/*SQL l:58 #:1*/SELECT VALUE FROM INFORMATION_SCHEMA.SETTINGS WHERE NAME=? {1: 'QUERY_TIMEOUT'};

Beim Aufruf von Counter # setUpdatedAt. Es sieht so aus, als ob es nicht verarbeitet wurde.

com.example.CounterService               : Before: setUpdatedAt
com.example.CounterService               : After: setUpdatedAt

Selbst wenn Sie die Setter-Methode der Entität mehrmals aufrufen (setCount und setUpdatedAt), wird der Aktualisierungsprozess zu diesem Zeitpunkt nicht ausgeführt.

Beim Aufruf von CounterRepository # getOne.

com.example.CounterService               : Before: getOne
o.s.orm.jpa.JpaTransactionManager        : Found thread-bound EntityManager [SessionImpl(1254645459<open>)] for JPA transaction
o.s.orm.jpa.JpaTransactionManager        : Participating in existing transaction
com.example.CounterService               : After: getOne

Nachdem der gesamte Code in CounterService # countup abgeschlossen ist, wird eine Aktualisierungsanweisung ausgegeben und festgeschrieben.

o.s.orm.jpa.JpaTransactionManager        : Initiating transaction commit
o.s.orm.jpa.JpaTransactionManager        : Committing JPA transaction on EntityManager [SessionImpl(1254645459<open>)]
org.hibernate.SQL                        : update counter set count=?, updated_at=? where name=?
o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [INTEGER] - [1]
o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [TIMESTAMP] - [2020-05-09T23:21:19.247019]
o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [VARCHAR] - [mycounter]

H2 Datenbankprotokoll.

2020-05-09 23:21:19 jdbc[3]: 
/*SQL l:53 #:1 t:3*/update counter set count=?, updated_at=? where name=? {1: 1, 2: TIMESTAMP '2020-05-09 23:21:19.247019', 3: 'mycounter'};
2020-05-09 23:21:19 jdbc[3]: 
/*SQL */COMMIT;
2020-05-09 23:21:19 jdbc[3]: 
/*SQL */COMMIT;

Nach der Transaktion.

o.s.orm.jpa.JpaTransactionManager        : Closing JPA EntityManager [SessionImpl(1254645459<open>)] after transaction

CounterService # Countup-Aufruf abgeschlossen.

com.example.CounterController            : After: countup

Referenzmaterial

Recommended Posts

Sehen Sie sich das Verhalten von Entitätsaktualisierungen mit Spring Boot + Spring Data JPA an
Überprüfen Sie das Verhalten von getOne-, findById- und Abfragemethoden mit Spring Boot + Spring Data JPA
Siehe das relative Umleitungsverhalten mit der Einstellung server.tomcat.use-relative-redirects in Spring Boot
Greifen Sie mit jdbcTemplate auf das integrierte h2db des Spring Boot zu
Organisieren Sie die Unterschiede im Verhalten von @NotBlank, @NotEmpty und @NotNull mit Spring Boot + Thymeleaf
Bis zur Verwendung von Spring Data und JPA Part 2
Bis zur Verwendung von Spring Data und JPA Part 1
Ich habe das Spring Boot-Einführungshandbuch [Zugriff auf Daten mit JPA] ausprobiert.
ODER suchen Sie mit der Spring Data Jpa-Spezifikation
Untersuchen Sie das Verhalten des JPA-Transaktionszeitlimits
[Java] [Spring] Testen Sie das Verhalten des Loggers
Implementierungsmethode für Multi-Datenquelle mit Spring Boot (Mybatis und Spring Data JPA)
Bis zur Datenerfassung mit Spring Boot + MyBatis + PostgreSQL
Lassen Sie uns das Gefühl von Spring Boot + Swagger 2.0 überprüfen
Gegenseitige Bezugnahme auf Entity of Spring Data JPA und seine Anmerkungen
Sortieren nach Spring Data JPA (mit zusammengesetzter Schlüsselsortierung)
Erstellen eines gemeinsamen Repositorys mit Spring Data JPA
Spring Boot + Spring Data JPA Informationen zu mehreren Tabellenverknüpfungen
Ressourcenhandler-Einstellungen bei der Bereitstellung von SPA mit der statischen Ressourcenfunktion von Spring Boot
Geben Sie die statische Ressourcencodierung in Spring Boot an
Ein Memorandum beim Versuch von Spring Data JPA mit STS
Kompatibilität von Spring JDBC und My Batis mit Spring Data JDBC (vorläufig)
05. Ich habe versucht, die Quelle von Spring Boot zu löschen
Ich habe versucht, die Kapazität von Spring Boot zu reduzieren
Ich habe versucht, mit Spring Data JPA zu beginnen
Erstellen Sie Restapi mit Spring Boot (bis zum Ausführen der App)
Machen Sie die where-Klauselvariable in Spring Data JPA
[Spring Boot] Die Geschichte, dass die Bean der Klasse mit der Annotation ConfigurationProperties nicht gefunden wurde
Booten nach Umgebung mit Spring Boot of Maven
Überprüfen Sie das Verhalten von include, exclude und ExhaustedRetryException von Spring Retry
Steuern Sie den Spring Batch-Verarbeitungsablauf mit JavaConfig.
Mit Spring Boot herunterladen
[Spring Data JPA] Kann die And-Bedingung in der automatisch implementierten Löschmethode verwendet werden?
Verwendung derselben Mapper-Klasse in mehreren Datenquellen mit Spring Boot + MyBatis
Die Geschichte der Erhöhung von Spring Boot von 1.5 auf 2.1 Serie Teil2
Über die Funktion von Spring Boot aufgrund unterschiedlicher Versionen
Ändern Sie das Injektionsziel für jede Umgebung mit Spring Boot 2
Implementieren Sie die REST-API mit Spring Boot und JPA (Application Layer).
Implementieren Sie die REST-API mit Spring Boot und JPA (Infrastructure Layer).
Schneiden Sie SQL in die Eigenschaftendatei mit jdbcTemplate von Spring Boot aus
Seite, auf der Sie die Versionsrelation von spring (?) Sehen können
[Java] Vereinfachen Sie die Implementierung der Datenverlaufsverwaltung mit Reladomo
Versuchen Sie, die Springcode-Such-API mit Spring Boot aufzurufen
Stellen Sie mit spring boot + spring jpa eine Verbindung zur Datenbank her und führen Sie die CRUD-Operation durch
Fluss bis zur Ausgabe von Tabellendaten, die mit Spring Boot angezeigt werden sollen
Implementieren Sie die REST-API mit Spring Boot und JPA (Domain Layer Edition).
Einführung der Bibliothek ff4j, die Feature Toggle mit Spring Boot realisiert
Generieren Sie mit Spring Boot einen Barcode
Hallo Welt mit Spring Boot
Implementieren Sie GraphQL mit Spring Boot
[spring] Verwenden wir Spring Data JPA
Hallo Welt mit Spring Boot!
Führen Sie LIFF mit Spring Boot aus
SNS-Login mit Spring Boot
Datei-Upload mit Spring Boot
Spring Boot beginnt mit dem Kopieren
Spring Boot beginnend mit Docker
Hallo Welt mit Spring Boot
Setzen Sie Cookies mit Spring Boot
Verwenden Sie Spring JDBC mit Spring Boot