Databázy (2) Prednáška 02. Alexander Šimko

Podobné dokumenty
enum

PowerPoint Presentation

Databázy (1) - Prednáška 04

História

DediĊnosť

Databázy (1) - Prednáška 03

PowerPoint Presentation

midterm2014_1

Funkcionálne programovanie Cvičenie 9 Funkcionálne programovanie v Jave Sergej Chodarev 22. november 2017 Technická Univerzita v Košiciach

Princípy tvorby softvéru Programovacie paradigmy

Algoritmizácia a programovanie - Príkazy

Identity Lifecycle Management

Microsoft PowerPoint - OOP_prednaska_10.pptx

Identity Lifecycle Management

Tue Oct 3 22:05:51 CEST Začiatky s jazykom C 2.1 Štruktúra programu Štruktúra programu by sa dala jednoducho popísať nasledovnými časťami, kto

Prevádzka

Databázy (1) - Prednáška 10

STRUČNÝ NÁVOD KU IP-COACHU

7/1/2015 Úvod do databáz, skúškový test, max 25 bodov, 90 min

PowerPoint Presentation

Privátna zóna pre prevádzku Obsah Privátna zóna pre prevádzku 1 Obsah 1 Webová stránka 2 Úvodná stránka 2 Registrácia prevádzka/penzión

GEODETICKÝ A KARTOGRAFICKÝ ÚSTAV BRATISLAVA Chlumeckého 4, Bratislava II Obsah 1. Export údajov ZBGIS do CAD formá

Úroveň strojového kódu procesor Intel Pentium Pamäťový operand Adresovanie pamäte Priama nepriama a indexovaná adresa Práca s jednorozmerným poľom Pra

Objektovo orientované programovanie

Elmasri, Fundamentals of DBSs

CENTRÁLNY DEPOZITÁR CENNÝCH PAPIEROV SR, a.s. ROČNÁ ŠTATISTIKA Annual Statistics Rok 2012 / Year 2012

User:Andrej Sedlacek

Identity Lifecycle Management

iot business hub whitepaper isdd_em_New.pdf

Výnimky

Identity Lifecycle Management

SK_mTransfer_Okamzita_notifikacia_ indd

Slovenská technická univerzita v Bratislave Fakulta informatiky a informačných technológií Ilkovičova 2, , Bratislava 4 Internet vecí v našich ž

Balíčkovanie FreeSWITCH-u pre Debian Autor: Zdenko Holeša, InžProjekt 1, KIS FRI ŽU Predkompilované balíčky Predkompilované balíčky existujú pre Debia

Novinky v OpcDbGateway 5.0

s sol

Microsoft Word - Priloha_1.docx

gis5 prifuk

Finančné riaditeľstvo Slovenskej republiky 9/ORP/2019/IM Stiahnutie identifikačných a autentifikačných údajov pri ORP - rola Administrátor/Technik Inf

Relačné a logické bázy dát

UNIVERZITA KOMENSKÉHO V BRATISLAVE FAKULTA MATEMATIKY, FYZIKY A INFORMATIKY Informačný systém pre materské školy Bakalárska práca 2019 Monika Vlčková

Katalóg služieb OTPdirekt-retail

Template for PowerPoint

Finančné riaditeľstvo Slovenskej republiky 10/ORP/2019/IM Stiahnutie identifikačných a autentifikačných údajov pri ORP - rola Administrátor Informácia

SK_mTransfer_Technicka_dokumentacia_ indd

midterm2019

Úrad pre dohľad nad zdravotnou starostlivosťou Žellova 2, Bratislava Dátové rozhranie pre externý subjekt FR SR Strana 1 z 11 Dátové rozhranie

Snímka 1

IAB budicek - Branding Landscape & Research options_FINAL_Gregor.pptx

NÁVRH UČEBNÝCH OSNOV PRE 1

Stravné - přecenění

CviĊenie z PTS

ECDL Syllabus V50 SK-V01

Loan Processing System pre VÚB banku Ako sme jednej z najväčších bánk na Slovensku zvýšili kvalitu a rýchlosť obsluhy firemných klientov nasadením sys

Matej Kendera - PDF, word, lucene, java

