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.
Java 11 Gradle 5.4.1 Spring Boot 2.3.1.RELEASE Spring Data JDBC 2.0.1.RELEASE
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.
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.
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()
}
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 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
);
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.
Diesmal habe ich Muster 1 übernommen.
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()));
}
}
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.
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.
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 CRUDcount OderexistsById Stellen 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-
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);
}
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);
}
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.
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);
}
}
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);
}
}
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.
Wenn die ID nicht automatisch auf der Datenbankseite generiert wird, ist es besser, die Entität gemäß der zweiten Methode zu definieren.
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.
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
));
}
}
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, 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);
}
}
}
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.
Dies ist das Ende der ersten Ausgabe, und ich möchte das Wissen organisieren, während ich es in Zukunft betreibe.
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