{"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\/de\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh","title":{"rendered":"Wahrheit zuerst: Warum Systeme unter Ber\u00fccksichtigung der Datenbankstruktur entworfen werden m\u00fcssen","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Hallo, Habr!<\/p>\n<p>Wir setzen unsere Erforschung des Themas fort <noindex><a rel=\"nofollow\" href=\"https:\/\/www.piter.com\/collection\/all\/product\/sovremennyy-yazyk-java-lyambda-vyrazheniya-potoki-i-funktsionalnoe-programmirovanie\">Java<\/a><\/noindex> und <noindex><a rel=\"nofollow\" href=\"https:\/\/storage.piter.com\/upload\/contents\/978544611587\/978544611587_X.pdf\">Spring<\/a><\/noindex>, einschlie\u00dflich auf Datenbankebene. Heute m\u00f6chten wir Ihnen erl\u00e4utern, warum bei der Gestaltung gro\u00dfer Anwendungen die Struktur der Datenbank, nicht der Java-Code, entscheidend sein sollte, wie dies umgesetzt wird und welche Ausnahmen es von dieser Regel gibt.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex> <br \/>\nIn diesem etwas versp\u00e4teten Artikel erkl\u00e4re ich, warum ich denke, dass das Datenmodell in einer Anwendung in den meisten F\u00e4llen \"von der Datenbank aus\" und nicht \"von den M\u00f6glichkeiten von Java\" (oder einer anderen Programmiersprache, mit der Sie arbeiten) entworfen werden sollte. Wenn Sie den zweiten Ansatz w\u00e4hlen, begeben Sie sich auf einen langen Weg voller Schmerzen und Herausforderungen, sobald Ihr Projekt zu wachsen beginnt.<\/p>\n<p>Dieser Artikel basiert auf <noindex><a rel=\"nofollow\" href=\"https:\/\/stackoverflow.com\/questions\/50706556\/kotlin-with-jooq-and-write-table-models-manually-without-code-generation\">einer Frage<\/a><\/noindex>, die auf Stack Overflow gestellt wurde.<\/p>\n<p>Interessante Diskussionen auf reddit in den Bereichen <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> und <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>Code-Generierung<\/h4>\n<p>\nIch war wirklich \u00fcberrascht, dass es eine so kleine Gruppe von Nutzern gibt, die sich \u00fcber die Tatsache emp\u00f6ren, dass jOOQ ernsthaft auf die Codegenerierung angewiesen ist. Niemand hindert Sie daran, jOOQ so zu verwenden, wie Sie es f\u00fcr richtig halten, und niemand zwingt Sie zur Codegenerierung. Aber standardm\u00e4\u00dfig (wie im Handbuch beschrieben) funktioniert die Arbeit mit jOOQ so: Sie beginnen mit einem (vererbbare) Datenbankschema, f\u00fchren dessen Reverse Engineering mit dem jOOQ-Codegenerator durch, um so eine Reihe von Klassen zu erhalten, die Ihre Tabellen repr\u00e4sentieren, und dann schreiben Sie typensichere Abfragen an diese Tabellen:<\/p>\n<pre><code class=\"java\">\tfor (Record2 record : DSL.using(configuration)\n\/\/   ^^^^^^^^^^^^^^^^^^^^^^^ Typinformationen stammen aus \n\/\/   dem generierten Code, auf den sich die\n\/\/   folgende SELECT-Anweisung bezieht\n\n       .select(ACTOR.FIRST_NAME, ACTOR.LAST_NAME)\n\/\/           vvvvv ^^^^^^^^^^^^  ^^^^^^^^^^^^^^^ generierte Namen\n       .from(ACTOR)\n       .orderBy(1, 2)) {\n    \/\/ ...\n}<\/code><\/pre>\n<p>\nDer Code wird entweder manuell au\u00dferhalb des Builds oder manuell bei jedem Build generiert. Zum Beispiel kann eine solche Regenerierung sofort nach <noindex><a rel=\"nofollow\" href=\"https:\/\/blog.jooq.org\/2014\/06\/25\/flyway-and-jooq-for-unbeatable-sql-development-productivity\/\">Datenbankmigration mit Flyway, die sowohl manuell als auch automatisch durchgef\u00fchrt werden kann.<\/a><\/noindex>.<\/p>\n<h4>Generierung von Quellcode<\/h4>\n<p>\nMit diesen Ans\u00e4tzen zur Code-Generierung \u2013 sowohl manuell als auch automatisch \u2013 sind verschiedene Philosophien, Vorteile und Nachteile verbunden, die ich in diesem Artikel nicht im Detail er\u00f6rtern m\u00f6chte. Im Grunde genommen geht es bei generiertem Code darum, dass er es erm\u00f6glicht, in Java jene 'Wahrheit' zu reproduzieren, die wir als gegeben akzeptieren, sei es innerhalb oder au\u00dferhalb unseres Systems. In gewisser Weise leisten Compiler, die Bytecode, Maschinencode oder eine andere Art von Code aus den Quellcodes generieren, dasselbe \u2013 wir erhalten eine Darstellung unserer 'Wahrheit' in einer anderen Sprache, unabh\u00e4ngig von den spezifischen Gr\u00fcnden. <\/p>\n<p>Es gibt eine Vielzahl solcher Code-Generatoren. Zum Beispiel, <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/technotes\/tools\/unix\/xjc.html\">XJC kann Java-Code basierend auf XSD- oder WSDL-Dateien generieren.<\/a><\/noindex>Das Prinzip ist immer dasselbe:<\/p>\n<ul>\n<li>Es gibt eine gewisse Wahrheit (intern oder extern) \u2013 beispielsweise eine Spezifikation, ein Datenmodell usw.<\/li>\n<li>Wir ben\u00f6tigen eine lokale Darstellung dieser Wahrheit in unserer Programmiersprache.<\/li>\n<\/ul>\n<p>\nEs ist oft sinnvoll, eine solche Darstellung zu generieren, um Redundanz zu vermeiden.<\/p>\n<h4>Typen-Provider und Annotationenverarbeitung<\/h4>\n<p>\nHinweis: Ein weiterer, modernerer und spezifischerer Ansatz zur Codegenerierung f\u00fcr jOOQ bezieht sich auf die Nutzung von Typen-Providern, <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/fsharp\/tutorials\/type-providers\/\">so wie sie in F# umgesetzt sind.<\/a><\/noindex>In diesem Fall wird der Code vom Compiler w\u00e4hrend des Kompilierungsprozesses generiert. In Form von Quellcode existiert dieser Code grunds\u00e4tzlich nicht. In Java gibt es \u00e4hnliche, wenn auch weniger elegante Werkzeuge \u2013 diese sind die Annotation-Prozessoren, zum Beispiel, <noindex><a rel=\"nofollow\" href=\"https:\/\/projectlombok.org\">Lombok<\/a><\/noindex>.<\/p>\n<p>In gewissem Sinne geschieht hier dasselbe wie im ersten Fall, mit der Ausnahme:<\/p>\n<ul>\n<li>Sie sehen den generierten Code nicht (vielleicht erscheint diese Situation f\u00fcr einige nicht so abweisend?).<\/li>\n<li>Sie m\u00fcssen garantieren, dass Typen bereitgestellt werden k\u00f6nnen, das hei\u00dft, 'Wahrheit' muss immer verf\u00fcgbar sein. Das ist einfach im Falle von Lombok, das 'Wahrheit' annotiert. Etwas komplizierter wird es mit Datenbankmodellen, deren Funktion auf einer st\u00e4ndig verf\u00fcgbaren, aktiven Verbindung beruht.<\/li>\n<\/ul>\n<p><\/p>\n<h4>Was ist das Problem bei der Codegenerierung?<\/h4>\n<p>\nNeben der komplexen Frage, wie man die Codegenerierung am besten startet \u2013 manuell oder automatisch \u2013, muss auch erw\u00e4hnt werden, dass es Menschen gibt, die der Meinung sind, dass die Codegenerierung \u00fcberhaupt nicht notwendig ist. Die am h\u00e4ufigsten geh\u00f6rte Begr\u00fcndung f\u00fcr diese Sichtweise ist, dass es dann schwierig ist, die Build-Pipeline einzurichten. Ja, das ist in der Tat eine Herausforderung. Es entstehen zus\u00e4tzliche infrastrukturelle Kosten. Wenn Sie gerade erst mit einem bestimmten Produkt beginnen (sei es jOOQ, JAXB oder Hibernate usw.), ben\u00f6tigt die Einrichtung der Entwicklungsumgebung Zeit, die Sie lieber in das Erlernen der API investieren w\u00fcrden, um sp\u00e4ter davon profitieren zu k\u00f6nnen.<\/p>\n<p>Wenn die Kosten f\u00fcr das Verst\u00e4ndnis der Funktionsweise des Generators zu hoch sind, dann wurde in der API tats\u00e4chlich schlecht an der Benutzerfreundlichkeit des Code-Generators gearbeitet (was sich sp\u00e4ter als auch schwierig f\u00fcr die Benutzeranpassung herausstellt). Die Benutzerfreundlichkeit sollte die oberste Priorit\u00e4t f\u00fcr jede solche API haben. Aber das ist nur ein Argument gegen die Code-Generierung. Ansonsten ist es absolut notwendig, die lokale Darstellung interner oder externer Wahrheiten vollst\u00e4ndig manuell zu erstellen.<\/p>\n<p>Viele werden sagen, dass sie keine Zeit daf\u00fcr haben. Ihre Fristen f\u00fcr das Super-Produkt brennen. Irgendwann werden wir die Montageb\u00e4nder \u00fcberarbeiten, dazu bleibt Zeit. Ich antworte ihnen:<\/p>\n<p><img decoding=\"async\" alt=\"Wahrheit zuerst: Warum Systeme unter Ber\u00fccksichtigung der Datenbankstruktur entworfen werden m\u00fcssen\" 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\/\">Original<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"http:\/\/audiencestack.com\/static\/blog.html\">Alan O'Rourke, Audience Stack<\/a><\/noindex> <\/p>\n<p><b>Aber in Hibernate \/ JPA ist es so einfach, Code \u201ef\u00fcr Java\u201c zu schreiben. <\/b><\/p>\n<p>In der Tat. F\u00fcr Hibernate und seine Nutzer ist das sowohl Segen als auch Fluch. In Hibernate kann man einfach ein paar Entit\u00e4ten schreiben, so wie:<\/p>\n<pre><code class=\"java\">\t@Entity\nclass Book {\n  @Id\n  int id;\n  String title;\n}<\/code><\/pre>\n<p>\nUnd fast alles ist bereit. Nun ist es die Aufgabe von Hibernate, die komplexen \u201eDetails\u201c zu generieren, wie genau diese Entit\u00e4t in DDL Ihres SQL-Dialekts definiert wird:<\/p>\n<pre><code class=\"sql\">\tERSTELLEN 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 \nERSTELLEN INDEX i_book_title ON book (title);<\/code><\/pre>\n<p>\n\u2026 und wir beginnen, die Anwendung zu starten. Eine wirklich tolle M\u00f6glichkeit, schnell loszulegen und verschiedene Dinge auszuprobieren.<\/p>\n<p>Aber warten Sie. Ich habe geschummelt.<\/p>\n<ul>\n<li>Wird Hibernate tats\u00e4chlich die Definition dieses benannten Prim\u00e4rschl\u00fcssels anwenden?<\/li>\n<li>Wird Hibernate einen Index in TITLE erstellen? \u2013 Ich wei\u00df genau, dass wir ihn brauchen werden. <\/li>\n<li>Wird Hibernate diesen Schl\u00fcssel in der Identity-Spezifikation als identifizierend festlegen?<\/li>\n<\/ul>\n<p>\nWahrscheinlich nicht. Wenn Sie Ihr Projekt von Grund auf neu entwickeln, ist es immer praktisch, die alte Datenbank einfach abzulehnen und eine neue zu generieren, sobald Sie die erforderlichen Annotationen hinzugef\u00fcgt haben. So wird die Entit\u00e4t Book letztendlich folgenderma\u00dfen aussehen: <\/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>\nCool. Neu generieren. Wieder einmal wird es in diesem Fall zu Beginn sehr einfach sein.<\/p>\n<h4>Aber sp\u00e4ter m\u00fcssen Sie daf\u00fcr bezahlen.<\/h4>\n<p>\nFr\u00fcher oder sp\u00e4ter m\u00fcssen Sie in die Produktion gehen. Genau dann wird ein solches Modell nicht mehr funktionieren. Denn: <\/p>\n<p>Im Produktionsbetrieb k\u00f6nnen Sie nicht mehr einfach die alte Datenbank fallen lassen und von Grund auf neu beginnen. Ihre Datenbank wird zu einer veralteten Version.<\/p>\n<p>Von nun an werden Sie <noindex><a rel=\"nofollow\" href=\"https:\/\/blog.jooq.org\/2014\/06\/25\/flyway-and-jooq-for-unbeatable-sql-development-productivity\/\">DDL-Migrationsskripte, beispielsweise mithilfe von Flyway, schreiben m\u00fcssen.<\/a><\/noindex>Was passiert dann mit Ihren Entit\u00e4ten? Sie k\u00f6nnen entweder manuell Anpassungen vornehmen (was Ihren Arbeitsaufwand verdoppelt), oder Sie lassen Hibernate f\u00fcr Sie neu generieren (wie hoch ist die Wahrscheinlichkeit, dass das generierte Ergebnis Ihren Erwartungen entspricht?). In jedem Fall haben Sie verloren.<\/p>\n<p>Sobald Sie in die Produktion \u00fcbergehen, ben\u00f6tigen Sie Hotfixes. Diese m\u00fcssen sehr schnell in die Produktion gebracht werden. Da Sie sich jedoch nicht vorbereitet haben und keine reibungslose Pipeline f\u00fcr Ihre Migrationen eingerichtet haben, m\u00fcssen Sie alles wild patchen. Und dann schaffen Sie es nicht, alles richtig zu machen. Und beschuldigen Hibernate, denn immer ist jemand anders schuld, nur nicht Sie\u2026<\/p>\n<p>Stattdessen h\u00e4tte man von Anfang an alles ganz anders gestalten k\u00f6nnen. Zum Beispiel h\u00e4tte man runde R\u00e4der an das Fahrrad montieren k\u00f6nnen.<\/p>\n<h4>Zuerst die Datenbank<\/h4>\n<p>\nDie wahre \"Wahrheit\" \u00fcber das Schema Ihrer Datenbank und die \"Souver\u00e4nit\u00e4t\" dar\u00fcber liegt innerhalb der Datenbank. Das Schema wird ausschlie\u00dflich in der Datenbank selbst definiert und nirgendwo anders, und jeder Kunde hat eine Kopie dieses Schemas. Daher ist es vollkommen sinnvoll, die Einhaltung des Schemas und seiner Integrit\u00e4t direkt in der Datenbank durchzusetzen \u2013 dort, wo die Informationen gespeichert sind. <br \/>\nDas ist eine alte, beinahe abgedroschene Weisheit. Prim\u00e4r- und Sekund\u00e4rschl\u00fcssel sind gut. Fremdschl\u00fcssel sind gut. Einschr\u00e4nkungen zu \u00fcberpr\u00fcfen ist gut. <noindex><a rel=\"nofollow\" href=\"https:\/\/community.oracle.com\/ideas\/13028\">Aussagen<\/a><\/noindex> \u2013 gut. <\/p>\n<p>Und das ist noch nicht alles. Wenn Sie Oracle verwenden, m\u00f6chten Sie wahrscheinlich angeben:<\/p>\n<ul>\n<li>In welchem Tabellenraum sich Ihre Tabelle befindet <\/li>\n<li>Welchen PCTFREE-Wert sie hat <\/li>\n<li>Wie gro\u00df der Cache in Ihrer Sequenz (hinter der ID) ist<\/li>\n<\/ul>\n<p>\nVielleicht ist das alles in kleinen Systemen nicht wichtig, aber man muss nicht auf den \u00dcbergang zu \"Big Data\" warten \u2013 man kann bereits viel fr\u00fcher von den vom Anbieter bereitgestellten Optimierungen f\u00fcr die Datenspeicherung profitieren, wie die oben genannten. Keine der ORM-Frameworks, die ich gesehen habe (einschlie\u00dflich jOOQ), bietet Zugriff auf das vollst\u00e4ndige Spektrum der DDL-Optionen, die Sie m\u00f6glicherweise in Ihrer Datenbank verwenden m\u00f6chten. ORM bieten einige Werkzeuge, die beim Schreiben von DDL helfen.<\/p>\n<p>Aber letztendlich wird ein gut gestaltetes Schema manuell in DDL geschrieben. Jeder generierte DDL ist lediglich eine Ann\u00e4herung daran.<\/p>\n<h4>Wie sieht es mit dem Client-Modell aus?<\/h4>\n<p>\nWie oben erw\u00e4hnt, ben\u00f6tigen Sie auf dem Client eine Kopie des Schemas Ihrer Datenbank, ein Client-View. Es ist unn\u00f6tig zu erw\u00e4hnen, dass dieses Client-View mit dem tats\u00e4chlichen Modell synchronisiert werden muss. Wie erreichen Sie das am besten? Mit einem Code-Generator.<\/p>\n<p>Alle Datenbanken stellen ihre Metainformationen \u00fcber SQL bereit. So k\u00f6nnen Sie alle Tabellen aus Ihrer Datenbank in verschiedenen SQL-Dialekten abrufen:<\/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>\nDiese Abfragen (oder \u00e4hnliche, je nachdem, ob auch Sicht, materialisierte Sichten und tabellarische Funktionen ber\u00fccksichtigt werden m\u00fcssen) werden ebenfalls \u00fcber einen Aufruf ausgef\u00fchrt <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> aus JDBC oder \u00fcber das Meta-Modul jOOQ.<\/p>\n<p>Aus den Ergebnissen solcher Abfragen l\u00e4sst sich relativ einfach eine klientenspezifische Darstellung Ihres Datenbankmodells generieren, unabh\u00e4ngig davon, welche Technologie auf Ihrer Client-Seite verwendet wird.<\/p>\n<ul>\n<li>Wenn Sie JDBC oder Spring verwenden, k\u00f6nnen Sie eine Reihe von String-Konstanten erstellen. <\/li>\n<li>Wenn Sie JPA verwenden, k\u00f6nnen Sie die Entit\u00e4ten selbst generieren. <\/li>\n<li>Wenn Sie jOOQ verwenden, k\u00f6nnen Sie das jOOQ-Meta-Modell generieren.<\/li>\n<\/ul>\n<p>\nJe nachdem, welche Funktionen Ihre Client-API (z. B. jOOQ oder JPA) bietet, kann das generierte Meta-Modell wirklich umfangreich und detailliert sein. Nehmen wir zum Beispiel die M\u00f6glichkeit von impliziten Joins, <noindex><a rel=\"nofollow\" href=\"https:\/\/blog.jooq.org\/2018\/02\/20\/type-safe-implicit-join-through-path-navigation-in-jooq-3-11\/\">die in jOOQ 3.11 eingef\u00fchrt wurde.<\/a><\/noindex>, die auf generierten Metainformationen zu den Beziehungen zwischen Ihren Tabellen basiert.<\/p>\n<p>Jetzt f\u00fchrt jede \u00c4nderung in der Datenbank automatisch zu einem Update des Client-Codes. Stellen Sie sich beispielsweise Folgendes vor:<\/p>\n<pre><code class=\"sql\">ALTER TABLE book RENAME COLUMN title TO book_title;<\/code><\/pre>\n<p>\nM\u00f6chten Sie diese Arbeit wirklich zweimal machen? Auf keinen Fall. Wir halten einfach DDL fest, f\u00fchren es durch Ihre Build-Pipeline und erhalten das aktualisierte Entity:<\/p>\n<pre><code class=\"java\">@Entity\n@Table(name = \"book\", indexes = {\n \n  \/\/ Haben Sie dar\u00fcber nachgedacht?\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>\nOder die aktualisierte jOOQ-Klasse. Die meisten DDL-\u00c4nderungen beeinflussen auch die Semantik, nicht nur die Syntax. Daher kann es sinnvoll sein, im kompilieren Code zu sehen, welcher Code durch die \u00c4nderungen in Ihrer Datenbank betroffen sein k\u00f6nnte.<\/p>\n<h4>Die einzige Wahrheit<\/h4>\n<p>\nUnabh\u00e4ngig von der verwendeten Technologie gibt es stets ein Modell, das die einzige Quelle der Wahrheit f\u00fcr ein bestimmtes Teilsystem darstellt \u2013 oder zumindest sollten wir dieses Ziel anstreben, um das Chaos im Unternehmen zu vermeiden, wo die \u201eWahrheit\u201c \u00fcberall und nirgendwo gleichzeitig existiert. Alles k\u00f6nnte viel einfacher sein. Wenn Sie lediglich XML-Dateien mit einem anderen System austauschen, nutzen Sie einfach XSD. Werfen Sie einen Blick auf das INFORMATION_SCHEMA-Meta-Modell von jOOQ im XML-Format:<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 ist gut verst\u00e4ndlich.<\/li>\n<li>XSD kennzeichnet den XML-Inhalt sehr pr\u00e4zise und erm\u00f6glicht die Validierung in allen Client-Sprachen. <\/li>\n<li>XSD verf\u00fcgt \u00fcber eine gute Versionierung und bietet umfangreiche Abw\u00e4rtskompatibilit\u00e4t. <\/li>\n<li>XSD kann mithilfe von XJC in Java-Code \u00fcbersetzt werden.<\/li>\n<\/ul>\n<p>\nDer letzte Punkt ist wichtig. Bei der Kommunikation mit externen Systemen \u00fcber XML-Nachrichten m\u00f6chten wir sicherstellen, dass unsere Nachrichten g\u00fcltig sind. Das l\u00e4sst sich sehr einfach mit JAXB, XJC und XSD erreichen. Es w\u00e4re absolut verr\u00fcckt zu glauben, dass wir bei einem \"Java-zuerst\"-Ansatz, bei dem wir unsere Nachrichten als Java-Objekte erstellen, diese irgendwie sinnvoll nach XML abbilden und zur Verwendung in ein anderes System senden k\u00f6nnen. XML, das auf diese Weise generiert wird, w\u00e4re von sehr schlechter Qualit\u00e4t, schlecht dokumentiert und schwer weiterzuentwickeln. Sollte ein solcher Schnittstelle ein Service Level Agreement (SLA) zugrunde liegen, w\u00fcrden wir es sofort ruinieren.<\/p>\n<p>Ehrlich gesagt passiert genau das st\u00e4ndig mit JSON-APIs, aber das ist eine andere Geschichte, beim n\u00e4chsten Mal werde ich mich dar\u00fcber aufregen\u2026 <\/p>\n<h4>Datenbanken: das ist dasselbe<\/h4>\n<p>\nWenn Sie mit Datenbanken arbeiten, verstehen Sie, dass sie alle im Grunde \u00e4hnlich sind. Eine Datenbank besitzt ihre Daten und muss das Schema verwalten. Alle Modifikationen am Schema sollten direkt in DDL umgesetzt werden, damit die einzige Wahrheit aktualisiert wird.<\/p>\n<p>Wenn die Quelle aktualisiert wird, m\u00fcssen auch alle Kunden ihre Modellkopien aktualisieren. Einige Kunden k\u00f6nnten in Java mit jOOQ und Hibernate oder JDBC (oder sogar allen zusammen) geschrieben sein. Andere k\u00f6nnten in Perl geschrieben sein (da bleibt nur, ihnen viel Gl\u00fcck zu w\u00fcnschen), und wieder andere in C#. Das spielt keine Rolle. Das Hauptmodell befindet sich in der Datenbank. Durch ORM generierte Modelle sind oft von minderer Qualit\u00e4t, schlecht dokumentiert und schwer weiterzuentwickeln.<\/p>\n<p>Machen Sie daher keine Fehler. Begehen Sie von Anfang an keine Fehler. Arbeiten Sie, basierend auf der Datenbank. Erstellen Sie eine Bereitstellungspipeline, die automatisiert werden kann. Integrieren Sie Code-Generatoren, um Ihr Datenbankmodell bequem kopieren und an die Clients \u00fcbergeben zu k\u00f6nnen. Und h\u00f6ren Sie auf, sich \u00fcber Code-Generatoren zu sorgen. Sie sind gut. Mit ihnen werden Sie produktiver. Sie m\u00fcssen nur von Anfang an etwas Zeit in ihre Einrichtung investieren \u2013 und schon erwarten Sie Jahre gesteigerter Produktivit\u00e4t, die die Geschichte Ihres Projekts pr\u00e4gen werden.<\/p>\n<p>Noch nicht danken, sp\u00e4ter.<\/p>\n<h4>Erkl\u00e4rung<\/h4>\n<p>\nZur Klarheit: Dieser Artikel propagiert keineswegs, dass das gesamte System (d.h. das Fachgebiet, die Gesch\u00e4ftslogik usw.) sich nach dem Modell Ihrer Datenbank richten sollte. In diesem Artikel erkl\u00e4re ich, dass der Client-Code, der mit der Datenbank interagiert, basierend auf dem Modell der Datenbank handeln sollte, sodass das Modell der Datenbank nicht als \"First-Class\" im Client selbst reproduziert wird. Eine solche Logik befindet sich normalerweise auf der Datenzugriffsebene in Ihrem Client.<\/p>\n<p>In den nach wie vor gelegentlich anzutreffenden Zwei-Schichten-Architekturen k\u00f6nnte ein solches Systemmodell die einzige M\u00f6glichkeit darstellen. Allerdings erscheint mir in den meisten Systemen die Datenzugriffsebene als eine \"Subsystem\", die das Modell der Datenbank kapselt.<\/p>\n<h4>Ausnahmen<\/h4>\n<p>\nJede Regel hat Ausnahmen, und ich habe bereits erw\u00e4hnt, dass der Ansatz, die Datenbank als prim\u00e4r zu betrachten und den Quellcode zu generieren, manchmal ungeeignet sein kann. Hier sind ein paar solcher Ausnahmen (es gibt wahrscheinlich noch weitere):<\/p>\n<ul>\n<li>Wenn das Schema unbekannt ist und es ge\u00f6ffnet werden muss. Zum Beispiel sind Sie ein Anbieter eines Tools, das den Nutzern hilft, sich in jedem Schema zurechtzufinden. Uff. Das geht hier ohne Codegenerierung. Aber dennoch \u2013 die Datenbank steht an erster Stelle.<\/li>\n<li>Wenn das Schema zur Laufzeit generiert werden soll, um eine bestimmte Aufgabe zu l\u00f6sen. Dieses Beispiel scheint eine etwas ausgefallene Version des Musters zu sein. <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Entity%E2%80%93attribute%E2%80%93value_model\">Entity-Attribut-Wert<\/a><\/noindex>, d.h., Sie haben wirklich kein klar definiertes Schema. In diesem Fall kann man oft nicht einmal sicher sein, dass eine relationale Datenbank geeignet ist.<\/li>\n<\/ul>\n<p>\nAusnahmen sind von Natur aus au\u00dfergew\u00f6hnlich. In den meisten F\u00e4llen, die mit der Nutzung von relationalen Datenbanken verbunden sind, ist das Schema im Voraus bekannt, es befindet sich innerhalb der Datenbank und stellt die einzige Quelle der 'Wahrheit' dar, w\u00e4hrend alle Clients Kopien davon erwerben m\u00fcssen, die von ihm abgeleitet sind. Idealerweise sollte dabei ein Codegenerator verwendet werden.<br \/>\n<br \/>Quelle: <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 4.9.10 - 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 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,\" \/>\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\/de\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\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 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,\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/de\/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\udd47Die Wahrheit zuerst: Warum Systeme basierend auf der Datenbankstruktur entworfen werden sollten | ProHoster","description":"Hallo, Habr! Wir setzen unsere Erforschung des Themas Java und Spring fort, insbesondere im Bereich Datenbanken. Heute m\u00f6chten wir dar\u00fcber schreiben, warum bei der Gestaltung gro\u00dfer Anwendungen die Struktur der Datenbank, und nicht der Java-Code, entscheidend sein sollte, wie man dies umsetzt und welche Ausnahmen es von dieser Regel gibt. In diesem etwas versp\u00e4teten Artikel werde ich erl\u00e4utern,","canonical_url":"https:\/\/prohoster.info\/de\/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":"de_DE","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 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,","og:url":"https:\/\/prohoster.info\/de\/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"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/79465","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=79465"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/79465\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media\/79466"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=79465"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=79465"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=79465"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}