JavaRush /Java Blog /Random-TK /“PostgreSQL” maglumat bazasyny “Bahar boot” -da RESTful h...
Artur
Dereje
Tallinn

“PostgreSQL” maglumat bazasyny “Bahar boot” -da RESTful hyzmatyna goşmak. 2-nji bölüm

Toparda çap edildi
“PostgreSQL” maglumat bazasyny “Bahar boot” -da RESTful hyzmatyna goşmak. 1-nji bölüm “PostgreSQL” maglumat bazasyny “Bahar boot” -da RESTful hyzmatyna goşmak.  2-nji bölüm Şeýlelik bilen, soňky bölüminde kompýuterde PostgresSQL maglumat bazasyny nädip gurmalydygyny, pgAdmin-de maglumat bazasyny döretmegi, şeýle hem el bilen we programma taýdan tablisalary döretmegi we pozmagy öwrendik. Bu bölümde, maglumatlar bazasy we tablisalar bilen işlemegi öwrenmek üçin programmamyzy täzeden ýazarys. Näme üçin biz? Sebäbi men özüm bilen bu materialdan öwrenýärin. Soň bolsa diňe bir öňümizdäki meseläni çözmek bilen çäklenmän, has tejribeli programmistleriň maslahatynyň kömegi bilen ýolda ýüze çykýan ýalňyşlyklary hem düzederis. Şeýlelik bilen, bir toparda işlemegi öwreneris;) Ilki bilen, com.javarush.lectures.rest_examplebukjada täze bukja döredeliň we oňa jaň edeliň repository. Bu paketde täze interfeýs dörederis ClientRepository:
package com.javarush.lectures.rest_example.repository;

import com.javarush.lectures.rest_example.model.Client;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ClientRepository extends JpaRepository<Client, Integer>  {
}
Bu interfeýs maglumatlar bazalarymyz we tablisalarymyz bilen “jadyly” täsir eder. Näme üçin jadyly? Sebäbi onuň ýerine ýetirilişini ýazmak hökman däl we Bahar çarçuwasy bize berer. Diňe şeýle interfeýs döretmeli, bu “jadydan” eýýäm peýdalanyp bilersiňiz. ClientIndiki ädim, synpy şeýle redaktirlemek :
package com.javarush.lectures.rest_example.model;

import javax.persistence.*;

@Entity
@Table(name = "clients")
public class Client {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "name")
    private String name;

    @Column(name = "email")
    private String email;

    @Column(name = "phone")
    private String phone;

    //… getters and setters
}
Bu synpda edenlerimiziň hemmesi diňe bellikler goşmakdy. Geliň, olaryň üstünden geçeliň:
  • @Entity - bu noýba (synp) bir birlikdigini görkezýär.
  • @Table - bu guramada görkeziljek tablisanyň adyny görkezýär.
  • @Id - sütün ID (esasy açar - häzirki tablisadaky maglumatlaryň özboluşlylygyny üpjün etmek üçin ulanyljak baha. Bellik: Andreý )
  • @ Sütün - guramanyň emlägine düzülen sütüniň adyny görkezýär.
  • @GeneratedValue - bu emlägiň görkezilen strategiýa laýyklykda dörediljekdigini görkezýär.
Tablisa meýdanlarynyň atlary synpdaky üýtgeýänleriň atlaryna gabat gelmeli däldir. Mysal üçin, üýtgeýjimiz bar bolsa firstName, meýdançany tablisadaky at bilen atlandyrarys first_name. Bu düşündirişleri gönüden-göni meýdanlarda we alýanlarda goýup bolýar. Theseöne bu usullardan birini saýlasaňyz, bu stili programmaňyzyň dowamynda saklamaga synanyşyň. Sanawlary gysgaltmak üçin ilkinji usuly ulandym. Maglumatlar bazalary bilen işlemek üçin düşündirişleriň has doly sanawyny şu ýerden tapyp bilersiňiz . Indi klasa geçeliň ClientServiceImplwe ony aşakdaky ýaly ýazalyň:
package com.javarush.lectures.rest_example.service;

import com.javarush.lectures.rest_example.model.Client;
import com.javarush.lectures.rest_example.repository.ClientRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ClientServiceImpl implements ClientService {

    @Autowired
    private ClientRepository clientRepository;

    @Override
    public void create(Client client) {
        clientRepository.save(client);
    }

    @Override
    public List<Client>  readAll() {
        return clientRepository.findAll();
    }

    @Override
    public Client read(int id) {
        return clientRepository.getOne(id);
    }

    @Override
    public boolean update(Client client, int id) {
        if (clientRepository.existsById(id)) {
            client.setId(id);
            clientRepository.save(client);
            return true;
        }

        return false;
    }

    @Override
    public boolean delete(int id) {
        if (clientRepository.existsById(id)) {
            clientRepository.deleteById(id);
            return true;
        }
        return false;
    }
}
Sanawdan görnüşi ýaly, eden zatlarymyz indi zerur däl setirleri pozmakdy:
// Хранorще клиентов
private static final Map<Integer, Client>  CLIENT_REPOSITORY_MAP = new HashMap<>();

