Einführung in Spring Data JDBC

In der kommenden Spring Data-Version mit dem Codenamen Lovelace werden wir ein neues Modul aufnehmen: Spring Data JDBC .


Die Idee hinter Spring Data JDBC ist es, den Zugriff auf relationale Datenbanken zu ermöglichen, ohne die Komplexität von JPA zu nutzen .


JPA bietet Funktionen wie verzögertes Laden , Zwischenspeichern und Änderungsverfolgung (Dirty Tracking). Trotz der Tatsache, dass diese Funktionen sehr cool sind, können sie das Verständnis der Logik des Datenzugriffs erheblich erschweren, wenn Sie sie wirklich benötigen.


Der Mechanismus des verzögerten Ladens kann plötzlich ressourcenintensive Anforderungen ausführen oder mit einer Ausnahme sogar fehlschlagen. Das Caching kann Ihnen im Weg stehen, wenn Sie zwei Versionen einer Entität vergleichen. In Verbindung mit der Nachverfolgung von Änderungen ist es schwieriger zu verstehen, zu welchem ​​Zeitpunkt alle Datenbankoperationen tatsächlich ausgeführt werden.


Spring Data JDBC konzentriert sich auf ein viel einfacheres Modell . Es erfolgt kein Caching, Änderungsverfolgung oder verzögertes Laden. Stattdessen werden SQL-Abfragen genau dann ausgeführt, wenn Sie die Repository-Methode aufrufen. Das zurückgegebene Ergebnis wird nach Ausführung der Methode vollständig in den Speicher geladen. Es gibt keinen "Sitzungs" -Mechanismus oder Proxy-Objekte für Entitäten. All dies sollte Spring Data JDBC zu einem einfacheren und intuitiveren Tool für den Zugriff auf Daten machen.


Ein derart vereinfachter Ansatz führt natürlich zu einer Reihe von Einschränkungen, die wir in den nächsten Beiträgen erörtern werden. Die kommende Version ist die allererste Version der Bibliothek. Wir haben viele Pläne und Ideen, die wir implementieren möchten, aber wir müssen sie verschieben, damit Sie die Möglichkeit haben, Spring Data JDBC so früh wie möglich zu verwenden.


Beispiel


Um zu beginnen, müssen wir die Entität definieren:


class Customer { @Id Long id; String firstName; LocalDate dob; } 

Bitte beachten Sie, dass wir weder Getter noch Setter definieren. Natürlich können Sie sie hinzufügen, wenn Sie möchten. Im Wesentlichen besteht die einzige Voraussetzung für eine Entität darin, dass das Feld mit einer org.springframework.data.annotation.Id Annotation versehen wird (jedoch org.springframework.data.annotation.Id , nicht javax.persistence one ).

Als nächstes müssen Sie das Repository definieren. Der einfachste Weg, dies zu tun, besteht darin, die CrudRepository Schnittstelle zu erweitern.


 interface CustomerRepository extends CrudRepository<Customer, Long> {} 

Schließlich müssen Sie ApplicationContext so konfigurieren, dass die Implementierung dieser Schnittstelle automatisch erstellt wird:


 @Configuration @EnableJdbcRepositories (1) public class CustomerConfig extends JdbcConfiguration { (2) @Bean NamedParameterJdbcOperations operations() { (3) return new NamedParameterJdbcTemplate(dataSource()); } @Bean PlatformTransactionManager transactionManager() { (4) return new DataSourceTransactionManager(dataSource()); } @Bean DataSource dataSource(){ (5) return new EmbeddedDatabaseBuilder() .generateUniqueName(true) .setType(EmbeddedDatabaseType.HSQL) .addScript("create-customer-schema.sql") .build(); } } 

