sql >> Databáze >  >> RDS >> Database

Práce s JDBC a Spring

Ve scénáři aplikace v reálném světě se velké množství zpracování provádí na backendovém serveru, kde se data skutečně zpracovávají a uchovávají v úložišti. Kromě mnoha prominentních funkcí Spring, jako je DI (Dependency Injection), Aspects a vývoj orientovaný na POJO, má Spring vynikající podporu pro práci s daty. Existují různé způsoby, jak psát dobré databázové aplikace. I dnes je velké množství aplikací napsáno na základě schopnosti přístupu k datům JDBC. Tento článek se konkrétně zabývá JDBC ve spojení se Spring, jeho podporou a výhodami a nevýhodami s vhodnými příklady a úryvky kódu.

Přehled JDBC

Jednou z největších výhod stále používání JDBC ve světě ORM je to, že kromě práce s daty na mnohem nižší úrovni nevyžaduje zvládnutí dotazovacího jazyka jiného rámce. Umožňuje programátorovi využít proprietární funkce databáze. Má to i své nevýhody. Nevýhody jsou bohužel často tak viditelné, že nepotřebují zmínku. Jedním z nich je například kód kotelny . Termín kód kotelny v podstatě znamená psát stejný kód znovu a znovu bez začlenění jakékoli hodnoty do kódu. To lze obvykle vidět, když se dotazujeme na data z databáze; například v následujícím kódu jednoduše načteme Uživatele záznam z databáze.

public User getUserById(long id) {
   User user = null;
   Connection con = null;
   PreparedStatement pstmt = null;
   ResultSet rs = null;
   try {
      con = dataSource.getConnection();
      pstmt = con.prepareStatement("select * from "
         + "user_table where userid=?");
      pstmt.setInt(1, id);
      rs.pstmt.executeQuery();
      if (rs.next()) {
         user = new User();
         user.setId(rs.getInt("userid"));
         user.setFullName(rs.getString("fullname"));
         user.setUserType(rs.getString("usertype"));
         user.setPassword(rs.getString("password"));
      }
   } catch (SQLException ex1) {}
   finally {
      try {
         if (rs != null)
         rs.close();
         if (pstmt != null)
            rs.close();
         if (con != null)
            rs.close();
      } catch (SQLException ex2) {}
   }
   return user;
}

Všimněte si, že pokaždé, když potřebujeme interagovat s databází, musíme vytvořit tři objekty – spojení (Connection ), prohlášení (PreparedStatement ) a sada výsledků (Sada výsledků ). Všechny tyto musí být také uzavřeny v rámci uloženého zkusit…chytit blok. Dokonce i uzavření připojení musí být uzavřeno v rámci try…catch . To je směšné, protože skutečný požadovaný kód pro funkci je mnohem menší. Kód je jednoduše nafouknutý zbytečným, ale povinným kódem a musí se opakovat všude, kde pracujeme s databází. Chytré schéma kódování může tento nepořádek omezit, přesto je nemožné vymýtit problém standardního kódu JDBC. To není jen problém JDBC, ale také JMS, JNDI a REST.

Jarní řešení

Framework Spring poskytl řešení tohoto nepořádku a poskytl prostředek k odstranění standardního kódu pomocí tříd šablon. Tyto třídy zapouzdřují standardní kód, čímž ulehčují programátorovi. To znamená, že standardní kód je tam stále, pouze programátor, který používá některou z tříd šablon, je zbaven problémů s jeho psaním. JdbcTemplate poskytovaná Springem je ústřední třídou základního balíčku JDBC.

Zjednodušuje používání JDBC a pomáhá vyhnout se běžným chybám. Provádí základní pracovní tok JDBC a ponechává aplikační kód, aby poskytoval SQL a extrahoval výsledky. Tato třída provádí dotazy nebo aktualizace SQL, zahajuje iteraci přes ResultSets a zachycuje výjimky JDBC a převádí je do obecné, informativnější hierarchie výjimek definované v org.springframework.dao balíček.

Potřebujeme implementovat pouze rozhraní zpětného volání a dát jim jasnou, definovanou smlouvu. Například PreparedStatementCreator callback rozhraní slouží k vytvoření připraveného výpisu. Nástroj ResultsetExtractor rozhraní funguje jako Sada výsledků .

Proto může být předchozí fragment kódu přepsán pomocí JdbcTemplate takto:

@Autowired
private JdbcTemplate jdbcTemplate;
public User getUserById(long id) {
   return jdbcTemplate.queryForObject(
      "select * from user_table where userid=?",
      new UserRowMapper(),id);
   }
class UserRowMapper implements RowMapper<User>{
   @Override
   public User mapRow(ResultSet rs, int runNumber)
         throws SQLException {
      User user=new User();
      user.setId(rs.getInt("userid"));
      user.setFullName(rs.getString("fullname"));
      user.setUserType(rs.getString("usertype"));
      user.setPassword(rs.getString("password"));
      return user;
   }
}

RowMapper je rozhraní, které obvykle používá JdbcTemplate k mapování jednoho řádku na základ řádků Sada výsledků . RowMapper objekty jsou bezstavové, a proto znovu použitelné. Jsou ideální pro implementaci jakékoli logiky mapování řádků. Všimněte si, že v předchozím kódu jsme nezpracovali výjimky explicitně, jako jsme to udělali v kódu, který nepoužívá JdbcTemplate . Implementace RowMapper provádí skutečnou implementaci mapování každého řádku na výsledný objekt, aniž by se programátor musel starat o zpracování výjimek. Bude volána a zpracovávána voláním JdbcTemplate .

Výjimky

Výjimky poskytované JDBC jsou často příliš impozantní, než je nutné, s malou hodnotou. Hierarchie výjimek pro přístup k datům Spring je v tomto ohledu efektivnější a rozumnější. To znamená, že má ve svém arzenálu konzistentní sadu tříd výjimek na rozdíl od JDBC jedné velikosti vhodné pro všechny výjimky zvané SQLException pro všechny problémy související s přístupem k datům. Výjimky přístupu k datům Spring jsou zakořeněné pomocí DataAccessException třída. Proto můžeme mít do frameworku zakořeněnou jak volbu zaškrtnuté, tak nezaškrtnuté výjimky. To zní praktičtěji, protože na mnoho problémů, které se vyskytly během běhového přístupu k datům, skutečně neexistují žádná řešení a je zbytečné je chytat, když nemůžeme situaci řešit vhodnou alternativou.

Jarní způsob zjednodušení přístupu k datům

Spring ve skutečnosti dělá to, že rozlišuje pevnou a variabilní část mechanismu přístupu k datům do dvou sad tříd nazývaných template class a třídy zpětného volání , resp. Pevná část kódu představuje povrchní část přístupu k datům a proměnná část je způsob přístupu k datům, který se mění podle měnících se požadavků.

Stručně řečeno, třídy šablon rukojeť:

  • Kontrola transakcí
  • Správa zdrojů
  • Zpracování výjimek

A třídy zpětného volání rukojeť:

  • Vytvoření dotazu
  • Vazba parametrů
  • Řazení sady výsledků

Můžeme si vybrat jednu z mnoha tříd šablon podle výběru použité persistentní technologie. Například pro JDBC můžeme zvolit JdbcTemplate , nebo pro ORM můžeme zvolit JpaTemplate , HibernateTemplate , a tak dále.

Nyní, když se připojujeme k databázi, máme tři možnosti konfigurace zdroje dat, například:

  • Definováno ovladačem JDBC
  • Vyhledal JNDI
  • Načteno z fondu připojení

