{"id":79465,"date":"2020-04-27T07:42:20","date_gmt":"2020-04-27T05:42:20","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh"},"modified":"2020-04-27T07:42:20","modified_gmt":"2020-04-27T05:42:20","slug":"istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh","status":"publish","type":"post","link":"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh","title":{"rendered":"Resnica je na prvem mestu, ali zakaj je treba sistem na\u010drtovati ob upo\u0161tevanju strukture baze podatkov","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Hello, Habr!<\/p>\n<p>Nadaljujemo z raziskovanjem teme <noindex><a rel=\"nofollow\" href=\"https:\/\/www.piter.com\/collection\/all\/product\/sovremennyy-yazyk-java-lyambda-vyrazheniya-potoki-i-funktsionalnoe-programmirovanie\">Java<\/a><\/noindex> in <noindex><a rel=\"nofollow\" href=\"https:\/\/storage.piter.com\/upload\/contents\/978544611587\/978544611587_X.pdf\">Spring<\/a><\/noindex>, vklju\u010dno na ravni podatkovnih baz. Danes vam priporo\u010damo, da preberete, zakaj bi pri na\u010drtovanju velikih aplikacij struktura podatkovne baze, ne pa Java koda, morala imeti odlo\u010dilno vlogo, kako se to po\u010dne in kak\u0161ne izjeme obstajajo pri tem pravilu.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex> <br \/>\nV tem precej zamujenem \u010dlanku bom razlo\u017eil, zakaj menim, da bi morala biti v skoraj vseh primerih model podatkov v aplikaciji na\u010drtovana 'izhajajo\u010d iz podatkovne baze', ne pa 'izhajajo\u010d iz zmo\u017enosti Java' (ali drugega odjemal\u010dnega jezika, s katerim delate). Z izbiro drugega pristopa vstopite na dolgo pot bole\u010dine in trpljenja, takoj ko se va\u0161 projekt za\u010dne \u0161iriti.<\/p>\n<p>\u010clanek je napisan na podlagi <noindex><a rel=\"nofollow\" href=\"https:\/\/stackoverflow.com\/questions\/50706556\/kotlin-with-jooq-and-write-table-models-manually-without-code-generation\">enega vpra\u0161anja<\/a><\/noindex>, postavljenega na Stack Overflow.<\/p>\n<p>Zanimive razprave na redditu v oddelkih <noindex><a rel=\"nofollow\" href=\"https:\/\/www.reddit.com\/r\/java\/comments\/8p0uj3\/truth_first_or_why_you_should_mostly_implement\/\">\/r\/java<\/a><\/noindex> in <noindex><a rel=\"nofollow\" href=\"https:\/\/www.reddit.com\/r\/programming\/comments\/8p0qle\/truth_first_or_why_you_should_mostly_implement\/\">\/r\/programming<\/a><\/noindex>.<\/p>\n<h4>Generiranje kode<\/h4>\n<p>\nKoliko presene\u010den sem bil, da obstaja tako majhna plast uporabnikov, ki so ob spoznanju jOOQ razburjeni zaradi dejstva, da jOOQ pri delu resno zana\u0161a na generiranje izvorne kode. Nih\u010de vam ne prepre\u010duje, da bi jOOQ uporabljali, kot menite, da je prav, in vas ne sili k uporabi generiranja kode. Vendar pa po privzetku (kot opisano v priro\u010dniku) delo z jOOQ poteka tako: za\u010dnete s (dedovano) shemo podatkovne baze, izvedete njeno obratno in\u017eenirstvo s pomo\u010djo generatorja kode jOOQ, da pridobite nabor razredov, ki predstavljajo va\u0161e tabele, nato pa pi\u0161ete tipizirane poizvedbe v te tabele:<\/p>\n<pre><code class=\"java\">\tfor (Record2 record : DSL.using(configuration)\n\/\/   ^^^^^^^^^^^^^^^^^^^^^^^ Informacije o tipih so bile dolo\u010dene na \n\/\/   podlagi generirane kode, na katero se nana\u0161a navedena\n\/\/   spodaj pogoj SELECT \n \n       .select(ACTOR.FIRST_NAME, ACTOR.LAST_NAME)\n\/\/           vvvvv ^^^^^^^^^^^^  ^^^^^^^^^^^^^^^ generirana imena\n       .from(ACTOR)\n       .orderBy(1, 2)) {\n    \/\/ ...\n}<\/code><\/pre>\n<p>\nKoda se generira bodisi ro\u010dno zunaj zbirk bodisi ro\u010dno pri vsaki zbirki. Na primer, taka regeneracija lahko sledi takoj po <noindex><a rel=\"nofollow\" href=\"https:\/\/blog.jooq.org\/2014\/06\/25\/flyway-and-jooq-for-unbeatable-sql-development-productivity\/\">migraciji podatkovne baze Flyway, ki jo je prav tako mogo\u010de izvesti ro\u010dno ali samodejno.<\/a><\/noindex>.<\/p>\n<h4>Generiranje izvorne kode<\/h4>\n<p>\nS takimi pristopi k generaciji kode \u2013 ro\u010dnimi in avtomatskimi \u2013 so povezane razli\u010dne filozofije, prednosti in slabosti, o katerih se v tem \u010dlanku ne nameravam podrobno razpravljati. V splo\u0161nem je bistvo generiranega kode v tem, da nam omogo\u010da, da na Javi rekonstruiramo to 'resnico', ki jo sprejemamo kot samoumevno, bodisi v okviru na\u0161ega sistema bodisi izven njega. V nekem smislu to po\u010dnejo tudi prevajalniki, ki generirajo bajtno kodo, strojno kodo ali kakr\u0161no koli drugo vrsto kode na podlagi izvornih datotek \u2013 dobimo predstavitev na\u0161e 'resnice' v drugem jeziku, ne glede na konkretne razloge. <\/p>\n<p>Obstaja mnogo takih generatorjev kode. Na primer, <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/technotes\/tools\/unix\/xjc.html\">XJC lahko generira kode Java na osnovi datotek XSD ali WSDL<\/a><\/noindex>. Na\u010delo je vedno enako:<\/p>\n<ul>\n<li>Obstaja neka resnica (notranja ali zunanja) \u2013 na primer, specifikacija, model podatkov itd.<\/li>\n<li>Potrebujemo lokalno predstavitev te resnice v na\u0161em programskem jeziku.<\/li>\n<\/ul>\n<p>\nPrav tako je skoraj vedno smiselno generirati to predstavitev \u2013 da se izognemo odve\u010dnosti.<\/p>\n<h4>Povezovalci tipov in obdelava anotacij<\/h4>\n<p>\nZa opombo: \u0161e en, bolj sodoben in specifi\u010den pristop k generaciji kode za jOOQ je povezan z uporabo povezovalcev tipov, <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/fsharp\/tutorials\/type-providers\/\">v obliki, kot so implementirani v F#<\/a><\/noindex>. V tem primeru generira kodo prevajalnik, in sicer v fazi prevajanja. Tak\u0161na koda na\u010deloma ne obstaja v obliki izvornih datotek. V Javi obstajajo podobna orodja, \u010deprav ne tako elegantna \u2013 to so obdelovalniki anotacij, na primer, <noindex><a rel=\"nofollow\" href=\"https:\/\/projectlombok.org\">Lombok<\/a><\/noindex>.<\/p>\n<p>V nekem smislu se tukaj dogajajo iste stvari kot v prvem primeru, razen:<\/p>\n<ul>\n<li>Ne vidite generirane kode (morda se zdi ta situacija nekaterim ne tako odvratna?)<\/li>\n<li>Morate zagotoviti, da so tipi na voljo, torej, 'resnica' mora biti vedno dostopna. To je preprosto v primeru Lombok, ki anotira 'resnico'. Malce bolj zapleteno je z modeli baz podatkov, katerih delovanje je odvisno od nenehno dostopne \u017eive povezave.<\/li>\n<\/ul>\n<p><\/p>\n<h4>Kak\u0161en je problem z generacijo kode?<\/h4>\n<p>\nPoleg premetne in subtilne debate o tem, kako najbolje zagnati generacijo kode \u2013 ro\u010dno ali avtomatsko, je treba omeniti, da so nekateri mnenja, da generacija kode sploh ni potrebna. Najpogostej\u0161i razlog za to stali\u0161\u010de je, da je te\u017eko nastaviti proces zbiranja. Da, res je te\u017eko. Pojavijo se dodatne infrastrukturne stro\u0161ke. \u010ce \u0161ele za\u010dnete delati z dolo\u010denim produktom (naj bo to jOOQ, JAXB, Hibernate itd.), to, da porabite \u010das za nastavitev delovnega okolja, pomeni, da ne morete \u0161tudirati samega API-ja, da bi kasneje iz njega izlu\u0161\u010dili vrednost.<\/p>\n<p>\u010ce so stro\u0161ki preveliki, ker se morate u\u010diti o delovanju generatorja \u2013 potem res API ni dobro delal na uporabni\u0161ki prijaznosti generatorja (in kmalu se izka\u017ee, da je tudi uporabni\u0161ka nastavitev v njem zapletena). Udobje uporabe bi moralo biti najvi\u0161ja prioriteta za vsak tak API. Vendar je to le en argument proti generaciji kode. V drugih stvareh je povsem mo\u017eno ro\u010dno napisati lokalno predstavitev notranje ali zunanje resnice.<\/p>\n<p>Mnogi bodo rekli, da nimajo \u010dasa za to. Imajo roke za svoj Super-Produkt. Kdaj drugi\u010d se bomo posvetili procesom zbiranja, bomo imeli \u010das. Odgovorim jim:<\/p>\n<p><img decoding=\"async\" alt=\"Resnica je na prvem mestu, ali zakaj je treba sistem na\u010drtovati ob upo\u0161tevanju strukture baze podatkov\" src=\"\/wp-content\/uploads\/2020\/04\/cd9aca1e0365fa5af28cfc72c201cb8c.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/www.flickr.com\/photos\/toddle_email_newsletters\/15596940251\/in\/photostream\/\">Izvirnik<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"http:\/\/audiencestack.com\/static\/blog.html\">Alan O\u2019Rurke, Audience Stack<\/a><\/noindex> <\/p>\n<p><b>Ampak v Hibernate \/ JPA je res enostavno pisati kodo 'pod Java'. <\/b><\/p>\n<p>Res je. Za Hibernate in njegove uporabnike je to hkrati blagoslov in prekletstvo. V Hibernate lahko enostavno napi\u0161ete nekaj entitet, na ta na\u010din:<\/p>\n<pre><code class=\"java\">\t@Entity\nclass Book {\n  @Id\n  int id;\n  String title;\n}<\/code><\/pre>\n<p>\nIn skoraj vse je pripravljeno. Zdaj je naloga Hibernate-a, da generira kompleksne 'detajle' o tem, kako natan\u010dno bo ta entiteta definirana v DDL va\u0161ega 'dialekta' SQL:<\/p>\n<pre><code class=\"sql\">\tCREATE TABLE book (\n  id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,\n  title VARCHAR(50),\n \n  CONSTRAINT pk_book PRIMARY KEY (id)\n);\n \nCREATE INDEX i_book_title ON book (title);<\/code><\/pre>\n<p>\n\u2026 in za\u010dnemo poganjati aplikacijo. Res kul mo\u017enost, da hitro za\u010dnemo delati in preizku\u0161amo razli\u010dne stvari.<\/p>\n<p>Vendar, dovolite, da se vrnem nazaj. Malce sem zavajal.<\/p>\n<ul>\n<li>Ali Hibernate res uporabi definicijo tega poimenovanega primarnega klju\u010da?<\/li>\n<li>Ali Hibernate ustvari indeks v TITLE? \u2013 sem prepri\u010dan, da ga bomo potrebovali. <\/li>\n<li>Ali Hibernate zagotovo naredi ta klju\u010d identifikacijski v Identity Specifikaciji?<\/li>\n<\/ul>\n<p>\nVerjetno ne. \u010ce svoj projekt razvijate iz ni\u010d, je vedno priro\u010dno preprosto zavre\u010di staro bazo podatkov in ustvariti novo, takoj ko dodate potrebne anotacije. Tako bo entiteta Book na koncu izgledala: <\/p>\n<pre><code class=\"java\">\t@Entity\n@Table(name = \"book\", indexes = {\n  @Index(name = \"i_book_title\", columnList = \"title\")\n})\nclass Book {\n  @Id\n  @GeneratedValue(strategy = IDENTITY)\n  int id;\n  String title;\n}\n<\/code><\/pre>\n<p>\nSuper. Ponovno generiraj. Spet, v takem primeru bo na za\u010detku zelo enostavno.<\/p>\n<h4>A vendar boste na koncu morali za to pla\u010dati.<\/h4>\n<p>\nPrej ali slej boste morali iti v produkcijo. \u0160ele takrat ta model preneha delovati. Kajti: <\/p>\n<p>V produkciji ne boste ve\u010d mogli, \u010de bo potrebno, zavre\u010di staro bazo podatkov in za\u010deti znova z ni\u010dle. Va\u0161a baza podatkov se bo spremenila v dedi\u0161\u010dinsko.<\/p>\n<p>Od zdaj naprej boste morali pisati <noindex><a rel=\"nofollow\" href=\"https:\/\/blog.jooq.org\/2014\/06\/25\/flyway-and-jooq-for-unbeatable-sql-development-productivity\/\">DDL migracijske skripte, na primer, z uporabo Flyway.<\/a><\/noindex>. Kaj se potem zgodi z va\u0161imi entitetami? Lahko jih ro\u010dno prilagodite (in si tako podvojite obseg dela), ali pa naro\u010dite Hibernate, da jih ponovno generira za vas (kako velika je mo\u017enost, da bo tako generiran ustrezal va\u0161im pri\u010dakovanjem?) Tako ali tako ste na slabem.<\/p>\n<p>Tako boste, ko preidete v produkcijo, potrebovali hitre popravke. Te je treba hitro izvesti v produkciji. Ker se niste pripravili in organizirali gladke konvejerizacije va\u0161ih migracij za produkcijo, boste vse grobo popravili. In nato ne boste imeli \u010dasa, da bi to pravilno opravili. In obto\u017eujete Hibernate, ker je vedno kriv kdo drug, samo vi ne...<\/p>\n<p>Namesto tega bi lahko vse od za\u010detka po\u010deli povsem druga\u010de. Na primer, namestite kroglice na kolo.<\/p>\n<h4>Sprva baza podatkov.<\/h4>\n<p>\nPrava 'resnica' v shemi va\u0161e baze podatkov in 'suverenost' nad njo le\u017ei znotraj baze podatkov. Shema je dolo\u010dena le v sami bazi podatkov in nikjer drugje, in vsak od strank ima kopijo te sheme, zato je povsem smiselno uvesti spo\u0161tovanje sheme in njeno celovitost, to izvajati neposredno v bazi podatkov - tam, kjer se shranjujejo informacije. <br \/>\nTo je stara, celo izpiljena modrost. Primarni in unikatni klju\u010di so dobri. Zunanji klju\u010di so dobri. Preverjanje omejitev je dobro. <noindex><a rel=\"nofollow\" href=\"https:\/\/community.oracle.com\/ideas\/13028\">Navedbe<\/a><\/noindex> so dobre. <\/p>\n<p>In addition, this is not everything. For example, when using Oracle, you will likely want to specify:<\/p>\n<ul>\n<li>In which tablespace your table resides <\/li>\n<li>What is its PCTFREE value <\/li>\n<li>What is the cache size in your sequence (after the identifier)<\/li>\n<\/ul>\n<p>\nPerhaps all this isn't important in small systems, but you don't necessarily have to wait for the transition to 'big data' \u2014 you can start benefiting from the optimizations provided by the vendor much earlier, such as the ones mentioned above. None of the ORMs I've seen (including jOOQ) provide access to the full range of DDL options that you might want to use in your database. ORMs offer some tools that help write DDL.<\/p>\n<p>But in the end, a well-designed schema is manually written in DDL. Any generated DDL is just an approximation of it.<\/p>\n<h4>What about the client model?<\/h4>\n<p>\nAs mentioned above, on the client side, you will need a copy of your database schema, a client view. It's unnecessary to mention that this client view must be synchronized with the actual model. How can this best be achieved? By using a code generator.<\/p>\n<p>All databases provide their metadata via SQL. Here\u2019s how to obtain all tables from your database in various SQL dialects:<\/p>\n<pre><code class=\"sql\">\t-- H2, HSQLDB, MySQL, PostgreSQL, SQL Server\nSELECT table_schema, table_name\nFROM information_schema.tables\n \n-- DB2\nSELECT tabschema, tabname\nFROM syscat.tables\n \n-- Oracle\nSELECT owner, table_name\nFROM all_tables\n \n-- SQLite\nSELECT name\nFROM sqlite_master\n \n-- Teradata\nSELECT databasename, tablename\nFROM dbc.tables\n<\/code><\/pre>\n<p>\nThese queries (or similar ones, depending on whether views, materialized views, or table-valued functions also need to be considered) are also executed using the call <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.oracle.com\/javase\/10\/docs\/api\/java\/sql\/DatabaseMetaData.html#getTables(java.lang.String,java.lang.String,java.lang.String,java.lang.String%5B%5D)\"><code>DatabaseMetaData.getTables()<\/code><\/a><\/noindex> from JDBC, or through the jOOQ meta-module.<\/p>\n<p>From the results of such queries, it is relatively easy to generate any client view of your database model, regardless of what technology you are using on the client side.<\/p>\n<ul>\n<li>If you are using JDBC or Spring, you can create a set of string constants <\/li>\n<li>If you are using JPA, you can generate the entities yourself <\/li>\n<li>If you are using jOOQ, you can generate the jOOQ meta-model<\/li>\n<\/ul>\n<p>\nGlede na to, koliko mo\u017enosti ponuja va\u0161 odjemalski API (npr. jOOQ ali JPA), lahko generirani meta model postane res bogat in celovit. Vzemimo na primer mo\u017enost implicitnih zdru\u017eitev, <noindex><a rel=\"nofollow\" href=\"https:\/\/blog.jooq.org\/2018\/02\/20\/type-safe-implicit-join-through-path-navigation-in-jooq-3-11\/\">ki je bila uvedena v jOOQ 3.11<\/a><\/noindex>, ki se opira na generirane meta informacije o odnosih zunanjih klju\u010dev, ki veljajo med va\u0161imi tabelami.<\/p>\n<p>Zdaj bo vsako pove\u010danje baze podatkov samodejno privedlo do posodobitve odjemalske kode. Predstavljajte si na primer:<\/p>\n<pre><code class=\"sql\">ALTER TABLE book RENAME COLUMN title TO book_title;<\/code><\/pre>\n<p>\nAli res \u017eelite to delo opraviti dvakrat? Seveda ne. Preprosto zabele\u017eimo DDL, ga preusmerimo skozi va\u0161 gradbeni proces in dobimo posodobljeno entiteto:<\/p>\n<pre><code class=\"java\">@Entity\n@Table(name = \"book\", indexes = {\n \n  \/\/ Ste se o tem kdaj zamislili?\n  @Index(name = \"i_book_title\", columnList = \"book_title\")\n})\nclass Book {\n  @Id\n  @GeneratedValue(strategy = IDENTITY)\n  int id;\n \n  @Column(\"book_title\")\n  String bookTitle;\n}<\/code><\/pre>\n<p>\nAli posodobljen razred jOOQ. Ve\u010dina sprememb DDL se odra\u017ea tudi na semantiki, ne samo na sintaksi. Zato je v\u010dasih priro\u010dno pogledati v skompilirano kodo, katera koda bo (ali bi lahko bila) prizadeta pri pove\u010danju va\u0161e baze podatkov.<\/p>\n<h4>Edina resnica<\/h4>\n<p>\nNe glede na tehnologijo, ki jo uporabljate, vedno obstaja en model, ki je edini vir resnice za neko podskupino \u2013 ali, vsaj, stremimo k temu in se izogibamo tak\u0161ni podjetni\u0161ki zmedi, kjer je \"resnica\" naletela povsod in nikjer. Vse bi bilo lahko precej preprosto. \u010ce samo izmenjujete datoteke XML z drugo sistemom, preprosto uporabite XSD. Oglejte si meta-model INFORMATION_SCHEMA iz jOOQ v XML obliki:<br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/www.jooq.org\/xsd\/jooq-meta-3.10.0.xsd\">https:\/\/www.jooq.org\/xsd\/jooq-meta-3.10.0.xsd<\/a><\/noindex><\/p>\n<ul>\n<li>XSD je dobro razumljiv<\/li>\n<li>XSD zelo dobro ozna\u010duje vsebino XML in omogo\u010da validacijo v vseh odjemalskih jezikih <\/li>\n<li>XSD dobro razli\u010dicira in ima razvito obratno zdru\u017eljivost <\/li>\n<li>XSD se lahko pretvori v Java kodo s pomo\u010djo XJC<\/li>\n<\/ul>\n<p>\nZadnji punkt je pomemben. Pri komunikaciji z zunanjim sistemom z uporabo XML-sporo\u010dil \u017eelimo biti prepri\u010dani o veljavnosti na\u0161ih sporo\u010dil. To je zelo enostavno dose\u010di z uporabo JAXB, XJC in XSD. Bilo bi popolnoma noro pri\u010dakovati, da bi pri pristopu k oblikovanju \u201enajprej Java\u201c, kjer sporo\u010dila ustvarjamo kot Java objekte, bilo mogo\u010de na kakr\u0161en koli smiseln na\u010din prevesti te v XML in jih poslati v drug sistem. XML, ustvarjen na ta na\u010din, bi bil zelo slabe kakovosti, brez dokumentacije in te\u017eko raz\u0161irljiv. \u010ce bi za tak\u0161no vmesnik obstajala dogovor o ravni storitev (SLA), bi ga takoj pokvarili.<\/p>\n<p>Iskreno, prav to se nenehno dogaja z API-ji na JSON, vendar je to \u017ee druga zgodba, naslednji\u010d se bom jezil... <\/p>\n<h4>Baze podatkov: to je isto<\/h4>\n<p>\nKo delate z bazami podatkov, razumete, da so vse v bistvu podobne. Baza obvladuje svoje podatke in mora upravljati shemo. Vse spremembe, ki jih uvedete v shemo, morajo biti izvedene neposredno na DDL, da se posodobi enotni vir resnice.<\/p>\n<p>Ko se posodobitev vira zgodi, morajo tudi vsi klienti posodobiti svoje kopije modela. Nekateri klienti so lahko napisani v Javi z uporabo jOOQ in Hibernate ali JDBC (ali vse naenkrat). Drugi klienti so lahko napisani v Perl (ostavlja jim sre\u010do), tretji \u2013 v C#. To ni pomembno. Glavni model se nahaja v bazi podatkov. V modelih, generiranih z ORM, je obi\u010dajno slaba kakovost, slabo dokumentirano in te\u017eko jih je razvijati.<\/p>\n<p>Zato ne delajte napak. Od samega za\u010detka ne delajte napak. Delajte na podlagi baze podatkov. Zgradite tak\u0161no infrastrukturo za razporejanje, ki jo je mogo\u010de avtomatizirati. Vklju\u010dite generatorje kode, da boste lahko enostavno kopirali model va\u0161e baze podatkov in ga prenesli na kliente. In prenehajte skrbeti za generatorje kode. So dobri. S tem boste postali produktivnej\u0161i. Samo na za\u010detku morate nameniti nekaj \u010dasa za njihovo nastavitev \u2013 in potem vas \u010dakajo leta pove\u010dane produktivnosti, iz katerih se bo razvila zgodba va\u0161ega projekta.<\/p>\n<p>Zaenkrat se ne zahvaljujte, kasneje.<\/p>\n<h4>Obja\u0161njenje<\/h4>\n<p>\nZa jasno\u0107u: Ovaj \u010dlanak nikako ne propagira ideju da se kompletan sistem (tj. predmetna oblast, poslovna logika itd.) mora prilagoditi modelu va\u0161e baze podataka. U ovom \u010dlanku govorim o tome da klijentski kod koji komunicira sa bazom podataka treba delovati na osnovu modela baze podataka, kako se sam ne bi reprodukovao kao model baze podataka prvog reda. Ova logika obi\u010dno se nalazi na nivou pristupa podacima na va\u0161em klijentu.<\/p>\n<p>U dvojnim arhitekturama, koje se jo\u0161 uvek ponegde zadr\u017eavaju, ovakav sistemski model mo\u017ee biti jedini mogu\u0107. Me\u0111utim, u ve\u0107ini sistema, nivo pristupa podacima izgleda kao 'podsystem', koji inkapsulira model baze podataka.<\/p>\n<h4>Izjeme<\/h4>\n<p>\nSvako pravilo ima svoje izuzetke, i ve\u0107 sam spomenuo da pristup s primarno\u0161\u0107u baze podataka i generisanjem izvornog koda ponekad mo\u017ee biti neodgovaraju\u0107i. Evo nekoliko takvih izuzetaka (verovatno \u0107e ih biti i vi\u0161e):<\/p>\n<ul>\n<li>Kada je \u0161ema nepoznata, i treba je otvoriti. Na primer, vi ste pru\u017eatelj alata koji poma\u017ee korisnicima da se snalaze u bilo kojoj \u0161emi. Uf. Tu bez generisanja koda. Ali, opet \u2013 baza podataka je prvo.<\/li>\n<li>Kada \u0161ema treba biti generisana u hodu za re\u0161avanje odre\u0111enog zadatka. Ovaj primer izgleda kao malo pretenciozna verzija obrasca <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Entity%E2%80%93attribute%E2%80%93value_model\">entity attribute value<\/a><\/noindex>, tj. vi zapravo nemate jasno definisanu \u0161emu. U ovom slu\u010daju \u010desto ne mo\u017ee biti sigurno da \u0107e vam odgovarati RDBMS.<\/li>\n<\/ul>\n<p>\nIzuzeci po svojoj prirodi su izuzetni. U ve\u0107ini slu\u010dajeva vezanih za kori\u0161\u0107enje RDBMS, \u0161ema je unapred poznata, nalazi se unutar RDBMS i predstavlja jedini izvor 'istine', dok svi klijenti moraju nabaviti kopije izvedene iz nje. Idealno bi bilo u ovom slu\u010daju anga\u017eovati generator koda.<br \/>\n<br \/>Izvor: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/piter\/blog\/498816\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043c\u0443 Java \u0438 Spring, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435, \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043e \u0442\u043e\u043c, \u043f\u043e\u0447\u0435\u043c\u0443 \u043f\u0440\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438\u043c\u0435\u043d\u043d\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u043d\u0435 \u043a\u043e\u0434 Java, \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u043c\u0435\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043a\u0430\u043a \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f, \u0438 \u043a\u0430\u043a\u0438\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0435\u0441\u0442\u044c \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430. \u0412 \u044d\u0442\u043e\u0439 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0437\u0430\u043f\u043e\u0437\u0434\u0430\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043e\u0431\u044a\u044f\u0441\u043d\u044e, [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":79466,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-79465","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.4 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043c\u0443\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"sl_SI\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0418\u0441\u0442\u0438\u043d\u0430 \u043f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u0438\u043b\u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043c\u0443\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-04-27T05:42:20+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-04-27T05:42:20+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Istina pre svega, ili za\u0161to sistem treba projektovati uzimaju\u0107i u obzir strukturu baze podataka | ProHoster","description":"Zdravo, Habr! Nastavljamo istra\u017eivanje teme","canonical_url":"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sl_SI","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0418\u0441\u0442\u0438\u043d\u0430 \u043f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u0438\u043b\u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 | ProHoster","og:description":"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043c\u0443","og:url":"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-04-27T05:42:20+00:00","article:modified_time":"2020-04-27T05:42:20+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"79465","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 16:37:24","updated":"2022-09-29 16:13:15","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts\/79465","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/comments?post=79465"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts\/79465\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/media\/79466"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/media?parent=79465"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/categories?post=79465"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/tags?post=79465"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}