[JAVA] Hinweise zur Verwendung von Spring Data JDBC

Hinweise zur Verwendung von Spring Data JDBC

Einführung

Überblick

Ich habe bisher MyBatis3 verwendet, aber ich hatte Probleme beim Verwalten der Version des automatisch generierten Quellcodes. Daher suchte ich nach einem anderen O / R-Mapper für Spring. Also habe ich in diesem Dokument von Spring Data JDBC erfahren und den Erweiterungsteil aufgeschrieben, den ich häufig verwende.

Umgebung

Java 11 Gradle 5.4.1 Spring Boot 2.3.1.RELEASE Spring Data JDBC 2.0.1.RELEASE

Funktionen von Spring Data JDBC

Bisher hat Spring Data Module veröffentlicht, die JPA unterstützen, die am häufigsten verwendete RDB-Persistenz-API für Java-Anwendungen. Der neu veröffentlichte Spring Data JDBC wird als einfacheres und verständlicheres Modul als JPA veröffentlicht. Das offizielle Dokument erwähnt ausdrücklich die folgenden Punkte.

  1. Verwenden Sie zum Laden von Entitäten kein verzögertes Laden oder Zwischenspeichern. Es gibt jedes Mal SQL aus und alle Felder der Entität werden gelesen.
  2. Federdaten Die JDBC-Seite verwaltet nicht den Lebenszyklus der Entitätsinstanz. Wenn Sie die Entität speichern, wird sie in der Datenbank gespeichert. Wenn Sie die Entität nicht explizit speichern, werden die Änderungen nicht in der Datenbank übernommen. Selbst wenn die Entität von einem anderen Thread neu geschrieben wird, wird sie nicht erkannt.
  3. Die Zuordnung von Entitätstabellen verwendet eine einfache Zuordnungsmethode. Wenn Sie die zuvor vorbereitete Zuordnungsmethode nicht befolgen, müssen Sie die Zuordnung selbst codieren.

Im Gegensatz zu Spring Data JPA gibt es nicht so viele Funktionen. Daher scheint das Entwerfen nach der von Spring Data JDBC bereitgestellten Methode der Schlüssel zur Verwendung von Spring Data JDBC zu sein.

Einführungsmethode

Projekterstellung

Wählen Sie unter Spring Initializr Folgendes aus und laden Sie das Projekt herunter.

Artikel Entscheidungen
Project Gradle Project
Language Java
Spring Boot 2.2.1
Dependencies Spring Data JDBC、Lombok

Es ist in Ordnung, ein anderes Projekt und eine andere Sprache auszuwählen, aber einige der hier vorgestellten Quellen werden ersetzt. Die Version von Spring Boot, die ausgewählt werden kann, hängt von der Zeit ab. Es ist jedoch in Ordnung, wenn Sie die Standardversion auswählen.

build.gradle sollte folgendermaßen aussehen:

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

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

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
	runtimeOnly 'com.h2database:h2'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
}

test {
	useJUnitPlatform()
}

Stellen Sie die Datenquelle im Frühjahr ein

Erstellen Sie application.yml unter src / main / resources und stellen Sie die Datenquelle wie folgt ein. Dieses Mal habe ich H2Database so eingestellt, dass es im PostgreSQL-Modus startet.

application.yml


spring:
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:;DB_CLOSE_ON_EXIT=TRUE;MODE=PostgreSQL
    username: sa
    password:

Erstellen Sie schema.sql

Erstellen Sie eine SQL-Datei "schema.sql", die die Test-DDL unter "src / main / resources" beschreibt.

schema.sql


create table member
(
	id varchar not null
		constraint member_pk
			primary key auto_increment,
	name varchar not null
);

Erstellen Sie Entitäten und Repositorys

Vergessen Sie nicht, die Eigenschaft, die dem Primärschlüssel der Tabelle entspricht, mit "@ Id" zu versehen. Da die ID der Member-Klasse, wenn sie nicht beibehalten wird, Null ist, fügen Sie auch die Annotation "@ Wither" hinzu.

Member.java