Finančné riaditeľstvo Slovenskej republiky 12/ORP/2019/IM Postup pre overenie pravosti pokladničného dokladu Informácia je určená pre subjekty (zákazn

fm 2012 a predajňa.doc

Princípy tvorby softvéru Modelovanie domény

Snímka 1

INTERNET BANKING Ako zrealizovať hromadný prevod VŠETKO, ČO JE MOŽNÉ with.vub.sk, Bank of

Microsoft Word - Manažment_tagov_tim24_tema12_2017.docx

PowerPoint Presentation

SAEAUT SNMP OPC Server

Architektúra a návrh Zdôvodnenie navrhnutej architektúry Systém si architektonicky môžeme rozdeliť na viacero vrstiev. Najpodstatnejšie je oddelenie z

Informačný systém pre externú časť a písomnú formu internej časti maturitnej skúšky Informačný systém pre EČ a PFIČ maturitnej skúšky Užívateľská prír

FAQ

NSK Karta PDF

Microsoft Word - prirucka_katedry_nova

Ponuka Štart

Novinky programu MSklad

Slide 1

5/1/2012 Úvod do databáz, skúškový test, max 25 bodov, 90 min 1. Daná je databáza: capuje(krcma, Alkohol, Cena), lubi(pijan, Alkohol) navstivil(idn, P

SK MATEMATICKA OLYMPIADA 2010/ ročník MO Riešenia úloh domáceho kola kategórie Z4 1. Doplň do prázdnych políčok čísla od 1 do 7 každé raz tak,

2. Týždeň MySQL - dátové typy a funkcie num. a reťazcové 1. Prvky jazyka MySQL 2. Typy

Aktion.NEXT Novinky vo verzii 1.9

(Microsoft Word - Registr\341cia \372\350tu Hik-Connect.docx)

IP telefónia. Návrh AsÚ SAV

Algoritmizácia a programovanie - Štruktúrované údajové typy

Microsoft Word - mnohouholnik.doc

Návod na obsluhu CompactIO 1

PowerPoint Presentation

STRUČNÝ NÁVOD KU IP-COACHU

Stravné - přecenění

Microsoft Word - 11_Distribuované spracovanie dát nad MapReduce architektúrou _Hadoop a Hive_

Microsoft PowerPoint - SLIDES_02DTD.ppt

eKasa

Microsoft Word Nextra_ADSLink.doc

FAQ

ADBEE_System_pre_pozicovne_Datasheet copy

čiastka 22/2019 Vestník NBS rozhodnutie NBS č. 14/ ÚPLNÉ ZNENIE rozhodnutia Národnej banky Slovenska č. 3/2008 z 25. novembra 2008 o podmien

Untitled

CitiManager - Migration Quick Reference Guide for Cardholders_Slovak_fin

untitled

INTERNET BANKING Práca s tokenom VŠETKO, ČO JE MOŽNÉ with.vub.sk, Bank of

Konkurentné programovanie

Blood Glucose Monitoring System Copyright Ascensia Diabetes Care Holdings AG. All rights reserved. diabetes.ascensia.com

Georeceive a Geoshopping

Prepis:

Databázy (2) Prednáška 02 Alexander Šimko alexander.simko@uniba.sk

Contents I

Upozornenie Prezentovaný kód nie vždy správne ošetruje chyby a uzatvára objekty. Je to kompromis, aby sa dal dať na slajdy aspoň trochu čitateľne.

Section 1

pre rôzne typy aplikácii to môže byť rôzne

Podnikové (enterprise) aplikácie Typické operácie CRUD operácie nad entitami zobraz zoznam zákazníkov zobraz detail zákazníka aktualizuj, pridaj, odober zákazníka Zložitejšie doménové operácie prevod peňazí medzi účtami pripisovanie úrokov na účty účtovanie poplatkov za služby Reporty/Štatistiky počet nových zákazníkov sa jednotlivé kvartály zisky za jednotlivé služby po jednotlivých mesiacoch

Špagetový kód Určite nie ako špagetový kód kód, ktorý nie je dobre organizovaný do logických celkov je prepletený ako špagety nikto sa už v ňom nevyzná

Špagetový kód Špagetový kód Éra príkazu GOTO

Špagetový kód Špagetový kód Čo zle sa môže stať? https://xkcd.com/292/

Špagetový kód Špagetový kód Éra bez GOTO Miešame dokopy spracovanie a kontrolu vstupu od používateľa generovanie výstupu (HTML, kreslenie čiar,...) vykonávanie doménovej logiky práca s databázou

Špagetový kód Špagetový kód CRUD customers id : integer first_name : varchar last_name : varchar address : varchar birth_number : varchar gender : char(1)

Špagetový kód Špagetový kód CRUD Zobrazenie zákazníka class GUI { TextField firstname; TextField lastname; TextField birthnumber; TextField address; ComboBox gender; Label message;..

Špagetový kód Špagetový kód CRUD Zobrazenie zákazníka void showuser(int id) { Connection c =... PreparedStatement s = c.preparestatement("select * FROM customers WHERE id =?"); s.setint(1, id); ResultSet r = s.executequery(); if (r.next() == true) { firstname.settext(r.getstring("first_name"); lastname.settext(r.getstring("last_name"); birthnumber.settext(r.getstring("birth_number"); address.settext(r.getstring("address"); gender.setvalue(r.getstring("gender"); else { message.settext("no such customer exists"); s.close(); c.close();

Špagetový kód Špagetový kód CRUD Pridávanie zákazníka void onaddclicked() { if (firstname.gettext().isempty()) { message.settext("first name cannot be empty"); return; if (lastname.gettext().isempty()) { message.settext("last name cannot be empty"); return;

Špagetový kód Špagetový kód CRUD Pridávanie zákazníka Connection c =... PreparedStatement s = c.preparestatement("select * FROM customers WHERE birthnumber =?"); s.setstring(1, birthnumber.gettext()); ResultSet r = s.executequery(); if (r.next() == true) { message.settext("customer with given birth number already exists"); r.close(); s.close(); c.close(); return; r.close(); s.close();

Špagetový kód Špagetový kód CRUD Pridávanie zákazníka s = c.preparestatement("insert INTO customers (first_name, last_name, address, gender) VALUES(?,?,?,?)"); s.setstring(1, firstname.gettext()); s.setstring(2, lastname.gettext()); s.setstring(3, address.gettext()); s.setstring(4, gender.getselectedvalue()); try { s.executeupdate(); message.settext("customer was successfully added."); catch (SQLException e) { message.settext("could not perform the operation. Please try again."); s.close(). c.close();

Špagetový kód Špagetový kód Prečo to takto nerobiť? veľmi zle sa udržuje vysoká šanca chýb, ktoré sa potom ťažko hľadajú a opravujú veľmi obtiažne sa dopĺňajú nové požiadavky nový človek nemá šancu kódu porozumieť predlžuje čas tvorby softvéru a jeho náklady

Špagetový kód Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live. 1 1 http://c2.com/cgi/wiki?codeforthemaintainer

Row Data Gateway Problém Prepletené GUI a prístup k databáze na rôznych miestach v GUI kóde spúšťame rovnaké/podobné SQL príkazy názvy stĺpcov máme na rôznych miestach v GUI ak zmeníme názov tabuľky/stĺpca a pod, musíme meniť kód na veľa miestach navyše sú názvy tabuliek/stĺpcov ako reťazcové literály, čiže strácame statickú kontrolu kompilátorom a možnosť refaktorovania pomocou IDE

Row Data Gateway Čo takto zaobaliť prístup k DB do samostatnej triedy? customers id : integer first_name : varchar last_name : varchar address : varchar birth_number : varchar gender : char(1) class Customer { Integer id; String firstname; String lastname; String address; String birthnumber; String gender;

Row Data Gateway Čo takto zaobaliť prístup k DB do samostatnej triedy? static Customer findbyid(int id) { Connection c =... PreparedStatement s = c.preparestatement("select * FROM customers WHERE id =?"); s.setint(1, id); return loadone(s); static Customer findbybirthnumber(string birthnumber) { Connection c =... PreparedStatement s = c.preparestatement("select * FROM customers WHERE birth_number =?"); s.setint(1, birthnumber); return loadone(s);

Row Data Gateway Čo takto zaobaliť prístup k DB do samostatnej triedy? static Customer loadone(preparedstatement s) { ResultSet r = s.executequery(); if (r.next()) { return load(r); else { return null; static Customer load(resultset r) { Customer customer = new Customer(); customer.id = r.getint("id"); customer.firstname = r.getstring("first_name"); customer.lastname = r.getstring("last_name"); customer.address = r.getstring("address"); customer.birthnumber = r.getstring("birth_number"); customer.gender = r.getstring("gender"); return customer;

Row Data Gateway Čo takto zaobaliť prístup k DB do samostatnej triedy? static List<Customer> findall() { Connection c =... PreparedStatement s = c.preparestatement("select * FROM customers"); return loadall(s); static List<Customer> loadall(preparedstatement s) { ResultSet r = s.executequery(); List<Customer> customers = new ArrayList<>(); while (r.next()) { customers.add(load(r)); return customers;

Row Data Gateway Čo takto zaobaliť prístup k DB do samostatnej triedy? void insert() { Connection c =... PreparedStatement s = c.preparestatement("insert INTO customers (first_name, last_name, address, birth_number, gender) VALUES(?,?,?,?,?) RETURING id"); s.setstring(1, firstname); s.setstring(2, lastname); s.setstring(3, address); s.setstring(4, birth_number); s.setstring(5, gender); ResultSet r = s.executequery(); if (r.next()) { this.id = r.getint("id"); r.close(); s.close();

Row Data Gateway Čo takto zaobaliť prístup k DB do samostatnej triedy? void update() { Connection c =... PreparedStatement s = c.preparestatement("update customers SET first_name =?, last_name =?, address =?, birth_number =?, gender =? WHERE id =?"); s.setstring(1, firstname); s.setstring(2, lastname); s.setstring(3, address); s.setstring(4, birth_number); s.setstring(5, gender); s.setint(6, id); s.executeupdate(); s.close();

Row Data Gateway Čo takto zaobaliť prístup k DB do samostatnej triedy? void delete() { PreparedStatement s = c.preparestatement("delete customers WHERE id =?"); s.setint(1, id); s.executeupdate(); s.close();

Row Data Gateway Vylepšený kód CRUD Zobrazenie zákazníka class GUI { TextField firstname; TextField lastname; TextField birthnumber; TextField address; ComboBox gender; Label message;..

Row Data Gateway Vylepšený kód CRUD Zobrazenie zákazníka void showuser(int id) { Customer c = Customer.findById(id); if (c!= null) { firstname.settext(c.firstname); lastname.settext(c.lastname); birthnumber.settext(c.birthnumber); address.settext(c.address); gender.setvalue(c.gender); else { message.settext("no such customer exists");

Row Data Gateway Vylepšený kód CRUD Pridávanie zákazníka void onaddclicked() { if (firstname.gettext().isempty()) { message.settext("first name cannot be empty"); return; if (lastname.gettext().isempty()) { message.settext("last name cannot be empty"); return;

Row Data Gateway Vylepšený kód CRUD Pridávanie zákazníka Customer existing = Customer.findByBirthNumber(birthNumber.getText()); if (existing!= null) { message.settext("customer with the given birth number already exists"); return; Customer customer = new Customer(); customer.firstname = firstname.gettext(); customer.lastname = lastname.gettext(); customer.address = address.gettext(); customer.gender = gender.getselectedvalue(); customer.insert();

Row Data Gateway Čo sme tým získali? kód je prehľadnejší všetok SQL kód týkajúci sa tabuľky customers je v triede Customer čisto databázové zmeny sa prejavia iba v zmene tejto triedy máme statickú kontrolu názvov stĺpcov, nakoľko sú to teraz členské premenné triedy trieda Customer slúži aj ako dokumentácia hovoríme ňou, že systém narába so zákazníkmi

Row Data Gateway To, čo sme si práve ukázali je vzor Row Data Gateway je to architektonický vzor na oddelenie kódu na prístup k databáze pre jednu tabuľku vytvoríme jednu Row Data Gateway triedu inštancia triedy reprezentuje jeden riadok tabuľky členské premenné mapujú stĺpce tabuľky 1:1 RowDataGateway column1... dolumnn insert() update() delete() uses Finder findbyid(id) findbycolumn1(value) metódy na nájdenie riadku/ov v špeciálnej triede Finder alebo ako statické metódy triedy RowDataGateway

Row Data Gateway Row Data Gateway súvisiace argumenty pokope na výpočet oslovenia osoby potrebujeme viac atribútov zákazníka namiesto viacerých argumentov použijeme triedu Customer class EmailService { String getaddressline(customer c, String language) { if("en".equals(language)) { if (/* is male */) { return "Mr " + c.firstname + " " + c.lastname; else if (/* is younger that 15 */) { return "Miss " + c.firstname + " " + c.lastname; else { return "Ms " + c.firstname + " " + c.lastname;...

Row Data Gateway Zapúzdrenie členských premenných zmena členských premenných na private zavedenie public metód getxy a setxy

Row Data Gateway Zapúzdrenie členských premenných Kontrola argumentov class Customer { private String birthnumber; public String getbirthnumber() { return birthnumber; public void setbirthnumber(string birthnumber) { if (birthnumber == null) { throw new IllegalArgumentException(); if (birthnumber.matches("[0-9]{6/[0-9]{3,4" == false) { throw new IllegalArgumentException(); this.birthnumber = birthnumber;...

Row Data Gateway public void setgender(string gender) { this.gender = gender.equals("m")? Gender.MALE : Gender.FEMALE;... Zapúzdrenie členských premenných Zmena reprezentácie môžeme zmeniť vnútornú reprezentáciu bez rozbitia zvyšku kódu enum Gender { MALE, FEMALE class Customer { private Gender gender; // povodne String, teraz Gender public String getgender() { return gender == Gender.MALE? "M" : "F";

Row Data Gateway Zapúzdrenie členských premenných Vypočítané stĺpce class Customer { private String firstname; private String lastname; public String getfirstname() { return firstname; public String getlastname() { return lastname; public String getfullname() { return String.format("%s %s", firstname, lastname);... k pôvodným a vypočítaným stĺpcom pristupujeme rovnako

Row Data Gateway Cudzie kľúče ostávajú tak ako sú customers id : integer... transfer_limit : numeric accounts number : varchar balance : numberic overdraft : boolen owner_id : integer class Account { String number; BigDecimal balance; boolean overdraft; int ownerid; // toto je primarny kluc // toto je cudzi kluc...

Row Data Gateway Väzobné tabuľky sú tiež iba tabuľky customers id : integer first_name : varchar last_name : varchar... customer-badges id : integer customer_id : integer badge_id : integer badges id : integer name : varchar class CustomerBadge { Integer id; int customerid; int badgeid;...

Row Data Gateway Hodí sa zaobaliť aj vypočítané tabuľky (napr. štatistiky) SELECT ceil(balance / 100.0)*100.0 AS upper_bound, count(*) FROM accounts GROUP BY upper_bound ORDER BY upper_bound class RangeStatistic { BigDecimal upperbound; int count; static List<RangeStatistic> findall() { Connection c =... PreparedStatement s = c.preparestatement("select ceil...");...

Row Data Gateway Potom treba prehodnotiť či majú pre nás zmysel operácie insert update delete to závisí od kontrétneho prípadu, čo naozaj potrebujeme

Row Data Gateway Čo s nejakým špecifickým SQL príkazom? Napr. UPDATE, čo modifikuje tisíce riadkov Vyriešiť obdobne ako metódu find zaobaliť do metódy dať ju ako statickú do Row Data Gateway alebo do špeciálnej na to určenej triedy

Špagetový kód pokračuje Špagetový kód Prevod peňazí customers id : integer... transfer_limit : numeric accounts number : varchar balance : numberic overdraft : boolen owner_id : integer prevod peňazí medzi zdrojovým a cieľovým účtom kontrola, či je na zdrojovom účte dosť peňazí kontrola, či neprekračujeme limit nastavený majiteľom účtu

Špagetový kód pokračuje Špagetový kód Prevod peňazí class GUI { TextField sourcefield; TextField destinationfield; TextField amountfield; Label message; void ontransferclicked() { String source = sourcefield.gettext(); String destination = destinationfield.gettext(); BigDecimal amount = new BigDecimal(amountField.getText());

Špagetový kód pokračuje Špagetový kód Prevod peňazí Connection c =... PreparedStatement s = c.preparestatement("select * FROM accounts WHERE number =?"); s.setstring(1, source); ResultSet r = s.executequery(); if (r.next() == false) { message.settext("source account does not exist"); r.close(); s.close(); c.close(); return;

Špagetový kód pokračuje Špagetový kód Prevod peňazí BigDecimal sourcebalance = r.getbigdecimal("balance"); boolean overdraft = r.getboolean("overdraft"); integer ownerid = r.getint("owner_id"); r.close(); PreparedStatement cs = c.preparestatement("select * FROM customers WHERE id =?"); cs.setinteger(1, ownerid); r = cs.executequery(); r.next(); BigDecimal transferlimit = r.getbigdecimal("transfer_limit"); r.close(); cs.close();

Špagetový kód pokračuje Špagetový kód Prevod peňazí if (amount.compareto(transferlimit) > 0) { message.settext("transfer limit exceeded"); s.close(); c.close(); return; if (overdraft == false sourcebalance.compareto(amount) < 0) { message.settext("insufficient banance on the source account"); s.close(); c.close(); return;...

Špagetový kód pokračuje Prvé zlepšenie Row Data Gateway class GUI { TextField sourcefield; TextField destinationfield; TextField amountfield; Label message; void ontransferclicked() { String source = sourcefield.gettext(); String destination = destinationfield.gettext(); BigDecimal amount = new BigDecimal(amountField.getText());

Špagetový kód pokračuje Prvé zlepšenie Row Data Gateway Account sourceaccount = Account.find(source); if (sourceaccount == null) { message.settext("source account does not exist"); return; Account destinationaccount = Account.find(destination); if (destinationaccount == null) { message.settext("destination account does not exist"); return; Customer customer = Customer.find(sourseAccount.ownerId); if (amount.compareto(customer.transferlimit) > 0) { message.settext("transfer limit exceeded"); return;

Špagetový kód pokračuje Prvé zlepšenie Row Data Gateway if (sourceaccount.overdraft == false sourceaccount.balance.compareto(amount) < 0) { message.settext("insufficient balance on the source account"); return; sourceaccount.balance = sourceaccount.balance.substract(amount); destinationaccount.balance = destinationaccount.balance.add(amount); sourceaccount.update(); destinationaccount.update(); message.settext("transfer succeeded");

Transaction Script Problém Prepletené GUI a doménová logika Tá istá metóda rieši: ako získať vstup od používateľa ako vykonať doménovú logiku ako zobraziť doménové chyby používateľovi Ak budeme chcieť vykonať tú istú doménovú operáciu z iného používateľského rozhrania, musíme duplikovať kód.

Transaction Script Čo takto osamostatniť doménovú operáciu? class Banking { static void transfer(string source, String destination, BigDecimal amount) { Account sourceaccount = Account.find(source); if (sourceaccount == null) throw new Exception("Source account does not exist"); Account destinationaccount = Account.find(destination); if (destinationaccount == null) throw new Exception("Destination account does not exist"); Customer customer = Customer.find(sourseAccount.ownerId); if (amount.compareto(customer.transferlimit) > 0) throw new Exception("Transfer limit exceeded");

Transaction Script Čo takto osamostatniť doménovú operáciu? if (sourceaccount.overdraft == false sourceaccount.balance.compareto(amount) < 0) throw new Exception("Insufficient balance on the source account"); sourceaccount.balance = sourceaccount.balance.substract(amount); destinationaccount.balance = destinationaccount.balance.add(amount); sourceaccount.update(); destinationaccount.update();

Transaction Script Čo takto osamostatniť doménovú operáciu? class GUI { TextField sourcefield; TextField destinationfield; TextField amountfield; Label message; void ontransferclicked() { String source = sourcefield.gettext(); String destination = destinationfield.gettext(); BigDecimal amount = new BigDecimal(amountField.getText()); try { Banking.transfer(source, destination, amount); message.settext("transfer succeeded"); catch(exception e) { message.settext(e.getmessage());

Transaction Script To, čo sme si práve ukázali je vzor Transaction Script je to architektonický vzor na oddelenie kódu doménových operácii jedna operácia/požiadavka jedna procedúra je to také procedurálne programovanie v OOP jazykoch to skončí na tiedach, ktoré majú iba (statické) metódy a žiadne členské premenné/atribúty TransactionScript operation(argument1,..., argumentn) Alterantívy buď každý skript ako jediná metóda v samostatnej triede alebo nejako rozumne zoskupiť viac metód do jednej triedy

Transaction Script Čo sme tým získali? kód je prehľadnejší doménová operácia je oddelená môžeme ju volať z viacerých miest bez duplicity kódu zmeny v tejto operácii sa prejavia v kóde iba na jednom mieste trieda Banking a metóda transfer slúžia aj ako dokumentácia hovoríme nimi, že systém vykonáva takú operáciu

Rekapitulácia Je vhodné oddeliť kód realizujúci prístup k DB vzor Row Data Gateway doménové operácie vzor Transaction Script využíva Row Data Gateway používateľské rozhranie využíva Transaction Script využíva Row Data Gateway

Ešte jeden problém Aktuálny stav kód je síce rozdelený prístup k DB a doménové operácie bežia na tom istom počítači ako GUI

Ešte jeden problém Aktuálny stav jeden PostgreSQL server s jednou databázou viac klientských počítačov, na ktorých beží doménový kód server PostgreSQL Banková aplikácia Banková aplikácia Banková aplikácia klientské PC klientské PC klientské PC

Ešte jeden problém Aké to má nevýhody? citlivý kód ako prevod peňazí beží u klienta program sa dá dekompilovať a upraviť, aby robil niečo iné program sa dá dekompilovať, a tak zdrojové kódy nie sú chránené pred ukradnutím ak chceme mať dva internet bankingy, desktopový a mobilný, v oboch klientoch máme kód na prevod peňazí

Back end a front end Čo takto rozdeliť program na dva? back end serverová aplikácia implementuje doménovú logiku cez HTTP príjima volania metód a posiela odpovede front end desktopová/mobilná aplikácia implementuje používateľské rozhranie cez HTTP volá metódy backendu

Back end a front end class Backend { static void main() { // bezi na localhost:8000 HttpServer server = HttpServer.create(new InetSocketAddress(8000),0); server.createcontext("/transfer", new TransferHandler()); server.setexecutor(executors.newcachedthreadpool()); server.start(); class TransferHandler implements HttpHandler { void handle(httpexchange exchange) { String query = exchange.getrequesturi().getquery(); String source = // vytiahni argument z query String destination // vytiahni argument z query BigDecimal amount = // vytiahni argument z query Banking.transfer(source, destination, amount); // do exchange vypis ze sa prevod podaril Ukážka jednoduchého backendu

Back end a front end Ukážka jednoduchého frontendu class GUI { TextField sourcefield; TextField destinationfield; TextField amountfield; Label message; void ontransferclicked() { String message = Unirest.get("http://banka.sk:8000/transfer").queryString("source", sourcefield.gettext()).querystring("destination", destinationfield.gettext()).querystring("amount", amountfield.gettext()).asstring().getbody(); message.settext(message);

Back end a front end Nový stav server s backendom pripájajúcim sa na PostgreSQL veľa inštancií frontendu server PostgreSQL Back end Front end Front end Front end klientské PC klientské PC klientské PC

Back end a front end Backend musí spúštať príkazy paralelne každá požiadavka je v backende obslúžená v samostatnom vlákne JDBC spojenia sú síce threadsafe, ale blokujúce (prístup z viacerých vlákien) každé vlánko potrebuje vlastné spojenie

Back end a front end Zakaždým vytvoríme nové spojenie class TransferHandler implements HttpHandler { void handle(httpexchange exchange) { Connection c = datasource.getconnection();... c.close();

Back end a front end Predávanie si spojenia pripomenutie z minula class DbContext { private static Connection connection; private DbContext() {; // tymto zakazeme robit instancie static void setconnection(connection c) { connection = c; static Connection getconnection() { return connection; static void closeconnection() { if (connection!= null) { connection.close(); connection = null;

Back end a front end Predávanie si spojenia pripomenutie z minula class DbContext { private static Connection connection; // do statickej premennej connection vieme ulozit iba jednu hodnotu

Uchovávanie si spojení vo viacvláknovom prostredí java.lang.threadlocal je to úložisko jednej hodnoty T get() void set(t value) každé vlákno ale vidí iba hodnotu, ktorú zapísalo ono

Uchovávanie si spojení vo viacvláknovom prostredí java.lang.threadlocal ThreadLocal<Integer> value = new ThreadLocal<>(); Thread 1 Thread 2 ----------------------------------------------------- value.set(10) value.set(12) value.get() == 10 value.get() == 12

Uchovávanie si spojení vo viacvláknovom prostredí java.lang.threadlocal // toto je iba ilustracna zjednodusena implementacia class ThreadLocal<T> { void set(t value) { // kazde vlakno ma priradenu svoju mapu Map values = Thread.getCurrent().getThreadLocalMap(); values.put(this, value); void T get() { Map values = Thread.getCurrent().getThreadLocalMap(); return values.get(this);

Uchovávanie si spojení vo viacvláknovom prostredí DbContext s ThreadLocal class DbContext { static ThreadLocal<Connection> connection = new ThreadLocal<>(); private DbContext() {; // tymto zakazeme robit instancie static void setconnection(connection c) { connection.set(c); static Connection getconnection() { return connection.get(); static void closeconnection() { if (connection.get()!= null) { connection.get().close(); connection.set(null);

Uchovávanie si spojení vo viacvláknovom prostredí DbContext s ThreadLocal class TransferHandler implements HttpHandler { void handle(httpexchange exchange) { String query = exchange.getrequesturi().getquery(); String source = // vytiahni argument z query String destination // vytiahni argument z query BigDecimal amount = // vytiahni argument z query // ziskame nove spojenie a nastavime ho pre vlakno DbContext.setConnection(dataSource.getConnection()); Banking.transfer(source, destination, amount); // uzavrie spojenie pre svoje vlakno DbContext.closeConnection();

Uchovávanie si spojení vo viacvláknovom prostredí DbContext s ThreadLocal nemusíme stále opakovať argument Connection každé vlákno si uchováva svoje vlastné spojenie vhodné aj pre viacvláknovú aplikáciu

Uchovávanie si spojení vo viacvláknovom prostredí Odkiaľ sa vezme DataSource? class TransferHandler implements HttpHandler { void handle(httpexchange exchange) { String query = exchange.getrequesturi().getquery(); String source = // vytiahni argument z query String destination // vytiahni argument z query BigDecimal amount = // vytiahni argument z query // odkial sa vezme datasource? DbContext.setConnection(dataSource.getConnection()); Banking.transfer(source, destination, amount); DbContext.closeConnection();

Uchovávanie si spojení vo viacvláknovom prostredí static void closeconnection() { if (connection.get()!= null) { connection.get().close(); connection.set(null); DataSource v DbContext class DbContext { static DataSource ds; static ThreadLocal<Connection> connection = new ThreadLocal<>(); static void setdatasource(datasource d) { ds = d; static Connection getconnection() { if (connection.get() == null) { connection.set(ds.getconnection()); return connection.get();

Uchovávanie si spojení vo viacvláknovom prostredí Backend Vytvorenie DataSource class Backend { static void main() { // bezi na localhost:8000 PgSimpleDataSource ds = new PgSimpleDataSource(); ds.setservername("server name"); ds.setservername("database name"); ds.setportnumber(5432); ds.setuser("user"); ds.setpassword("password"); DbContext.setDataSource(ds); HttpServer server = HttpServer.create(new InetSocketAddress(8000),0); server.createcontext("/transfer", new TransferHandler()); server.setexecutor(executors.newcachedthreadpool()); server.start();

Uchovávanie si spojení vo viacvláknovom prostredí Backend Vytváranie a zatváranie spojenia class TransferHandler implements HttpHandler { void handle(httpexchange exchange) { String query = exchange.getrequesturi().getquery(); String source = // vytiahni argument z query String destination // vytiahni argument z query BigDecimal amount = // vytiahni argument z query // cez DbContext.getConnection() // ziska nove spojenie Banking.transfer(source, destination, amount); // zatvori spojenie DbContext.closeConnection();

Uchovávanie si spojení vo viacvláknovom prostredí Koniec Koniec