Aplikace připravená k produkci obvykle používá fond připojení nebo rozhraní JNDI. Zdroje dat definované ovladačem JDBC jsou zdaleka nejjednodušší, i když se většinou používají pro testovací účely. Spring nabízí tři třídy v balíčku org.springframework.jdbc.datasource této kategorie; jsou:

  • DriverManagerDataSource: Jednoduchá implementace standardního JDBC DataSource rozhraní, konfigurace prostého starého JDBC DriverManager přes vlastnosti bean a vrací nové Připojení z každé žádosti.
  • SingleConnectionDataSource: Vrátí stejné připojení na každý požadavek. Tento typ připojení je primárně určen pro testování.
  • SimpleDriverDataSource: Stejné jako DriverManagerDataSource kromě toho, že má problémy s načítáním speciální třídy, jako je OSGi; tato třída přímo pracuje s ovladačem JDBC.

Konfigurace těchto zdrojů dat je podobná. Můžeme je nakonfigurovat ve třídě bean nebo pomocí XML.

// Configuring MySQL data source
@Bean
public DataSource dataSource() {
   DriverManagerDataSource ds=new DriverManagerDataSource();
   ds.setDriverClassName("com.mysql.jdbc.Driver");
   ds.setUrl("jdbc:mysql://localhost:3306/testdb");
   ds.setUsername("root");
   ds.setPassword("secret");
   return ds;
}

<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p_driverClassName="com.mysql.jdbc.Driver"
p_url="jdbc:mysql://localhost:3306/testdb"
p_username="root"
p_password="secret"/>

Třídy šablon JDBC

Spring nabízí několik tříd šablon pro zjednodušení přístupu k datům pomocí JDBC:

  • JdbcTemplate: Toto je základní třída základního balíčku JDBC org.springframework.jdbc.core který poskytuje nejjednodušší přístup k databázi prostřednictvím indexovaných dotazů.
  • NamedParameterJdbcTemplate: Tato třída šablon také poskytuje základní sadu operací JDBC, kde jsou hodnoty svázány s pojmenovanými parametry spíše než s tradičními zástupnými symboly ‚?‘ v dotazech SQL.

Třídy zpětného volání JDBC

Klíčová funkční rozhraní zpětného volání JDBC definovaná v org.springframework.jdbc.core jsou:

  • CallableStatementCallback: Funguje na JDBC CallableStatement. Toto zpětné volání používá interně JdbcTemplate a umožňuje provedení na jediném CallableStatement jako jeden nebo více SQL provádějí volání s různými parametry.
  • PreparedStatementCallback: Funguje na JDBC PreparedStatement. Toto zpětné volání interně používá JdbcTemplate a umožňuje provedení více než jedné operace na jednom PreparedStatement jako je jedno nebo více volání SQL executeUpdate s různými parametry.
  • StatementCallback: Funguje na Prohlášení JDBC . Toto zpětné volání také používá interně JdbcTemplate k provedení více než jedné operace na jednom Příkazu jako jedno nebo více volání SQL executeUpdate.

Jednoduchý příklad JDBC Spring Boot

Zkusme jednoduchý příklad jarní botičky. Projekt Spring boot automaticky zvládá mnoho složitostí konfigurace, kdy je vývojář zbaven všech problémů, jakmile je do souboru Maven pom.xml zahrnuta správná závislost. . Aby byl článek krátký, nebudeme uvádět vysvětlivky kódů. Pro podrobnější popis použijte prosím odkazy uvedené na konci článku.

Chcete-li pracovat na následujícím příkladu, vytvořte databázi a tabulku v MySQl následovně:

Přihlaste se do databáze MySQL a vytvořte databázi a tabulku pomocí následujícího příkazu:

CREATE DATABASE testdb;
USE testdb;
CREATE TABLE candidate(
   id INT UNSIGNED NOT NULL AUTO_INCREMENT,
   fullname VARCHAR(100) NOT NULL,
   email VARCHAR(100) NOT NULL,
   phone VARCHAR(10) NOT NULL,
   PRIMARY KEY(id)
);

Začněte jako projekt Spring Starter ze Spring Tool Suite (STS) se závislostí JDBC a MySQL. Konfigurační soubor Maven, pom.xml , projektu je následující:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
      xmlns_xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi_schemaLocation="http://maven.apache.org/POM/4.0.0
      http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.mano.springbootjdbc.demo</groupId>
   <artifactId>spring-boot-jdbc-demo</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>

   <name>spring-boot-jdbc-demo</name>
   <description>Demo project for Spring Boot
      jdbc</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>1.5.10.RELEASE</version>
      <relativePath/> <!-- Look up parent from repository -->
   </parent>

   <properties>
     <project.build.sourceEncoding>UTF-8
         </project.build.sourceEncoding>
     <project.reporting.outputEncoding>UTF-8
         </project.reporting.outputEncoding>
      <java.version>1.8</java.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-jdbc</artifactId>
      </dependency>

      <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <scope>runtime</scope>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>

   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-
               plugin</artifactId>
         </plugin>
      </plugins>
   </build>
</project>

Třída modelu:Candidate.java

package org.mano.springbootjdbc.demo.model;

public class Candidate {
   private int id;
   private String fullname;
   private String email;
   private String phone;

   public Candidate() {
      super();
   }

   public Candidate(int id, String fullname,
         String email, String phone) {
      super();
      setId(id);
      setFullname(fullname);
      setEmail(email);
      setPhone(phone);
   }

   public int getId() {
      return id;
   }

   public void setId(int id) {
      this.id = id;
   }

   public String getFullname() {
      return fullname;
   }

   public void setFullname(String fullname) {
      this.fullname = fullname;
   }

   public String getEmail() {
      return email;
   }

   public void setEmail(String email) {
      this.email = email;
   }

   public String getPhone() {
      return phone;
   }

   public void setPhone(String phone) {
      this.phone = phone;
   }

   @Override
   public String toString() {
      return "Candidate [id=" + id + ", fullname=" + fullname
         + ", email=" + email + ", phone=" + phone + "]";
   }

}

Rozhraní objektu pro přístup k datům:CandidateDao.java

package  org.mano.springbootjdbc.demo.dao;

import java.util.List;

import org.mano.springbootjdbc.demo.model.Candidate;

public interface CandidateDao {
   public void addCandidate(Candidate candidate);

   public void modifyCandidate(Candidate candidate,
      int candidateId);

   public void deleteCandidate(int candidateId);

   public Candidate find(int candidateId);

   public List<Candidate> findAll();
}

Třída implementace objektu pro přístup k datům:CandidateDaoImpl.java

package org.mano.springbootjdbc.demo.dao;

import java.util.ArrayList;
import java.util.List;

import org.mano.springbootjdbc.demo.model.Candidate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
@Qualifier("candidateDao")
public class CandidateDaoImpl implements CandidateDao {

   @Autowired
   JdbcTemplate jdbcTemplate;

   @Override
   public void addCandidate(Candidate candidate) {
      jdbcTemplate.update("insert into candidate
            (id,fullname,email,phone) "
            + "values (?,?,?,?)", candidate.getId(),
         candidate.getFullname(), candidate.getEmail(),
         candidate.getPhone());
      System.out.println(candidate+" is added successfully!");

   }

   @Override
   public void modifyCandidate(Candidate candidate, int
         candidateId) {
      jdbcTemplate.update("update candidate fullname=?,
         email=?,phone=? "
         + "where id=? values (?,?,?,?)",candidate.getFullname(),
      candidate.getEmail(), candidateId);
      System.out.println("Candidate with id="+candidateId+
         " modified successfully!");

   }

   @Override
   public void deleteCandidate(int candidateId) {
      jdbcTemplate.update("delete from candidate where id=?",
         candidateId);
      System.out.println("Candidate with id="+candidateId+
         " deleted successfully!");

   }