@RequiredArgsConstructor
@Getter
@EqualsAndHashCode(of = {"id"})
@ToString
public class Member {
	@Id
	@Wither
	private final String id;
	private final String name;
}

Erstellen Sie ein Repository, das von "CrudRepository" erbt. Geben Sie das Typargument in der Reihenfolge Entitätstyp und ID-Typ an.

MemberRepository.java


public interface MemberRepository extends CrudRepository<Member, String> {
}

Damit ist die folgende Methode in MemberCredentialRepository definiert.

Es ist ähnlich wie bei JPA. Die Methode save führt die Anweisung INSERT und die Anweisung UPDATE aus. Die Logik, die bestimmt, welche Anweisung ausgeführt werden soll, lautet jedoch wie folgt.

  1. Die Spalte mit der Annotation "@ Id" ist Null.
  2. Entity ist die Implementierungsklasse der 'Persistable'-Schnittstelle, und die isNew () -Methode ist true.

Diesmal habe ich Muster 1 übernommen.

Überprüfen Sie den Betrieb

Bereiten Sie eine Testklasse vor, um den Vorgang zu überprüfen. Ich frage mich, ob es in Ordnung ist, wenn ich die Daten vorerst registrieren und prüfen kann, ob die Daten enthalten sind.

MemberRepositoryTest.java


@DataJdbcTest
class MemberRepositoryTest {

	@Autowired
	private MemberRepository memberRepository;

	@Test
	void test() {
		String name = "Kuchita";
		Member save = memberRepository.save(new Member(null, name));
		assertNotNull(save.getId());
		Optional<Member> maybeMember = memberRepository.findById(save.getId());
		assertTrue(maybeMember.isPresent());
		maybeMember
			.ifPresent(member -> assertEquals(save.getName(), member.getName()));
	}
}

Tipps: Wenn Test keine integrierte Datenbank verwendet

Wenn Sie "@ DataJdbcTest" gewähren, wird die integrierte Datenbank standardmäßig gestartet. Dieses Mal habe ich h2 verwendet, es ist also in Ordnung, aber wenn Sie eine Verbindung zu einem externen Datenbankserver herstellen möchten, fügen Sie Folgendes zu application.properties hinzu.

application.properties


spring.test.database.replace=none

Durch Hinzufügen dieser Option können Sie zum Zeitpunkt des Tests Ihren bevorzugten Datenbankserver verwenden.

Detaillierte Verwendung

Repository

Grundlegende Verwendung

Spring Data JDBC realisiert den Datenbankzugriff, indem eine Schnittstelle erstellt wird, die die zuvor vorbereitete Repository-Schnittstelle erbt. Standardmäßig wird eine praktische Schnittstelle bereitgestellt, die grundlegende Methoden gemäß der im Argument type und dem Typ der Entität angegebenen ID bereitstellt.

Variationen der Repository-Schnittstelle

Die im Voraus vorbereiteten Klassen sind wie folgt.

Name der Schnittstelle Spezifikation
Repository<Entity, Id> Bietet eine leere, grundlegendste Repository-Schnittstelle.
CrudRepository<Entity, Id> Neben CRUDcountOderexistsByIdStellen Sie Methoden wie.
PagingAndSortingRepository<Entity, Id> Darüber hinaus bietet es eine Methode, um das Ergebnis von Paging und Sortierung zurückzugeben.

Ich denke, es ist in Ordnung, wenn Sie es wie folgt richtig verwenden.

** Spring Data JDBC 1.1.1.RELEASE Derzeit ** PagingAndSortRepository funktionierte nicht richtig. stack overflow -PagingAndSortingRepository methods throw error when used with spring data jdbc-

Benutzerdefiniertes Basis-Repository

Möglicherweise möchten Sie zusätzlich zur Standardschnittstelle eine Schnittstelle definieren, die allen Projekten gemeinsam ist. In diesem Fall erweitern wir die Schnittstelle. Fügen Sie zu diesem Zeitpunkt der Klasse die Annotation @ NoRepositoryBean hinzu.

Unten finden Sie die Basisschnittstelle des Crud-Repositorys, die nur die Methoden definiert, mit denen die Entität geladen wird.

ReadOnlyRepository.java