// Переменная для генерации ID клиента
private static final AtomicInteger CLIENT_ID_HOLDER = new AtomicInteger();
Munuň ýerine interfeýsimizi yglan etdik ClientRepositorywe baharyň synpymyza awtomatiki usulda goşmagy üçin @Autowired düşündirişini goýduk. Şeýle hem, ähli işleri bu interfeýsde, has dogrusy, Baharyň goşjak ýerine ýetirişine tabşyrdyk. Iň soňky we iň gyzykly tapgyra geçeliň - programmamyzy synap göreliň. Poçta programmasyny açalyň ( bu ýerde nädip ulanmalydygyny görüň ) we şu adrese GET haýyşyny ibereliň: http: // localhost: 8080 / müşderiler. Bu jogaby alýarys:
[
    {
        "id": 1,
        "name": "Vassily Petrov",
        "email": "vpetrov@jr.com",
        "phone": "+7 (191) 322-22-33)"
    },
    {
        "id": 2,
        "name": "Pjotr Vasechkin",
        "email": "pvasechkin@jr.com",
        "phone": "+7 (191) 223-33-22)"
    }
]
POST haýyşyny iberýäris:
{
  "name" : "Amigo",
  "email" : "amigo@jr.com",
  "phone" : "+7 (191) 746-43-23"
}
We ... programmadaky ilkinji ýalňyşlygymyzy ele alýarys:
{
    "timestamp": "2020-03-06T13:21:12.180+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement",
    "path": "/clients"
}
“PostgreSQL” maglumat bazasyny “Bahar boot” -da RESTful hyzmatyna goşmak.  2-nji bölüm Surnallara seredýäris we aşakdaky ýalňyşlygy tapýarys:

org.postgresql.util.PSQLException: ОШИБКА: повторяющееся meaning ключа нарушает ограничение уникальности "clients_pkey"
  Detail: Ключ "(id)=(1)" уже существует.