   @Override
   public Candidate find(int candidateId) {
      Candidate c = null;
      c = (Candidate) jdbcTemplate.queryForObject("select *
         from candidate "
         + "where id=?", new Object[] { candidateId },
      new BeanPropertyRowMapper<Candidate>(Candidate.
         class));
      return c;
   }

   @Override
   public List<Candidate> findAll() {
      List<Candidate> candidates = new ArrayList<>();
      candidates = jdbcTemplate.query("select * from candidate",
      new BeanPropertyRowMapper<Candidate>
         (Candidate.class));
      return candidates;
   }

}

Třída Spring Boot Loader:SpringBootJdbcDemoApplication.java

package org.mano.springbootjdbc.demo;

import java.util.List;

import org.mano.springbootjdbc.demo.dao.CandidateDao;
import org.mano.springbootjdbc.demo.model.Candidate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.
   SpringBootApplication;

@SpringBootApplication
public class SpringBootJdbcDemoApplication implements
      CommandLineRunner {
   @Autowired
   private CandidateDao cdao;

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

   @Override
   public void run(String... arg0) throws Exception {
      Candidate c1 = new Candidate(1, "Sachin Tendulkar",
         "[email protected]", "1234567890");
      Candidate c2 = new Candidate(2, "Amit Saha",
         "[email protected]", "9632587410");
      Candidate c3 = new Candidate(3, "Sandip Paul",
         "[email protected]", "8527419630");
      Candidate c4 = new Candidate(4, "Rajib Kakkar",
         "[email protected]", "9876543210");
      Candidate c5 = new Candidate(5, "Rini Simon",
         "[email protected]", "8624793150");
      cdao.addCandidate(c1);
      cdao.addCandidate(c2);
      cdao.addCandidate(c3);
      cdao.addCandidate(c4);
      cdao.addCandidate(c5);

      List<Candidate> candidates = cdao.findAll();
      for (Candidate candidate : candidates) {
         System.out.println(candidate);
      }
      cdao.deleteCandidate(3);

      candidates = cdao.findAll();
      for (Candidate cc : candidates) {
         System.out.println(cc);
      }

   }

}

Application.properties

spring.driverClassName=com.mysql.jdbc.Driver
spring.url=jdbc:mysql://localhost:3306/testdb
spring.username=root
spring.password=secret

Spusťte aplikaci

Chcete-li aplikaci spustit, klikněte pravým tlačítkem na projekt v Projektovém průzkumníku a vyberte Spustit jako -> Aplikace Spring Boot . To je vše.

Závěr

Máme tři možnosti, jak pracovat s programováním relační databáze s Spring:

  • Staromódní JDBC s Spring. To znamená použití rámce Spring pro všechny praktické účely v programu kromě podpory dat Spring.
  • Použití tříd šablon JDBC. Spring nabízí JDBC abstraktní třídy pro dotazování relačních databází; ty jsou mnohem jednodušší než práce s nativním kódem JDBC.
  • Spring má také vynikající podporu pro rámec ORM (Object Relational Mapping) a lze jej dobře integrovat s prominentní implementací JPA (Java Persistent Annotation) API, jako je Hibernate. Má také vlastní asistenci Spring Data JPA, která může automaticky generovat implementaci úložiště za běhu.

Pokud se člověk z nějakého důvodu rozhodne pro JDBC, je lepší použít podporu šablon Spring, jako je JdbcTemplate jinak než pomocí ORM.

Odkazy

  • Zdi, Crag. Jaro v akci 4 , Manning Publications
  • Dokumetace rozhraní API Spring 5

  1. Předat parametry WHERE do zobrazení PostgreSQL?

  2. Chyby T-SQL, úskalí a osvědčené postupy – spoje

  3. Zápis do konkrétních schémat pomocí RPostgreSQL

  4. v postgres, můžete nastavit výchozí formátování pro časové razítko, podle relace nebo globálně?