@NoRepositoryBean
public interface ReadOnlyRepository extends Repository<Member, String> {
    Iterable<Member> findAll();
    Optional<Member> findById(String id);
}

Benutzerdefinierte Abfrage

Fügen Sie für Methoden, die nicht als Standard bereitgestellt werden, die Annotation "@ Query" zur Methode hinzu und beschreiben Sie SQL im Argument der Annotation, um sie zu definieren. Die Parameter, die Sie an SQL übergeben möchten, können mit : argument name angegeben werden.

MemberRepository.java



public interface MemberRepository extends CrudRepository<Member, String> {
    @Query("SELECT * FROM member WHERE name = :name")
    List<Member> getMembersByNameEquals(String name);
}

Entität

Grundlegende Definition

Das grundlegende Implementierungsmuster besteht darin, unveränderliche Objekte oder JavaBeans zu definieren. Ich werde es unter der Annahme beschreiben, dass die ID automatisch generiert wird.

Unveränderliches Objekt

Eine Entität, die ein unveränderliches Feld definiert, und ein Konstruktor, der alle Felder als Argumente verwendet.

Um mehrere Konstruktoren mit Argumenten zu definieren, müssen Sie dem Konstruktor, der für die Instanziierung in Spring Data JDBC verwendet wird, die Annotation "@ PersistenceConstructor" hinzufügen. Wenn Sie Spring Data JDBC nicht mit Anmerkungen versehen möchten, können Sie eine Factory-Methode separat definieren.

Fügen Sie der Spalte "@ Id" die Spalte hinzu, die zum Bezeichner wird. Da der ID nach dem Speichern der Entität die in der Datenbank ausgegebene Kennung zugewiesen wird, definieren Sie den Widerrist, damit die ID aktualisiert werden kann.

** * Die Referenz zeigte zwei Methoden, eine zur Verwendung des Konstruktors für vollständige Argumente und eine zur Verwendung von Wither. Da die erstere Methode in meiner Umgebung nicht funktioniert hat, werde ich die Methode mit Wither einführen. Ich bin. ** **.

Member.java


@RequiredArgsConstructor
@Getter
@EqualsAndHashCode(of = {"id"})
@ToString
public class Member {
    @Id
    @With
    private final String id;
    private final String name;

    public static Member createInstance(String name) {
        return new Member(null, name);
    }
}
JavaBeans-Muster

Eine Entität, die Accessoren für Standardkonstruktoren und -felder definiert.

Member.java


@Getter
@Setter
@EqualsAndHashCode(of = {"id"})
@ToString
public class Member {
    @Id
    private String id;
    private String name;

    public static Member createInstance(String name) {
        return new Member(null, name);
    }
}

Spezifikationen für die Objekterstellung

  1. Wenn ein Konstruktor ohne Argumente definiert ist, erstellen Sie eine Instanz mit dem Konstruktor ohne Argumente
  2. Wenn ein Konstruktor mit anderen Argumenten als 1 definiert ist, erstellen Sie eine Instanz mit dem Konstruktor mit Argumenten.
  3. Wenn mehrere Konstruktoren mit Argumenten vorhanden sind, erstellen Sie mit dem Konstruktor eine Instanz mit "@ PersistenceConstructor".

Spezifikationen für die Zuordnung zu Feldern

  1. Wenn für ein unveränderliches Feld ein Widerrist definiert ist, legen Sie den Wert für das Feld mit Widerrist fest.
  2. Wenn Sie einen Setter haben, verwenden Sie den Setter, um den Wert im Feld festzulegen
  3. Wenn das Feld veränderbar ist, setzen Sie den Wert direkt in das Feld

Spezifikationen für das Lebenszyklusmanagement von Unternehmen

In Spring Data JDBC wird die Speichermethode zum Speichern und Aktualisieren der Entität verwendet. Ob Sie eine INSERT-Anweisung oder eine UPDATE-Anweisung ausgeben möchten, hängt davon ab, ob die Entität bereits beibehalten wurde oder noch nicht. In Spring Data JDBC gibt es zwei Hauptbeurteilungslogiken.

  1. Stellen Sie fest, ob die Entitätskennung null ist.
  2. Wenn die Entität "Persistable # isNew" implementiert, bestimmen Sie anhand des Rückgabewerts der Methode, ob die Entität persistent ist oder nicht.

