Der erste Eintrag im Jahr 2018 ist ... Ich habe @ sndrs "Spring Data JDBC Preview" gesehen und dachte "Hey" Spring Data JDBC Es ist ein Memo, als ich es ausprobiert habe. Es scheint immer noch eine einfache Unterstützung auf CRUD-Ebene zu sein, aber mit der offiziellen Veröffentlichung von Spring Data JDBC (https://github.com/spring-projects/spring-data-jdbc), Spring Data REST (https) Wir freuen uns (sehr) darauf, unterstützt zu werden unter: //projects.spring.io/spring-data-rest/)! ↓ ** Seit der offiziellen Veröffentlichung am 21.09.2008 wurde der Inhalt basierend auf 1.0.0.RELEASE geändert! ** ** **
HINWEIS: Verlauf aktualisieren
2018-02-06 :
- DATAJDBC-161 Unterstützt Änderungen der Benutzeroberfläche aufgrund der Unterstützung
- Mit Spring Boot 2.0.0.RC1 erneut validiert
2018-02-08 :
- Verwendung der Methode "@ Query" hinzugefügt (entspricht DATAJDBC-172)
2018-03-08 :
- Es wurde hinzugefügt, dass der einfache Typ aufgrund der Unterstützung von DATAJDBC-175 als Rückgabewert der Methode @ @ Query unterstützt wird.
- Mit Spring Boot 2.0.0.RELEASE erneut validiert
2018-03-09 :
- Beschreibung zum Umgang mit verwandten Objekten hinzugefügt
- In Bezug auf das Obige wurde hinzugefügt, dass es notwendig ist, Lovelace-BUILD-SNAPSHOT des Spring-Data-Release-Zugs zu importieren, wenn Spring Data JDBC auf Spring Boot 2.0.0.RELEASE verwendet wird.
2018-03-10 :
- Verwendung der Update-Abfrage hinzugefügt (
@ Modifying
) (entspricht DATAJDBC-182)2018-03-23 :
- Behoben, dass "DefaultNamingStrategy" nicht verwendet wird, da DATAJDBC-189 unterstützt wird (Standardimplementierung ist als "NamingStrategy.INSTANCE" definiert)
- Auf MyBatis Spring Boot Starter 1.3.2 aktualisiert
2018-03-31 :
- Es wurde behoben, dass "NamedParameterJdbcOperations" beim Generieren von "DefaultDataAccessStrategy" nicht angegeben wurde, da DATAJDBC-155 unterstützt wurde.
NamingStrategy
hinzugefügt, um Schlangenfälle (Unterstriche) mit Unterstützung von DATAJDBC-184 zu unterstützen.2018-04-03 :
- Mit Unterstützung für DATAJDBC-178 kann durch Festlegen einer beliebigen NamespaceStrategy-Instanz in MyBatisDataAccessStrategy die Namenskonvention des Namespace geändert werden. Es wurde hinzugefügt, dass es geändert werden kann
2018-05-18 :
- Beschreibung zur Unterstützung der annotationsbasierten Überwachungsfunktion hinzugefügt (entsprechend DATAJDBC-204)
- Update auf Spring Boot 2.0.2.RELEASE und erneutes Validieren
2018-05-19 :
- Reflektierte Änderungen der Paketkonfiguration (entsprechend DATAJDBC-138)
2018-06-28 :
- Reflektiert Änderungen der Paketkonfiguration und des Klassennamens (entspricht DATAJDBC-226)
- Es wurde hinzugefügt, dass die Standardimplementierung von "NamingStrategy" als Reaktion auf DATAJDBC-207 in "Snake Case" geändert wurde.
- Auf Spring Boot 2.0.3.RELEASE aktualisiert und erneut validiert
2018-07-03 :
- Der explizite Import von Spring-Data-Releasetrain Lovelace-BUILD-SNAPSHOT wurde entfernt und
<spring-data-releasetrain.version> Lovelace-BUILD-SNAPSHOT </ spring-data-releasetrain.version>
zu den Eigenschaften hinzugefügt. Behoben, um hinzuzufügen2018-07-20 :
- Reflektierte die Änderung in der Anwendungsmethode des benutzerdefinierten Konverters (entsprechend DATAJDBC-235)
- Es wurde ein Problem behoben, bei dem MyBatis beim Löschen von All einen Fehler ausgibt. Es scheint, dass sich die SQL-ID, die die Entität löscht, geändert hat! ??
2018-07-28 :
- Reflektierte die Änderung in der Anwendungsmethode von
JdbcConfiguration
(entsprechend DATAJDBC-243)2018-09-22 :
- Die Version der Spring Data JDBC-Überprüfung wurde auf 1.0.0.RELEASE korrigiert
- Die Spring Boot-Überprüfungsversion wurde auf 2.0.5.RELEASE korrigiert
- Beschreibt Spring-Boot-Starter-Data-JDBC
2018-09-23 :
- Die Erklärung zum Angeben / Erweitern von JdbcConfiguration wurde korrigiert (Korrektur aufgrund des Einflusses von DATA JDBC-267).
Die in diesem Eintrag beschriebenen Quellen werden in den folgenden Repositories veröffentlicht. (Da Spring JDBC und MyBatis gemischt und verifiziert sind, gibt es einige Unterschiede zur Beschreibung im Eintrag.)
Wählen Sie zunächst in SPRING INITIALIZR "H2", "JDBC" und "MyBatis (nur bei Verwendung von MyBatis)" als Abhängigkeiten zum Erstellen eines Projekts aus. (Dieser Eintrag basiert auf dem Maven-Projekt) Fügen Sie als Nächstes "spring-data-jdbc" zu dem von SPRING INITIALIZR erstellten Projekt hinzu. Bei Verwendung von Spring Data JDBC in der Spring Boot 2.0-Serie muss die Lovelace-RELEASE-Version von Spring-Data-Releasetrain in den von Spring Boot bereitgestellten Eigenschaften wie folgt angegeben werden.
pom.xml
<properties>
<spring-data-releasetrain.version>Lovelace-RELEASE</spring-data-releasetrain.version>
</properties>
pom.xml
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jdbc</artifactId>
</dependency>
Bereiten Sie eine DDL vor, um eine Tabelle zu erstellen.
src/main/resources/schema.sql
CREATE TABLE IF NOT EXISTS todo (
id IDENTITY
,title TEXT NOT NULL
,details TEXT
,finished BOOLEAN NOT NULL
);
Erstellen Sie ein Todo-Objekt, das den Datensatz in der TODO-Tabelle darstellt. Fügen Sie der Eigenschaft, die den Schlüsselwert enthält, "@ Id" hinzu.
src/main/java/com/example/demo/domain/Todo.java
package com.example.demo.domain;
import org.springframework.data.annotation.Id;
public class Todo {
@Id
private int id;
private String title;
private String details;
private boolean finished;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDetails() {
return details;
}
public void setDetails(String details) {
this.details = details;
}
public boolean isFinished() {
return finished;
}
public void setFinished(boolean finished) {
this.finished = finished;
}
}
Erstellen Sie eine Repository-Schnittstelle zum Bearbeiten von Domänenobjekten. Es geht darum, das von Spring Data bereitgestellte "Croud Repository" zu erben.
src/main/java/com/example/demo/repository/TodoRepository.java
package com.example.demo.repository;
import org.springframework.data.repository.CrudRepository;
import com.example.demo.domain.Todo;
public interface TodoRepository extends CrudRepository<Todo, Integer> {
}
Auf diese Weise ... Sie können das Todo-Objekt mit den folgenden in "CrudRepository" definierten Methoden bedienen.
Referenz: Auszug aus dem Crud Repository
package org.springframework.data.repository;
import java.util.Optional;
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
<S extends T> S save(S entity);
<S extends T> Iterable<S> saveAll(Iterable<S> entities);
Optional<T> findById(ID id);
boolean existsById(ID id);
Iterable<T> findAll();
Iterable<T> findAllById(Iterable<ID> ids);
long count();
void deleteById(ID id);
void delete(T entity);
void deleteAll(Iterable<? extends T> entities);
void deleteAll();
}
Spring Data JDBC bietet "DataAccessStrategy" als Schnittstelle zum Abstrahieren der SQL-Ausführungsmethode. Derzeit sind die Implementierung von "Spring JDBC (" NamedParameterJdbcOperations ")" und "MyBatis" implementiert.
Wenn Sie die Spring JDBC-Implementierung verwenden, wird die SQL, die ausgeführt werden soll, wenn Sie die in "CrudRepository" definierte Methode aufrufen, automatisch generiert (= Sie müssen kein SQL für CRUD-Operationen schreiben).
Erstellen Sie eine Konfigurationsklasse mit "@ EnableJdbcRepositories" und "@Import (JdbcConfiguration.class)". Jedoch ... Wenn Sie die in JdbcConfiguration
definierte Bean ändern möchten, müssen Sie eine Konfigurationsklasse erstellen, die JdbcConfiguration
erbt, und sie als DI-Container registrieren. Wenn Sie beispielsweise Typkonvertierungen benötigen, die standardmäßig nicht unterstützt werden, können Sie die Methode "jdbcCustomConversions" überschreiben und "JdbcCustomConversions" mit einem beliebigen "Konverter" zurückgeben. In diesem Eintrag wird "Konverter" hinzugefügt, um den TEXT-Typ ("Clob") der H2-Datenbank in "String" zu konvertieren. Übrigens ... Wenn Sie VARCHAR anstelle von TEXT verwenden, müssen Sie die Methode "jdbcCustomConversions" nicht überschreiben.
@EnableJdbcRepositories
@Configuration
public class SpringDataJdbcConfig extends JdbcConfiguration {
@Override
protected JdbcCustomConversions jdbcCustomConversions() {
return new JdbcCustomConversions(Collections.singletonList(new Converter<Clob, String>() {
@Override
public String convert(Clob clob) {
try {
return clob == null ? null : clob.getSubString(1L, (int) clob.length());
} catch (SQLException e) {
throw new IllegalStateException(e);
}
}
}));
}
}
Note:
NamingStrategy
wird als Schnittstelle zur Bestimmung der Namensstrategie für Spalten- und Eigenschaftsnamen bereitgestellt. Standardmäßig wird "NamingStrategy.INSTANCE" verwendet. Sie können das Standardverhalten jedoch ändern, indem Sie eine Bean für "NamingStrategy" definieren. ~~ Zusätzlich wurdeNamingStrategy
, das Schlangenfälle (Unterstriche) unterstützt, durch die Unterstützung von DATAJDBC-184 (bei Verwendung) hinzugefügt. Bean Definition erforderlich). ~~ Das Standardverhalten wird als Schlangenfall behandelt (Unterstrich) (das Standardverhalten wurde geändert, um [DATAJDBC-206] zu unterstützen (https://jira.spring.io/browse/DATAJDBC-206)).
Bei Verwendung der MyBatis-Implementierung muss die auszuführende SQL definiert werden, wenn die in "CrudRepository" definierte Methode auf der MyBatis-Seite aufgerufen wird. (= Es ist notwendig, SQL auch für CRUD-Operationen zu schreiben).
Erstellen Sie eine Konfigurationsklasse mit "@ EnableJdbcRepositories" und "@Import (JdbcConfiguration.class)" und definieren Sie eine Bean von "MyBatisDataAccessStrategy" (MyBatis-Implementierung) als "DataAccessStrategy".
@EnableJdbcRepositories
@Import(JdbcConfiguration.class)
@Configuration
public class SpringDataJdbcConfig {
@Bean
DataAccessStrategy dataAccessStrategy(SqlSession sqlSession) {
return new MyBatisDataAccessStrategy(sqlSession);
}
}
NOTE:
2018-02-06: Mit Unterstützung von DATAJDBC-161 wird das an das Konstruktorargument von "MyBatisDataAccessStrategy" zu übergebende Objekt von "SqlSessionFactory" an "SqlSession" übergeben. (Eigentlich geändert in
SqlSessionTemplate
).
Legen Sie den Speicherort und den Typalias der Mapper-XML-Datei fest.
src/main/resources/application.properties
mybatis.mapper-locations=classpath:/com/example/demo/mapper/*Mapper.xml
mybatis.type-aliases-package=com.example.demo.domain
Definieren Sie die SQL entsprechend der Methode von "CrudRepository". Wenn Sie MyBatis über Spring Data JDBC verwenden, müssen Sie beim Definieren von SQL einige spezielle Regeln beachten.
NOTE:
2018-04-03: Mit Unterstützung von DATAJDBC-178 durch Festlegen einer beliebigen
NamespaceStrategy
-Instanz inMyBatisDataAccessStrategy
, dem Namen Sie können die Namenskonvention für Leerzeichen ändern.
src/main/resources/com/example/demo/mapper/TodoMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.domain.TodoMapper">
<!-- statements for CrudRepository method -->
<insert id="insert" useGeneratedKeys="true" keyProperty="instance.id">
INSERT INTO todo
(title, details, finished)
VALUES
(#{instance.title}, #{instance.details}, #{instance.finished})
</insert>
<update id="update">
UPDATE todo SET
title = #{instance.title}, details = #{instance.details}, finished = #{instance.finished}
WHERE
id = #{instance.id}
</update>
<delete id="delete">
DELETE FROM todo WHERE id = #{id}
</delete>
<delete id="deleteAll">
DELETE FROM todo
</delete>
<select id="existsById" resultType="_boolean">
SELECT count(*) FROM todo WHERE id = #{id}
</select>
<select id="findById" resultType="Todo">
SELECT
id, title, details, finished
FROM
todo
WHERE
id = #{id}
</select>
<select id="findAll" resultType="Todo">
SELECT
id, title, details, finished
FROM
todo
ORDER BY
id
</select>
<select id="findAllById" resultType="Todo">
SELECT
id, title, details, finished
FROM
todo
<where>
<foreach collection="id" item="idValue" open="id in("
separator="," close=")">
#{idValue}
</foreach>
</where>
ORDER BY
id
</select>
<select id="count" resultType="_long">
SELECT count(*) FROM todo
</select>
</mapper>
Referenz: Auszug aus MyBatisContext
package org.springframework.data.jdbc.mybatis;
import java.util.Map;
public class MyBatisContext {
private final Object id;
private final Object instance;
private final Class domainType;
private final Map<String, Object> additonalValues;
public MyBatisContext(Object id, Object instance, Class domainType, Map<String, Object> additonalValues) {
this.id = id;
this.instance = instance;
this.domainType = domainType;
this.additonalValues = additonalValues;
}
public Object getId() {
return id;
}
public Object getInstance() {
return instance;
}
public Class getDomainType() {
return domainType;
}
public Object get(String key) {
return additonalValues.get(key);
}
}
Ich werde es in diesem Eintrag nicht erklären + Ich habe es nicht überprüft, aber es scheint möglich zu sein, mehrere Implementierungen (z. B. Spring JDBC und MyBatis) zusammen mit CascadingDataAccessStrategy
zu verwenden.
Das Spring Data JDBC-Repository wird wie jedes andere Spring Data-Projekt injiziert und verwendet.
@Autowired
private TodoRepository todoRepository;
@Test
public void insertAndFineById() {
Todo newTodo = new Todo();
newTodo.setTitle("Trinkparty");
newTodo.setDetails("Ginza 19:00");
todoRepository.save(newTodo);
Optional<Todo> todo = todoRepository.findById(newTodo.getId());
Assertions.assertThat(todo.isPresent()).isTrue();
Assertions.assertThat(todo.get().getId()).isEqualTo(newTodo.getId());
Assertions.assertThat(todo.get().getTitle()).isEqualTo(newTodo.getTitle());
Assertions.assertThat(todo.get().getDetails()).isEqualTo(newTodo.getDetails());
Assertions.assertThat(todo.get().isFinished()).isFalse();
}
Jede Abfrage kann (mithilfe der Spring JDBC-Funktion) ausgeführt werden, indem dem Repository eine Methode mit "@ Query" hinzugefügt wird.
~~WARNING:~~ ~~ Mit der aktuellen Implementierung ist es nicht möglich, Update SQL auszuführen (es scheint Pläne zu geben, dies zu unterstützen). ~~
NOTE: 10.03.2018: DATAJDBC-182 unterstützt auch die Ausführung von Update SQL.
src/main/java/com/example/demo/repository/TodoRepository.java
package com.example.demo.repository;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import com.example.demo.domain.Todo;
public interface TodoRepository extends CrudRepository<Todo, Integer> {
@Query("SELECT * FROM todo WHERE id = :id")
Optional<Todo> findOptionalById(@Param("id") Integer id);
@Query("SELECT * FROM todo WHERE id = :id")
Todo findEntityById(@Param("id") Integer id);
@Query("SELECT * FROM todo ORDER BY id")
Stream<Todo> findAllStream();
@Query("SELECT * FROM todo ORDER BY id")
List<Todo> findAllList();
@Query("SELECT count(*) FROM todo WHERE finished = :finished")
long countByFinished(@Param("finished") Boolean finished);
@Query("SELECT count(*) FROM todo WHERE finished = :finished")
boolean existsByFinished(@Param("finished") Boolean finished);
@Query("SELECT current_timestamp()")
LocalDateTime currentDateTime();
@Modifying
@Query("UPDATE todo SET finished = :finished WHERE id = :id")
boolean updateFinishedById(@Param("id") Integer id, @Param("finished") boolean finished);
}
NOTE:
@ Param
kann durch Angabe der Option-parameters
des Java-Compilers weggelassen werden.
Derzeit werden folgende Rückgabetypen unterstützt
T
(Domänenklasse)java.util.Optional<T>
java.lang.Iterable <T>
zugewiesen werden können (z. B. java.util.List <T>
)java.util.stream.Stream<T>
Und "org.springframework.data.domain.Page
Darüber hinaus wird als Rückgabewert der Aktualisierungsmethode Folgendes unterstützt
int
(Integer
)boolean
(Boolean
)void
Ist.
~~WARNING:~~ ~~ In der aktuellen Implementierung ist es nicht möglich, einen anderen Typ als die Domänenklasse anzugeben, z. B. einen numerischen Wert (
int
,long
usw.) oder einen booleschen Wert als Rückgabewert (dh ...@ Query
-Methode-Ausbuchung). Sie können kein SQL angeben, um die Nummer abzurufen, oder ein SQL, um das Vorhandensein von Datensätzen zu überprüfen. Es kann mit der Methode behandelt werden, die unten unter "Hinzufügen von benutzerdefinierten Operationen" vorgestellt wird, aber ... Ich habe das Gefühl, dass mir einige Überlegungen fehlen, daher werde ich ein Problem damit behandeln. ⇒ DATAJDBC-175 ~~ ↓ 2018-03-08: Es ist jetzt möglich, andere Typen als Domänenklassen (sogenannte einfache Typen) wie Zahlen (int
,long
usw.) und boolesche Werte als Rückgabewerte zurückzugeben! !! Intern ...SingleColumnRowMapper
+ Die Auflösung des Spring-Datentyps wird in Zusammenarbeit mitConversionService
durchgeführt, das auf JDBC angewendet wird. Übrigens ist für diese Unterstützung Spring Framework 5.0.4.RELEASE oder höher erforderlich.
"Mechanismus zum Hinzufügen benutzerdefinierter Operationen (benutzerdefinierte Methoden)" in Spring Data Dieser Mechanismus kann auch in Spring Data JDBC verwendet werden.
Definieren Sie eine Schnittstelle zum Definieren benutzerdefinierter Operationen (benutzerdefinierte Methoden).
src/main/java/com/example/demo/repository/CustomizedTodoRepository.java
package com.example.demo.repository;
import com.example.demo.domain.Todo;
public interface CustomizedTodoRepository {
Iterable<Todo> findAllByFinished(boolean finished);
}
Erben Sie die erstellte Schnittstelle mit "Todo Repository".
src/main/java/com/example/demo/repository/TodoRepository.java
package com.example.demo.repository;
import org.springframework.data.repository.CrudRepository;
import com.example.demo.domain.Todo;
public interface TodoRepository extends CrudRepository<Todo, Integer>, CustomizedTodoRepository {
}
Erstellen Sie bei Verwendung von Spring JDBC die folgende Implementierungsklasse.
src/main/java/com/example/demo/repository/CustomizedTodoRepositoryImpl.java
package com.example.demo.repository;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import com.example.demo.domain.Todo;
public class CustomizedTodoRepositoryImpl implements CustomizedTodoRepository {
private static final RowMapper<Todo> ROW_MAPPER = new BeanPropertyRowMapper<>(Todo.class);
private final NamedParameterJdbcOperations namedParameterJdbcOperations;
public CustomizedTodoRepositorySpringJdbcImpl(NamedParameterJdbcOperations namedParameterJdbcOperations) {
this.namedParameterJdbcOperations = namedParameterJdbcOperations;
}
public Iterable<Todo> findAllByFinished(boolean finished) {
return this.namedParameterJdbcOperations.query(
"SELECT id, title, details, finished FROM todo WHERE finished = :finished ORDER BY id",
new MapSqlParameterSource("finished", finished), ROW_MAPPER);
}
}
Erstellen Sie bei Verwendung von MyBatis die folgende Implementierungsklasse.
src/main/java/com/example/demo/repository/CustomizedTodoRepositoryImpl.java
package com.example.demo.repository;
import org.apache.ibatis.session.SqlSession;
import com.example.demo.domain.Todo;
public class CustomizedTodoRepositoryImpl implements CustomizedTodoRepository {
private final String NAMESPACE = Todo.class.getName() + "Mapper";
private final SqlSession sqlSession;
public CustomizedTodoRepositoryMyBatisImpl(SqlSession sqlSession) {
this.sqlSession = sqlSession;
}
public Iterable<Todo> findAllByFinished(boolean finished) {
return this.sqlSession.selectList(NAMESPACE + ".findAllByFinished", finished);
}
}
Fügen Sie auch die SQL-Definition hinzu.
src/main/resources/com/example/demo/mapper/TodoMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.domain.TodoMapper">
<!-- ... -->
<!-- statements for custom repository method -->
<select id="findAllByFinished" resultType="Todo">
SELECT
id, title, details, finished
FROM
todo
WHERE
finished = #{finished}
ORDER BY
id
</select>
</mapper>
Spring Data JDBC unterstützt Persistenzoperationen für verwandte Objekte mit einer 1: 1- oder 1: N-Beziehung. Der Supportstatus unterscheidet sich jedoch zwischen der Spring JDBC-Implementierung und der MyBatis-Implementierung. Wenn Sie einen kurzen Blick darauf werfen ... Der Support-Status für Update-Vorgänge ist der gleiche. Für den Betrieb des Referenzsystems bei Verwendung von MyBatis ist jedoch eine Implementierung auf der MyBatis-Seite (Tabellenverknüpfung + 1: 1/1: N-Zuordnung unter Verwendung von Zuordnung und Sammlung) erforderlich.
Erstellen Sie eine Tabelle, um verwandte Objekte beizubehalten.
src/main/resources/schema.sql
CREATE TABLE IF NOT EXISTS activity (
id IDENTITY
,todo INTEGER NOT NULL --Spalte, in der die ID des Domänenobjekts gespeichert ist
,todo_key INTEGER NOT NULL --Spalte, in der der Identifikationsschlüssel (und der Sortierschlüssel) verwandter Objekte im Domänenobjekt gespeichert sind
,content TEXT NOT NULL
,at TIMESTAMP NOT NULL
);
In der Standardimplementierung von Spring Data JDBC lautet der Spaltenname "Spalte, in der die ID des Domänenobjekts gespeichert ist" "Klassenname des Domänenobjekts" und der Spaltenname "Spalte, in der der Identifikationsschlüssel des zugehörigen Objekts im Domänenobjekt gespeichert ist" Es wird zu "Spalte, in der die ID des Domänenobjekts +" _key "" gespeichert ist.
Erstellen Sie ein Domänenobjekt, das die Aktivität von TODO darstellt, und ordnen Sie es dem Todo-Objekt zu.
src/main/java/com/example/demo/domain/Activity.java
package com.example.demo.domain;
import org.springframework.data.annotation.Id;
import java.time.LocalDateTime;
public class Activity {
@Id
private int id;
private String content;
private LocalDateTime at;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public LocalDateTime getAt() {
return at;
}
public void setAt(LocalDateTime at) {
this.at = at;
}
}
src/main/java/com/example/demo/domain/Todo.java
public class Todo {
// ...
private List<Activity> activities;
// ...
public List<Activity> getActivities() {
return activities;
}
public void setActivities(List<Activity> activities) {
this.activities = activities;
}
}
Hier wird das Domänenobjekt, das das zugehörige Objekt mit einer 1: N-Beziehung enthält, unter Verwendung der in "CrudRepository" definierten Methode betrieben.
Beispiel für die Ausführung einer CRUD-Operation
@Test
public void oneToMany() {
// Insert
Todo newTodo = new Todo();
newTodo.setTitle("Trinkparty");
newTodo.setDetails("Ginza 19:00");
Activity activity1 = new Activity();
activity1.setContent("Created");
activity1.setAt(LocalDateTime.now());
Activity activity2 = new Activity();
activity2.setContent("Started");
activity2.setAt(LocalDateTime.now());
newTodo.setActivities(Arrays.asList(activity1, activity2));
todoRepository.save(newTodo);
// Assert for inserting
Optional<Todo> loadedTodo = todoRepository.findById(newTodo.getId());
Assertions.assertThat(loadedTodo.isPresent()).isTrue();
loadedTodo.ifPresent(todo -> {
Assertions.assertThat(todo.getId()).isEqualTo(newTodo.getId());
Assertions.assertThat(todo.getTitle()).isEqualTo(newTodo.getTitle());
Assertions.assertThat(todo.getDetails()).isEqualTo(newTodo.getDetails());
Assertions.assertThat(todo.isFinished()).isFalse();
Assertions.assertThat(todo.getActivities()).hasSize(2);
Assertions.assertThat(todo.getActivities().get(0).getContent()).isEqualTo(activity1.getContent());
Assertions.assertThat(todo.getActivities().get(1).getContent()).isEqualTo(activity2.getContent());
});
// Update
Activity activity3 = new Activity();
activity3.setContent("Changed Title");
activity3.setAt(LocalDateTime.now());
loadedTodo.ifPresent(todo -> {
todo.setTitle("[Change] " + todo.getTitle());
todo.getActivities().add(activity3);
});
todoRepository.save(loadedTodo.get());
// Assert for updating
loadedTodo = todoRepository.findById(newTodo.getId());
Assertions.assertThat(loadedTodo.isPresent()).isTrue();
loadedTodo.ifPresent(todo -> {
Assertions.assertThat(todo.getTitle()).isEqualTo("[Change] " + newTodo.getTitle());
Assertions.assertThat(todo.getActivities()).hasSize(3);
Assertions.assertThat(todo.getActivities().get(0).getContent()).isEqualTo(activity1.getContent());
Assertions.assertThat(todo.getActivities().get(1).getContent()).isEqualTo(activity2.getContent());
Assertions.assertThat(todo.getActivities().get(2).getContent()).isEqualTo(activity3.getContent());
});
// Delete
todoRepository.deleteById(newTodo.getId());
// Assert for deleting
Assertions.assertThat(todoRepository.findById(newTodo.getId())).isNotPresent();
}
Wenn Sie die Spring JDBC-Implementierung verwenden, müssen Sie nichts tun. Wenn Sie einfach die CrudRepository-Methode aufrufen, generiert Spring Data JDBC SQL und führt es aus.
Wenn Sie die MyBatis-Implementierung verwenden, müssen Sie SQL in der Mapper-XML-Datei definieren.
Erstens ... Definieren Sie die SQL zum Einfügen verwandter Objekte.
src/main/resources/com/example/demo/mapper/ActivityMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.domain.ActivityMapper">
<insert id="insert" useGeneratedKeys="true" keyProperty="instance.id">
INSERT INTO activity
(todo, todo_key, content, at)
VALUES
(#{additonalValues.Todo}, #{additonalValues.Todo_key}, #{instance.content}, #{instance.at})
</insert>
</mapper>
Der Punkt hier ist, dass die "ID des Domänenobjekts" und der "Identifikationsschlüssel (und Sortierschlüssel) des zugehörigen Objekts im Domänenobjekt" in der Eigenschaft "additonalValues" vom Typ "Map" gespeichert sind. , Der Schlüsselname, in dem der Wert gespeichert ist, entspricht der Regel des Spaltennamens.
Weiter ... Definieren Sie SQL für DELETE-bezogene Objekte. Diese SQL wird auch beim Aktualisieren eines Domänenobjekts aufgerufen. Mit anderen Worten ... Alle verwandten Objekte mit einer 1: N-Beziehung werden GELÖSCHT und dann erneut EINFÜGEN.
src/main/resources/com/example/demo/mapper/TodoMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.domain.TodoMapper">
<!-- ... -->
<delete id="delete-activities">
DELETE FROM activity WHERE todo = #{id}
</delete>
<delete id="deleteAll-activities">
DELETE FROM activity WHERE todo = #{id}
</delete>
<!-- ... -->
</mapper>
Schließlich ... Ändern, um verwandte Objekte in der SQL abzurufen, die auf das Domänenobjekt verweisen. Insbesondere ... Verbinden Sie die Tabellen, die die Informationen zu verwandten Objekten enthalten, und ordnen Sie die zugehörigen Objekte mithilfe der ResultMap-Funktion von MyBatis Domänenobjekten zu.
src/main/resources/com/example/demo/mapper/TodoMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.domain.ActivityMapper">
<!-- ... -->
<select id="findById" resultMap="todoMap">
SELECT
t.id, t.title, t.details, t.finished
, a.id as activity_id, a.content as activity_content, a.at as activity_at
FROM
todo t
LEFT OUTER JOIN activity a ON a.todo = t.id
WHERE
t.id = #{id}
ORDER BY
a.todo_key
</select>
<resultMap id="todoMap" type="Todo">
<id column="id" property="id"/>
<result column="title" property="title"/>
<result column="details" property="details"/>
<result column="finished" property="finished"/>
<collection property="activities" columnPrefix="activity_" ofType="Activity">
<id column="id" property="id"/>
<result column="content" property="content"/>
<result column="at" property="at"/>
</collection>
</resultMap>
<!-- ... -->
</mapper>
Wenn Ihnen die von der Standardimplementierung von Spring Data JDBC generierten Spaltennamen nicht gefallen ... Sie können sie ändern, indem Sie die Implementierungsklasse von "NamingStrategy" als Bean definieren. Hier werden wir vorstellen, wie man "Todo" in "todo_id" und "Todo_key" in den Spaltennamen "sort_order" ändert.
Zuerst ... Ändern Sie den Spaltennamen der Tabelle.
src/main/resources/schema.sql
CREATE TABLE IF NOT EXISTS activity (
id IDENTITY
,todo_id INTEGER NOT NULL --Spaltennamen ändern
,sort_order INTEGER NOT NULL --Spaltennamen ändern
,content TEXT NOT NULL
,at TIMESTAMP NOT NULL
);
Weiter ... Bean-Definition der Implementierungsklasse von NamingStrategy
.
@Bean
NamingStrategy namingStrategy() {
return new NamingStrategy(){
@Override
public String getReverseColumnName(RelationalPersistentProperty property) {
return NamingStrategy.super.getReverseColumnName(property).toLowerCase() + "_id";
}
@Override
public String getKeyColumn(RelationalPersistentProperty property) {
return "sort_order";
}
};
}
Wenn Sie die MyBatis-Implementierung verwenden, müssen Sie auch die SQL ändern.
src/main/resources/com/example/demo/mapper/ActivityMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.domain.ActivityMapper">
<insert id="insert" useGeneratedKeys="true" keyProperty="instance.id">
INSERT INTO activity
(todo_id, sort_order, content, at)
VALUES
(#{additonalValues.todo_id}, #{additonalValues.sort_order}, #{instance.content}, #{instance.at})
</insert>
</mapper>
src/main/resources/com/example/demo/mapper/TodoMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.domain.ActivityMapper">
<!-- ... -->
<delete id="delete-activities">
DELETE FROM activity WHERE todo_id = #{id}
</delete>
<delete id="deleteAll-activities">
DELETE FROM activity WHERE todo_id = #{id}
</delete>
<!-- ... -->
<select id="findById" resultMap="todoMap">
SELECT
t.id, t.title, t.details, t.finished
, a.id as activity_id, a.content as activity_content, a.at as activity_at
FROM
todo t
LEFT OUTER JOIN activity a ON a.todo_id = t.id
WHERE
t.id = #{id}
ORDER BY
a.sort_order
</select>
<!-- ... -->
</mapper>
In Spring Data "Mechanismus zum Festlegen von Werten in der Spalte (Prüfspalte), die enthält, wann, wer und wann und aktualisierte (zuletzt aktualisierte) Daten -data / commons / docs / 2.1.0.RELEASE / reference / html / # auditing), und diese Funktion kann auch mit Spring Data JDBC verwendet werden.
IMPORTANT:
Zum Zeitpunkt von Spring Data JDBC 1.0.0.RELEASE (Lovelace) gibt es einen Teil, in dem die Überwachungsfunktion für verschachtelte Objekte (1: 1, 1: N) nicht unterstützt werden kann. Dies scheint auf der Seite von Spring Data Commons ein Problem zu sein, nicht auf der Seite von Spring Data JDBC.
- [DATACMNS-1297] (https://jira.spring.io/projects/DATACMNS/issues/DATACMNS-1297): Ein Fehler tritt immer dann auf, wenn die Audit-Eigenschaft in der Klasse auf der N-Seite mit einer 1: N-Beziehung (Daten) vorhanden ist. Wird zu einem Fehler führen, auch wenn 0 Fälle vorliegen)
- [DATACMNS-1296] (https://jira.spring.io/projects/DATACMNS/issues/DATACMNS-1296) : Ein Fehler tritt auf, wenn das Objekt selbst "null" ist, wenn die Eigenschaft für die Überwachung in der verschachtelten Klasse vorhanden ist.
Um die Überwachungsfunktion zu verwenden, fügen Sie der Konfigurationsklasse "@ org.springframework.data.jdbc.repository.config.EnableJdbcAuditing" hinzu.
@EnableJdbcAuditing //hinzufügen
@Import(JdbcConfiguration.class)
@EnableJdbcRepositories
@Configuration
public class SpringDataJdbcConfig {
// ...
}
Eine Klasse, die die Schnittstelle org.springframework.data.domain.AuditorAware
implementiert, wenn Sie aufzeichnen möchten, wer sie erstellt und aktualisiert hat.
package com.example.demo;
import org.springframework.data.domain.AuditorAware;
import java.util.Optional;
public class MyAuditorAware implements AuditorAware<String> {
static ThreadLocal<String> currentUser = ThreadLocal.withInitial(() -> "default");
public Optional<String> getCurrentAuditor() {
return Optional.ofNullable(currentUser.get());
}
}
NOTE:
Hier wird der in der threadlokalen Variablen festgelegte Benutzername einfach als Ersteller / letzter Aktualisierer der Daten zurückgegeben, jedoch bei der Entwicklung einer tatsächlichen Anwendung, Spring Security usw. Es ist üblich, den von der Authentifizierungsfunktion von verwalteten Login-Benutzernamen zurückzugeben.
Und registrieren Sie es im Anwendungskontext.
@EnableJdbcAuditing
@Import(JdbcConfiguration.class)
@EnableJdbcRepositories
@Configuration
public class SpringDataJdbcConfig {
// ...
@Bean
AuditorAware<String> auditorAware() {
return new MyAuditorAware();
}
// ...
}
Wenn Sie die Zeiterfassungsmethode "Wann" gegenüber der Standardimplementierung ändern möchten ("CurrentDateTimeProvider" = "LocalDateTime.now ()"), wenden Sie ein Objekt an, das die Schnittstelle "org.springframework.data.auditing.DateTimeProvider" implementiert. Geben Sie die BeanID des Objekts an, das im Kontext registriert und im Attribut dateTimeProviderRef
von @ EnableJdbcAuditing
registriert ist.
@EnableJdbcAuditing(dateTimeProviderRef = "dateTimeProvider")
@Import(JdbcConfiguration.class)
@EnableJdbcRepositories
@Configuration
public class SpringDataJdbcConfig {
// ...
@Bean
DateTimeProvider dateTimeProvider(ObjectProvider<Clock> clockObjectProvider) {
return () -> Optional.of(LocalDateTime.now(clockObjectProvider.getIfAvailable(Clock::systemDefaultZone)));
}
// ...
}
Fügen Sie nach dem Aktivieren der Überwachungsfunktion zunächst eine Überwachungsspalte zur Tabelle hinzu.
CREATE TABLE IF NOT EXISTS todo (
id IDENTITY
,title TEXT NOT NULL
,details TEXT
,finished BOOLEAN NOT NULL
,created_at TIMESTAMP
,created_by VARCHAR(64)
,last_updated_at TIMESTAMP
,last_updated_by VARCHAR(64)
);
Ab Spring Data JDBC 1.0.0.RELEASE (Lovelace) wird Annotation-based Auditing Function unterstützt. .RELEASE / reference / html / # auditing.annotations )nur.
Wenn Sie die auf Anmerkungen basierende Überwachungsfunktion verwenden, fügen Sie dem Wert der Überwachungsspalte eine Eigenschaft hinzu und fügen Sie der Zielspalte die folgende Anmerkung hinzu.
@CreatedDate
@CreatedBy
@LastModifiedDate
@LastModifiedBy
~~WARNING:~~
~~ Ab Spring Data JDBC 1.0 M3 (Lovelace) funktioniert es nicht richtig, wenn der Typ der Eigenschaft mit
@ Id
ein Grundelement ist. (DATAJDBC-216) ~~ -> 2018-05-18 Unterstützt: grinsen:
package com.example.demo.domain;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.relational.core.mapping.Column;
import java.time.LocalDateTime;
import java.util.List;
public class Todo {
@Id
private int id;
private String title;
private String details;
private boolean finished;
//Erstellungsdatum und -zeit
@CreatedDate
@Column("created_at")
private LocalDateTime createdAt;
//Autor
@CreatedBy
@Column("created_by")
private String createdBy;
//Zuletzt geändert
@LastModifiedDate
@Column("last_updated_at")
private LocalDateTime lastUpdatedAt;
//Zuletzt aktualisiert
@LastModifiedBy
@Column("last_updated_by")
private String lastUpdatedBy;
private List<Activity> activities;
// setters/getters
}
NOTE:
Obwohl nicht mit der Überwachungsfunktion verwandt, ist "@ Column" eine Anmerkung, die nach der Veröffentlichung von Spring Data JDBC 1.0 M3 (Lovelace) (DATAJDBC-106 unterstützt wird. DATA JDBC-106)). ~~ Übrigens, wenn es bestimmte Regeln gibt, wie z. B. die Zuordnung zwischen Schlangenfallspalten und Kamelfall-Eigenschaftsnamen, können Sie
NamingStrategy
verwenden, um den Unterschied in den Namen zu absorbieren. ~~ (→ DATAJDBC-206 Mit der Unterstützung wird die Zuordnung zwischen dem Namen der Schlangenfallspalte und dem Namen der Kamelfall-Eigenschaft zur Standardoperation. wurde)
Die schnittstellenbasierte Überwachungsfunktion wird ab Spring Data JDBC 1.0.0.RELEASE (Lovelace) nicht unterstützt. Dies liegt daran, dass Spring Data JDBC die Option "Optional" (DATAJDBC-205) noch nicht unterstützt.
Vorerst ... Es scheint spring-data-jdbc-boot-Starter im persönlichen Repository des Entwicklers zu geben. Es wird zu diesem Zeitpunkt nirgendwo bereitgestellt, daher müssen Sie es in Ihrem lokalen Repository installieren und verwenden. (Ich habe es diesmal vorerst nicht benutzt) ↓ Spring Boot 2.1 (2.1.0.M4) bietet AutoConfigure und Starter!
NOTE:
Ich schrieb "Try spring-boot-Starter-Daten-jdbc (2.1.0.BUILD-SNAPSHOT)".
Ich denke, es ist eine Bibliothek, die sich noch entwickelt und wächst, deshalb möchte ich die Trends im Auge behalten. Ich halte es für sehr praktisch, wenn Sie benutzerdefinierte Methoden in der Repository-Oberfläche definieren und SQL mit Anmerkungen angeben können (in Bezug auf README scheint es einen Plan zu geben, dies zu unterstützen ⇒ unterstützt !!). Und es wäre großartig, wenn die Zusammenarbeit mit Spring Data REST unterstützt würde. ↓ Endlich wurde 1.0.0 offiziell veröffentlicht! !! Es ist immer noch eine sich entwickelnde Bibliothek, aber ich denke, sie ist im Vergleich zu dem Zeitpunkt, als ich diesen Eintrag schrieb (2018/01/08), sehr gewachsen. [Spring Data REST-Referenz (Spring Data REST 3.1.0.RELEASE)](https://docs.spring.io/spring-data/rest/docs/3.1.0.RELEASE/reference/html/#getting-started In Bezug auf .bootstrap) scheint der offizielle Support noch nicht verfügbar zu sein (ich gebe Ihnen ein Problem ...).
Recommended Posts