Lassen Sie uns die Konfiguration genauer analysieren.


  1. EnableJdbcRepositories automatische Repository-Erstellung. Damit dies funktioniert, müssen Sie mehrere zusätzliche Beans bereitstellen, für die der Rest unserer Konfigurationsklasse erforderlich ist.
  2. Weil Die Konfigurationsklasse erweitert JdbcConfiguration . Mehrere Beans werden automatisch zum Kontext hinzugefügt. Sie können sie auch überlappen, wenn Sie das Verhalten von Spring Data JDBC ändern müssen. In diesem Beispiel wird jedoch das Standardverhalten beibehalten.
  3. Eine sehr wichtige Komponente ist NamedParameterJdbcOperations , mit der Datenbankabfragen ausgeführt werden.
  4. Ein Transaktionsmanager ist streng genommen nicht erforderlich. Aber ohne sie wird es keine Transaktionsunterstützung geben, und nur wenige werden es mögen, oder?
  5. Spring Data JDBC verwendet die DataSource direkt, aber der TransactionManager und NamedParameterJdbcOperation erfordern ihre Anwesenheit im Kontext, weshalb wir die gewünschte Bean bestimmen.

Das ist alles, was Sie brauchen, um mit Spring Data JDBC zu beginnen. Schreiben Sie nun einen Test, um zu sehen, wie alles funktioniert:


 @RunWith(SpringRunner.class) @Transactional @ContextConfiguration(classes = CustomerConfig.class) public class CustomerRepositoryTest { @Autowired CustomerRepository customerRepo; @Test public void createSimpleCustomer() { Customer customer = new Customer(); customer.dob = LocalDate.of(1904, 5, 14); customer.firstName = "Albert"; Customer saved = customerRepo.save(customer); assertThat(saved.id).isNotNull(); saved.firstName = "Hans Albert"; customerRepo.save(saved); Optional<Customer> reloaded = customerRepo.findById(saved.id); assertThat(reloaded).isNotEmpty(); assertThat(reloaded.get().firstName).isEqualTo("Hans Albert"); } } 

@Query


Nur mit Standard-CRUD-Methoden können Sie sich weit vom CrudRepository Klassenrepository CrudRepository . Wir haben uns bewusst dafür entschieden, die automatische Generierung von Abfragen - eine beliebte Funktion von Spring Data, wenn SQL-Abfragen basierend auf dem Methodennamen generiert werden - für zukünftige Versionen zu verschieben. Im @Query können Sie einfach die bekannte Annotation @Query , um genau anzugeben, welche SQL-Abfrage ausgeführt werden soll.


 @Query("select id, first_name, dob from customer where upper(first_name) like '%' || upper(:name) || '%' ") List<Customer> findByName(@Param("name") String name); 

Wenn Sie Daten in der Anforderung ändern oder löschen möchten, können Sie der @Modifying Annotation @Modifying hinzufügen.


Schreiben wir einen Test, um zu sehen, wie unsere neue Methode funktioniert.


 @Test public void findByName() { Customer customer = new Customer(); customer.dob = LocalDate.of(1904, 5, 14); customer.firstName = "Albert"; Customer saved = customerRepo.save(customer); assertThat(saved.id).isNotNull(); customer.id= null; (1) customer.firstName = "Bertram"; customerRepo.save(customer); customer.id= null; customer.firstName = "Beth"; customerRepo.save(customer); assertThat(customerRepo.findByName("bert")).hasSize(2); (2) } 

  1. Weil Da die Verbindung zwischen Java-Objekten und dem Datensatz in der Datenbank nur nach Feld und Typ der Id , wird durch Setzen der Id auf null und Speichern dieses Objekts ein neuer Datensatz erstellt.
  2. In der Anfrage verwenden wir Groß- und Kleinschreibung und finden daher "Albert" und "Bertram", aber nicht "Beth".

Abschließend


Natürlich kann noch viel mehr über Spring Data JDBC gesagt werden, und wir werden es Ihnen sicherlich in zukünftigen Artikeln erzählen.


In der Zwischenzeit können Sie den Beispielcode , die Dokumentation und natürlich den Quellcode studieren. Wenn Sie Fragen haben, können Sie diese gerne auf StackOverflow stellen . Und wenn Sie einen Fehler finden oder eine neue Funktion anfordern möchten, erstellen Sie bitte ein Ticket .

Source: https://habr.com/ru/post/de423697/


All Articles