Wenn die ID nicht automatisch auf der Datenbankseite generiert wird, ist es besser, die Entität gemäß der zweiten Methode zu definieren.

Informationen zur Datentypkonvertierung

Standardmäßig unterstützte Typen

Spring Data JDBC bietet nur eingeschränkte Unterstützung für hasOne- und hasMany-Beziehungen. Behalten Sie eine Entität oder ihre Menge nur dann in einem Feld, wenn die Beziehung zwischen der Stammentität und der Entität innerhalb ihres Aggregats im domänengesteuerten Design gilt.

Wenn Sie die Beziehung zwischen hasOne und hasMany zufällig definieren, werden NULL und Empty nicht durch "ob die Daten tatsächlich vorhanden sind oder nicht" definiert, sondern durch "ob die Daten von SQL verbunden werden oder nicht". Selbst wenn Sie Spring Data JDBC nicht verwenden, kann dies zu schwerwiegenden Fehlern und verminderter Produktivität führen.

Passen Sie die Typkonvertierung an

Die Typkonvertierung kann mit Converter oder Converter Factory angepasst werden. Wenden Sie den erstellten Converter und die ConverterFactory in der Konfigurationsklasse an, die AbstractJdbcConfiguration erbt. Sie können Ihre eigene Konvertierungsklasse anwenden, indem Sie die Methode "jdbcCustomConversions" überschreiben.

JdbcConfiguration.java


@Configuration
public class JdbcConfiguration extends AbstractJdbcConfiguration {
	@Override
	public JdbcCustomConversions jdbcCustomConversions() {
		return new JdbcCustomConversions(List.of(
			// Converter/Registrieren Sie die Bean von ConverterFactory
		));
	}
}
Wenn das Konvertierungsziel eine bestimmte Klasse ist

Implementieren Sie Conveter, wenn das Ziel eine bestimmte einzelne Klasse ist, z. B. das Konvertieren von Enum in String.

Weisen Sie dem definierten Conveter "@ ReadingConverter" oder "@ WritingConveter" zu. Wenn es sich um einen Konverter handelt, der beim Lesen aus der Datenbank verwendet wird, fügen Sie "@ ReadingConverter" hinzu, und wenn es sich um einen Konverter handelt, der beim Schreiben in die Datenbank verwendet wird, fügen Sie "@ WritingConverter" hinzu.

EnumToStringConverter.java


@WritingConverter
public enum EnumToStringConverter implements Converter<Enum, String> {
	INSTANCE;
	@Override
	public String convert(Enum e) {
		return e.name();
	}
}
Wenn das Konvertierungsziel eine Schnittstellenimplementierung oder eine Unterklasse einer bestimmten Klasse ist

Wenn das Konvertierungsziel eine Schnittstellenimplementierung oder eine Unterklasse einer bestimmten Klasse ist, z. B. das Konvertieren von String in Enum, implementieren Sie ConverterFactory.

Da das formale Argument von "ConverterFactory # getConverter" die Informationen der Konvertierungszielklasse sind, ist es von Vorteil, dass die Informationen der Konvertierungszielklasse beim Erstellen einer Converter-Instanz verarbeitet werden können.

Die Anmerkungen sind die gleichen wie für Converter.

StringToEnumFactory.java


@ReadingConverter
public enum StringToEnumFactory implements ConverterFactory<String, Enum> {
	INSTANCE;
	@Override
	public <T extends Enum> Converter<String, T> getConverter(Class<T> aClass) {
		return new StringToEnum<T>(aClass);
	}

	@RequiredArgsConstructor
	private static class StringToEnum<T extends Enum> implements Converter<String, T> {
		private final Class<T> enumType;

		@Override
		public T convert(String s) {
			return s == null ? null : Enum.valueOf(enumType, s);
		}
	}
}

Ordnen Sie verschachtelten Objekten mehrere Spalten zu

Sie können die Annotation "@ Embedded" verwenden, um benutzerdefinierte Wertobjekte und Spalten zuzuordnen.