Şol bir POST haýyşyny ýene-de iberýäris, netije şol bir, ýöne bu tapawut bilen: Ключ "(id)=(2)" уже существует. Üçünji gezek şol bir haýyşy iberýäris we Status: 201 Döredilýär. GET haýyşyny ýene iberýäris we jogap alýarys:
[
    {
        "id": 1,
        "name": "Vassily Petrov",
        "email": "vpetrov@jr.com",
        "phone": "+7 (191) 322-22-33)"
    },
    {
        "id": 2,
        "name": "Pjotr Vasechkin",
        "email": "pvasechkin@jr.com",
        "phone": "+7 (191) 223-33-22)"
    },
    {
        "id": 3,
        "name": "Amigo",
        "email": "amigo@jr.com",
        "phone": "+7 (191) 746-43-23"
    }
]
Bu, programmamyzyň bu tablisanyň eýýäm ilatyň köpdügine üns bermeýändigini we birinden başlap ID-ni belleýändigini görkezýär. Dogrusy, näsazlyk iş pursady, umytdan düşmäň, bu köplenç bolýar. Şonuň üçin kömek soramak üçin has tejribeli kärdeşlerime ýüz tutaryn: "Hormatly kärdeşlerim, programmanyň kadaly işlemegi üçin muny nädip düzedip boljakdygyny teswirlerde maslahat bermegiňizi haýyş edýäris." Kömek gelmek üçin köp wagt gerek däldi we Stas Pasinkow teswirlerde maňa haýsy ugra seretmelidigimi aýtdy. Munuň üçin oňa aýratyn minnetdarlyk bildirýärin! Thingöne zat, synpda meýdan üçin Clientdüşündiriş strategiýasyny nädogry görkezdim . Bu strategiýa MySQL üçin amatly. Oracle ýa-da PostrgeSQL bilen işlesek, başga strategiýa düzmeli. Esasy düwmeler üçin strategiýalar barada has giňişleýin maglumaty şu ýerden okap bilersiňiz . “GenerationType.SEQUENCE” strategiýasyny saýladym. Ony durmuşa geçirmek üçin initDB.sql faýlyny we elbetde, Müşderi synpynyň id meýdançasynyň düşündirişlerini täzeden ýazmaly bolarys. InitDB.sql täzeden ýazyň: @GeneratedValue(strategy = GenerationType.IDENTITY)id“PostgreSQL” maglumat bazasyny “Bahar boot” -da RESTful hyzmatyna goşmak.  2-nji bölüm
CREATE TABLE IF NOT EXISTS clients
(
    id    INTEGER PRIMARY KEY ,
    name  VARCHAR(200) NOT NULL ,
    email VARCHAR(254) NOT NULL ,
    phone VARCHAR(50)  NOT NULL
);
CREATE SEQUENCE clients_id_seq START WITH 3 INCREMENT BY 1;
Üýtgän zat: tablisamyzyň id sütüniniň görnüşi üýtgedi, ýöne soňundan has köp. Aşakda bir setir goşduk, onda täze yzygiderli müşderi_id_seq döredýäris, üçden başlamalydygyny görkezýäris (sebäbi populateDB.sql faýlyndaky iň soňky id 2) we ýokarlanmanyň biriniň bolmalydygyny görkezýäris. ID sütün görnüşine gaýdyp geleliň. Bu ýerde INTEGER-i kesgitledik, sebäbi SERIAL-dan çyksak, yzygiderlilik awtomatiki usulda dörediler, şol bir müşderi_id_seq ady bilen, ýöne birinden başlar (bu programma näsazlygyna sebäp boldy). Şeýle-de bolsa, indi bir tablisany pozmak isleseňiz, bu yzygiderliligi pgAdmin interfeýsi ýa-da aşakdaky buýruklary ulanyp .sql faýly arkaly el bilen pozmaly bolarsyňyz:
DROP TABLE IF EXISTS clients;
DROP SEQUENCE IF EXISTS clients_id_seq
Emma ilki bilen tablisany doldurmak üçin populateDB.sql ýaly faýly ulanmasaňyz, esasy açar üçin SERIAL ýa-da BIGSERIAL görnüşlerini ulanyp bilersiňiz, yzygiderliligi el bilen döretmeli däl we şonuň üçin pozmaly dälsiňiz aýratynlykda. Yzygiderlilik barada has giňişleýin maglumaty web sahypasynda okap bilersiňiz. PostgreSQL resminamalary . idGeliň, synp meýdançasynyň düşündirişlerine geçeliň Clientwe olary aşakdaky görnüşde format edeliň:
@Id
@Column(name = "id")
@SequenceGenerator(name = "clientsIdSeq", sequenceName = "clients_id_seq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "clientsIdSeq")
private Integer id;
Näme etdik: @SequenceGeneratoryzygiderlilik generatoryny döretmek üçin täze düşündiriş gurduk, oňa at dakdyk clientsIdSeq, yzygiderlilik üçin generatordygyny görkezdik clients_id_seqwe bir atribut goşduk. allocationSize = 1 Bu islege bagly atribut, ýöne muny etmesek, programmany işledenimizde aşakdaky ýalňyşlygy alarys:

org.hibernate.MappingException: The increment size of the [clients_id_seq] sequence is set to [50] in the entity mapping while the associated database sequence increment size is [1]
Ulanyjy Andreýiň teswirlerde bu barada ýazan zady : allocationSize, ilkinji nobatda, “täze id” üçin gibernatyň maglumatlar bazasyna syýahatyny azaltmak üçin niýetlenendir. Bahasy == 1 bolsa, maglumatlar bazasynda saklamazdan ozal her täze gurama üçin gyşlaň, ID üçin maglumatlar bazasyna “işleýär”. Bahasy> 1 bolsa (mysal üçin, 5) bolsa, gibernate “täze” id üçin maglumatlar bazasyna ýygy-ýygydan ýüz tutar (mysal üçin, 5 gezek) we habarlaşanyňyzda gibernat maglumat bazasyndan bu belgini saklamagyny sorar (biziňkilerde) ýagdaý, 5) bahalar. Beýan eden säwligiňiz, gibernatyň 50 sany ID-ni almak isleýändigini görkezýär, emma maglumatlar bazasynda bu gurama ID-ni diňe 1-nji belgä laýyklykda bermäge taýýardygyňyzy görkezdiňiz . Başga bir näsazlyk ulanyjy Nikolýa Kudrýaşow tarapyndan tutuldy : Asyl makala http: // localhost: 8080 / müşderi / 1-den haýyş etseňiz, ýalňyşlyk yzyna gaýtarylar:
{
    "timestamp": "2020-04-02T19:20:16.073+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "Type definition error: [simple type, class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.javarush.lectures.rest_example.model.Client$HibernateProxy$ZA2m7agZ[\"hibernateLazyInitializer\"])",
    "path": "/clients/1"
}
Bu ýalňyşlyk Gibernate-iň ýalta başlangyjy bilen baglanyşykly we ondan dynmak üçin Müşderi synpyna goşmaça düşündiriş goşmaly:
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
Şeýlelik bilen:
@Entity
@Table(name = "clients")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Client {.....}
Indi programmamyzy işledeliň (müşderiler tablisasyny soňky gezek şol ýerde galan bolsa maglumatlar bazasyndan aýyrandan soň) we application.properties faýlyndan 3 setir düşündiriş bereliň:
#spring.datasource.initialization-mode=ALWAYS
#spring.datasource.schema=classpath*:database/initDB.sql
#spring.datasource.data=classpath*:database/populateDB.sql
Geçen gezek diňe soňky setire teswir ýazdyk, ýöne ... Tablisa eýýäm döredip, dolduranymyz üçin, häzirki wagtda bu maňa has mantykly ýalydy. Synaga geçeliň, Postman arkaly GET, POST, PUT we DELETE haýyşlaryny ýerine ýetireliň, kemçilikleriň ýok bolandygyny we hemme zadyň gowy işleýändigini göreris. Ine, iş gutardy. Indi gysgaça jemläp, öwrenen zatlarymyza seredip bileris:
  • PostgreSQL-i kompýuteriňize guruň
  • PgAdmin-de maglumat bazalaryny dörediň
  • Tablisalary el bilen we programma taýdan dörediň we pozuň
  • Tablisalary .sql faýllary arkaly dolduryň
  • “Bahar” çarçuwasynyň “jadyly” JpaRepository interfeýsi barada azajyk öwrendik
  • Şeýle programma döredilende ýüze çykyp biljek käbir kemçilikler hakda öwrendik
  • Kärdeşlerimizden maslahat soramakdan utanmaly däldigimize düşündik
  • JavaRush jemgyýetiniň elmydama kömege ýetjek güýçdigini tassykladyk;)
Häzirlikçe bu ýerde gutaryp bileris. “PostgreSQL” maglumat bazasyny “Bahar boot” -da RESTful hyzmatyna goşmak.  2-nji bölümBu materialy okamak üçin wagt sarp edenlere sag bolsun aýdýaryn. Teswirleriňizi, synlamalaryňyzy, goşmaçalaryňyzy we konstruktiw tankytlaryňyzy görüp begenerin. Belki-de, bu meselä UPD “açar söz” arkaly goşmagy wada berýän, bu meseläniň has ajaýyp çözgütlerini hödürlärsiňiz, elbetde, awtor hökmünde agzalmagyňyz mümkin. Umuman aýdanyňda, bu makalany we materialy hödürlemegiň bu stilini haladyňyzmy ýa-da umuman, JR-da makalalar ýazmagy dowam etdirmelimi ýa-da ýokdugyny ýazyň. Ine goşmaçalar: UPD1: ulanyjy Justiniancom.javarush.lectures.rest_example , Java-da at dakmak konwensiýalaryny bozmazlyk üçin bukjanyň adyny com.javarush.lectures.rest.examplewe taslamanyň adyny üýtgetmegi maslahat berdi . UPD2 ulanyjysy Aleksandr PýanowClientRepository synpda bir meýdan başlamak üçin ClientServiceImpldüşündirişden has konstruktor ulanmak has gowudygyny aýtdy @Autowired. Bu, seýrek ýagdaýlarda alyp bolýandygy bilen düşündirilýär NullPointerExceptionwe umuman aýdylanda bu iň oňat tejribe we men onuň bilen ylalaşýaryn. Logika görä, obýektiň başlangyç işlemegi üçin bir meýdan zerur bolsa, ony konstruktorda başlamak has gowudyr, sebäbi konstruktorsyz synp bir obýekte ýygnalmaz, şonuň üçin bu meýdan basgançakda başlar. obýekt döretmek. Düzedişler bilen kod böleklerini goşaryn (näme bilen çalyşmaly):
@Autowired
private ClientRepository clientRepository;

private final ClientRepository clientRepository;

public ClientServiceImpl(ClientRepository clientRepository) {
   this.clientRepository = clientRepository;
}
Birinji bölüme baglanyşyk: “Spring Boot” -daky RESTful hyzmatyna PostgreSQL maglumat bazasyny goşmak. 1-nji bölüm PS Sizden haýsydyr biriňiz bu bilim programmasyny ösdürmegi dowam etdirmek isleseňiz, bu makala gollanmalaryňyza baglanyşyk goşmaga begenerin. Belki, bir gün bu programma portfeliňize iş goşup boljak hakyky iş programmasyna meňzeş bir zada öwrüler. PPS Bu sada makala barada, ruçkanyň bu synagyny eziz gyzlarymyza, aýal-gyzlarymyza bagyşlamagy makul bildim. Kim bilýär, belki indi bu aýal üçin bolmasa Java, JavaRush, tebigatda programmirleme bolmazdy . Baýramyňyz bilen gutlaýarys, eziz akylly adamlarymyz! 8-nji martyňyz gutly bolsun! Bagtly we owadan bol!
Teswirler
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION