{"id":550,"date":"2021-06-19T20:35:05","date_gmt":"2021-06-19T18:35:05","guid":{"rendered":"https:\/\/neu.montybanse.eu\/?p=550"},"modified":"2022-03-06T23:19:13","modified_gmt":"2022-03-06T22:19:13","slug":"dms-die-datenbank","status":"publish","type":"post","link":"https:\/\/www.montybanse.eu\/index.php\/server-programmierung-co\/dms-die-datenbank\/","title":{"rendered":"DMS: Die Datenbank"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_76 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Alles auf einen Blick<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 eztoc-toggle-hide-by-default' ><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.montybanse.eu\/index.php\/server-programmierung-co\/dms-die-datenbank\/#Tabelle_user\" >Tabelle: user<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.montybanse.eu\/index.php\/server-programmierung-co\/dms-die-datenbank\/#Tabelle_documents\" >Tabelle: documents<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.montybanse.eu\/index.php\/server-programmierung-co\/dms-die-datenbank\/#Tabelle_documentsAttachment\" >Tabelle: documentsAttachment<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.montybanse.eu\/index.php\/server-programmierung-co\/dms-die-datenbank\/#Tabelle_categories\" >Tabelle: categories<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-1'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.montybanse.eu\/index.php\/server-programmierung-co\/dms-die-datenbank\/#Tabelle_aliasMapping\" >Tabelle: aliasMapping<\/a><\/li><\/ul><\/nav><\/div>\n\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"550\" class=\"elementor elementor-550\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-d349cd0 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"d349cd0\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-488c824\" data-id=\"488c824\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-0e916d4 elementor-drop-cap-yes elementor-drop-cap-view-default elementor-widget elementor-widget-text-editor\" data-id=\"0e916d4\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;drop_cap&quot;:&quot;yes&quot;}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Ganz zu Beginn \u00fcberlegte ich mir eine Datenbankstruktur. Mein Plan war, dass ich alle Dokumente als Blob in einer MySQL Datenbank ablegen w\u00fcrde. Hier gibt es verschiedene Meinungen zu: Die einen sagen: \u201e<em>Absolut nicht akzeptabel<\/em>. Dateien geh\u00f6ren im Dateisystem abgelegt!!!\u201c und die anderen \u201e<em>Kann man ja mal machen\u2026<\/em>\u201c.<\/p><p>Die Vor- und Nachteile sind eigentlich relativ gut aufzuwiegen. F\u00fcr die Speicherung in der MySQL Datenbank spricht nat\u00fcrlich die gute Anpassbarkeit der Berechtigungen sowie die relativ einfache Abfrage der Daten aus der Datenbank.<\/p><p>Dagegen spricht: Die Datenbank wird mit der Zeit sehr gro\u00df. Unter Umst\u00e4nden kann MySQL auch an seine Grenzen sto\u00dfen (die ich \u00fcbrigens sp\u00e4ter noch anmerken werden &#8211; ich bin n\u00e4mlich auch darauf gesto\u00dfen).<\/p><p>Gegen das Speichern als Dateien sprach hingegen, dass ich mir keine Gedanken machen wollte, wie ich den Zugriff auf die Daten selbst einschr\u00e4nke. Wenn es ein Filesystem gibt in dem die Daten liegen, muss ich sehen, dass die Daten nicht z.B. \u00fcber eine URL abrufbar sind und versteckt bleiben.<\/p><p>Ich entschied mich daher meine zuk\u00fcnftigen Dokumente im PDF Format als base64 decodierten in eine Blob-Tabelle abzulegen. Nur nebenbei: Das macht auch das Backup relativ einfach. Es wird halt nur recht gro\u00df.<\/p><p>Mein erster Schritt war also mir meine Datenbankstruktur zu \u00fcberlegen:<br \/>Welche Tabellen brauche ich? Welche Inhalte sollen die Tabellen haben?<\/p><p>Ich begann mit der Tabelle f\u00fcr die\u00a0Benutzer:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-6caf3d8 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"6caf3d8\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-02686a5\" data-id=\"02686a5\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-f507a02 elementor-widget elementor-widget-text-editor\" data-id=\"f507a02\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h1><span class=\"ez-toc-section\" id=\"Tabelle_user\"><\/span>Tabelle: user<span class=\"ez-toc-section-end\"><\/span><\/h1><p>Die Usertabelle ist recht einfach und \u00fcberschaubar aufgebaut.\u00a0<\/p><p>In der ersten Version gab es eigentlich nur einige wenige Spalten:<\/p><ul><li>id: f\u00fcr die interne ID<\/li><li>login: Loginname<\/li><li>firstname: Vorname<\/li><li>lastname: Nachname<\/li><li>email: E-Mailadresse<\/li><li>password: Password als Hash<\/li><li>lastLoginIP: IP des letzten Logins<\/li><li>lastLoginDate: Datum des letzten Logins<\/li><li>disabled: Account aktiv oder nicht?<\/li><\/ul><p>Das wars auch schon mal. In der Zwischenzeit habe ich die Tabelle noch um einiges erg\u00e4nzt, aber dazu sp\u00e4ter mehr.<\/p><p>Ich brauchte dann nat\u00fcrlich auch eine Tabelle f\u00fcr meine Dokumente. Hier \u00fcberlegte ich mir wie es am besten w\u00e4re und wie es sinnvoll sein k\u00f6nnte.<\/p><p>Ich w\u00e4hlte ein Konstrukt aus zwei verschiedenen Tabellen:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-b86e654 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"b86e654\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-ae539d7\" data-id=\"ae539d7\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-3f8212d elementor-widget elementor-widget-text-editor\" data-id=\"3f8212d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h1><span class=\"ez-toc-section\" id=\"Tabelle_documents\"><\/span>Tabelle: documents<span class=\"ez-toc-section-end\"><\/span><\/h1><p>Hier werden die haupts\u00e4chlichen Inhalte und Metadaten des jeweiligen Dokuments gespeichert:<\/p><ul><li>id: f\u00fcr die interne ID<\/li><li>uid: die Benutzer-ID<\/li><li>name: Name des Dokumentes<\/li><li>fileName: Dateiname des Dokuments<\/li><li>fileDate: Datum des Dokuments<\/li><li>fileUploadDate: Datum des Uploads<\/li><li>categorie: Kategorie<\/li><li>description: Beschreibung des Dokuments<\/li><\/ul><p>Auch hier an und f\u00fcr sich, sehr \u00fcberschaubar gehalten. Aber auch hier gab es im Laufe der Zeit die eine oder kleine \u00c4nderung und Anpassung.<\/p><p>Dazu gibt es noch die<\/p><h1><span class=\"ez-toc-section\" id=\"Tabelle_documentsAttachment\"><\/span>Tabelle: documentsAttachment<span class=\"ez-toc-section-end\"><\/span><\/h1><p>Sie beinhaltet schlussendlich die Datei mit dem Dokument (in dem Fall PDF) an sich.<\/p><ul><li>id: f\u00fcr die interne ID<\/li><li>uid: die Benutzer-ID<\/li><li>documentID: die Dokument-ID<\/li><li>mimeTyp: Der Typ des Dokuments<\/li><li>attachment: Inhalt der Datei als base64 String.<\/li><\/ul><p>Auch bis hierher: Kein Hexenwerk. Diese Tabelle hat sich \u00fcbrigens in den ganzen Anpassungen von mir bisher auch nicht weiter ge\u00e4ndert.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-3411cb9 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"3411cb9\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c9b4c24\" data-id=\"c9b4c24\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-c493f31 elementor-widget elementor-widget-text-editor\" data-id=\"c493f31\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h1><span class=\"ez-toc-section\" id=\"Tabelle_categories\"><\/span>Tabelle: categories<span class=\"ez-toc-section-end\"><\/span><\/h1><p>Die Kategorien sind ebenfalls nicht besonders schwierig aufgebaut:<\/p><ul><li>id: f\u00fcr die interne ID<\/li><li>uid: f\u00fcr die Benutzer-ID<\/li><li>name: Name der Kategorie<\/li><li>description: Beschreibung der Kategorie<\/li><li>deletable: Kann die Kategorie gel\u00f6scht werden?<\/li><li>deletableDisabled: Die L\u00f6schm\u00f6glichkeit deaktivieren<\/li><li>parentCategorie: Die Elternkategorie<\/li><\/ul><p>Zu den Einstellungen ob eine L\u00f6schung erlaubt ist und ob die L\u00f6schung der L\u00f6schung erlaubt ist, komme ich sp\u00e4ter noch einmal im Detail und was der Sinn dahinter sein soll.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-c9d5057 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"c9d5057\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-a30f7e9\" data-id=\"a30f7e9\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-508cf86 elementor-widget elementor-widget-text-editor\" data-id=\"508cf86\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<h1><span class=\"ez-toc-section\" id=\"Tabelle_aliasMapping\"><\/span>Tabelle: aliasMapping<span class=\"ez-toc-section-end\"><\/span><\/h1><p>Diese Tabelle stellt einen Zusammenhang zwischen dem Absender einer E-Mail bzw. eines Dokumentes und dem Empf\u00e4nger dar. Auf die Funktion gehe ich sp\u00e4ter auch noch einmal genauer ein.<\/p><ul><li>id: f\u00fcr die Interne ID<\/li><li>uid: f\u00fcr die Benutzer-ID<\/li><li>sender: E-Mailadresse des Absenders<\/li><li>descript: Beschreibung<\/li><li>type: Typ der E-Mail die eingeliefert wird<\/li><\/ul>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-743f8df elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"743f8df\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-b8999ab\" data-id=\"b8999ab\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-e899171 elementor-drop-cap-yes elementor-drop-cap-view-default elementor-widget elementor-widget-text-editor\" data-id=\"e899171\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;drop_cap&quot;:&quot;yes&quot;}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Ihr seht also, dass die Tabellenstruktur gar nicht so kompliziert aufgebaut ist. Als Wichtig empfinde ich, dass die jede Tabelle seine eigene interne ID erh\u00e4lt, auch wenn das z.B. bei dem aliasMapping oder der Tabelle documentsAttachment gar nicht unbedingt n\u00f6tig gewesen w\u00e4re. Auch fand ich es wichtig, die \u00fcbergreifenden Spalten (wie z.B. uid) immer gleich zu benennen. Das verhindert sp\u00e4ter Verwirrungen.<\/p><p>Ansonsten habe ich die Datenbank allgemein noch mit den Relations ausgestattet (eigentlich alle soweit mittels CASCADE) um z.B. einfach zu verhindern, dass wenn ein User gel\u00f6scht wird, in den anderen einzelnen Tabellen Daten der User-ID weiterhin vorhanden bleiben. So reicht sp\u00e4ter z.B. auch nur ein query, wenn ein User gel\u00f6scht werden soll &#8211; und zwar direkt auf die user Tabelle und muss nicht auf andere Tabellen ausgedehnt werden. Zieht man das konsequent durch, l\u00e4sst sich das ganze sp\u00e4ter immer sch\u00f6n um weitere Tabellen erweitern und man muss z.B. die Funktionen f\u00fcr die L\u00f6schung eines Benutzer nicht weiter anfassen. Das passiert dann alles Datenbankseitig.<\/p><p>Hier gehts weiter:\u00a0<a href=\"https:\/\/neu.montybanse.eu\/index.php\/server-programmierung-co\/dokumentenmanagement-selbst-gemacht\/dms-das-aussehen\/\">Dokumentenmanagement: Das Aussehen<\/a><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Ganz zu Beginn \u00fcberlegte ich mir eine Datenbankstruktur. Mein Plan war, dass ich alle Dokumente als Blob in einer MySQL Datenbank ablegen w\u00fcrde. Hier gibt es verschiedene Meinungen zu: Die einen sagen: \u201eAbsolut nicht akzeptabel. Dateien geh\u00f6ren im Dateisystem abgelegt!!!\u201c und die anderen \u201eKann man ja mal machen\u2026\u201c. Die Vor-<\/p>\n","protected":false},"author":1,"featured_media":959,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_eb_attr":"","_themeisle_gutenberg_block_has_review":false,"footnotes":""},"categories":[18,17],"tags":[],"class_list":["post-550","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dokumentenmanagement-selbst-gemacht","category-server-programmierung-co"],"_links":{"self":[{"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/posts\/550","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/comments?post=550"}],"version-history":[{"count":22,"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/posts\/550\/revisions"}],"predecessor-version":[{"id":960,"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/posts\/550\/revisions\/960"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/media\/959"}],"wp:attachment":[{"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/media?parent=550"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/categories?post=550"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.montybanse.eu\/index.php\/wp-json\/wp\/v2\/tags?post=550"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}