Die Entität "Mitglied" mit dem Wertobjekt "Adresse" im Feld kann einer Tabellenspalte zugeordnet werden, indem sie wie folgt definiert wird:

Address.java


@RequiredArgsConstructor
@Getter
@EqualsAndHashCode
public class Address {
	private final String postcode;
	private final String prefecture;
	private final String addressLine;
}

Member.java


@Getter
@EqualsAndHashCode(of = {"id"})
@ToString
public class Member {
    @Id
    @With
    private final String id;
    private final String name;
    @Embedded(prefix = "address_", onEmpty = Embedded.OnEmpty.USE_NULL)
    private final Address address;

    public static Member createInstance(String name, Address address) {
        return new Member(null, name, address);
    }
}

Wie im Beispiel muss die Annotation "@ Embedded" zwei Argumente haben, "Präfix" und "onEmpty".

prefix

Jedes Feld im Wertobjekt wird einer Spalte mit "Präfix" und "Feldname im Wertobjekt" zugeordnet. Nun wird die Zuordnung von Feld zu Spalte "Adresse" wie folgt aufgelöst:

Feldname Spaltenname
postcode address_postcode
prefecture address_prefecture
addressLine address_address_line

onEmpty

Gibt an, welcher Wert im Feld der Entität festgelegt werden soll, wenn das dem Wertobjekt entsprechende Feld NULL ist.

Wert einstellen Inhalt
USE_NULL Setze NULL
USE_EMPTY Legen Sie ein leeres Wertobjekt fest

Grundsätzlich denke ich, dass es sicher ist, USE_NULL zu verwenden.

schließlich

Dies ist das Ende der ersten Ausgabe, und ich möchte das Wissen organisieren, während ich es in Zukunft betreibe.

Referenz-URL

Offizielle Referenz zu Spring Data JDBC stack overflow -PagingAndSortingRepository methods throw error when used with spring data jdbc- Konvertieren Sie Enum mit Spring Data JDBC in eine Nummer ohne Bestellung

Recommended Posts

Hinweise zur Verwendung von Spring Data JDBC
Wie man Lombok im Frühling benutzt
[So installieren Sie Spring Data Jpa]
Verwendung von ModelMapper (Spring Boot)
Verwendung von Map
Wie benutzt man rbenv?
Verwendung mit_option
Verwendung von fields_for
Verwendung von java.util.logging
Verwendung der Karte
Verwendung von collection_select
Wie benutzt man Twitter4J
Wie benutzt man active_hash! !!
Verwendung von MapStruct
Verwendung von TreeSet
Spring Data JDBC-Vorschau
[Verwendung des Etiketts]
Wie man Identität benutzt
Wie man Hash benutzt
Verwendung von Dozer.mapper
Wie benutzt man Gradle?
Verwendung von org.immutables
Verwendung von java.util.stream.Collector
Verwendung von VisualVM
Verwendung von Map
Verwendung von MyBatis2 (iBatis) mit Spring Boot 1.4 (Spring 4)
Verwendung des eingebauten h2db mit Federstiefel
Verwendung von Spring Boot-Sitzungsattributen (@SessionAttributes)
Verwendung der Ketten-API
[Java] Verwendung von Map
Verwendung der Warteschlange mit Priorität
[Rails] Verwendung von Enum
Verwendung von Java Optional
Verwendung von JUnit (Anfänger)
Verwendung von Ruby return
[Rails] Verwendung von Enum
[spring] Verwenden wir Spring Data JPA
Verwendung von @Builder (Lombok)
Verwendung der Java-Klasse
Wie man Big Decimal benutzt
[Java] Verwendung von removeAll ()
Verwendung von String [] args
Verwendung von Rails Join
Verwendung von Java Map
Ruby: Wie man Cookies benutzt
Verwendung von abhängigen :: zerstören
Verwendung von Eclipse Debug_Shell
Verwendung von Apache POI
[Rails] Verwendung der Validierung
Verwenden Sie Spring JDBC mit Spring Boot
Verwendung von Java-Variablen
[Rails] So verwenden Sie authenticate_user!