web-dev-qa-db-fra.com

Le professeur nous a dit de stocker les objets sérialisés Java en tant qu'objets blob au lieu de définir des tables relationnelles

Au lieu de définir réellement une table avec les bons attributs, mon professeur nous a dit que nous pouvions mapper des objets à des identifiants comme celui-ci:

id (int)  |   Serialized Object (blob)
   1               10010110110

Je peux voir tant de problèmes avec cela; redondance des données, devoir suivre les identifiants séparément, devoir tirer toute la table en mémoire pour chercher quoi que ce soit, et ** si je veux changer mon modèle dans le code Java Java, je ne le ferai plus être en mesure de désérialiser le blob stocké dans la base de données dans ce modèle.

Soit je suis toujours coincé avec ce modèle, soit je dois faire d'autres trucs vraiment laids pour changer de modèle. ** Tout cela me semble une mauvaise forme. Suis-je justifié d'être en désaccord avec mon professeur? Y a-t-il un avantage à faire cela auquel je n'ai pas pensé? Si j'ai raison, devrais-je dire quelque chose à mon professeur à ce sujet? Il prêchait cela à toute ma classe et a même dit qu'il avait construit des projets de cette façon. Un deuxième avis serait super.

Le cours est nommé Software Design.

Mon professeur n'a pas dit que c'était la meilleure façon, mais il a dit que c'était une alternative légitime à la définition des tables relationnelles.

Le modèle n'est en aucun cas dynamique.

21
Tyler Davis
  1. Ce n'est pas, en soi, une mauvaise chose - du tout. Discuter de "ce qui est mieux" sans un contexte approprié (= exigences exactes) est un exercice futile.

  2. La partie en gras est fausse. Vous pouvez facilement étendre des objets déjà sérialisés pour ajouter de nouveaux champs et obtenir une compatibilité binaire complète avec les objets plus anciens. Vous pouvez également simplement créer de nouvelles classes au lieu de changer les classes originales.

Votre discussion avec le professeur devrait se concentrer sur les avantages et les inconvénients du "relationnel" par rapport au "magasin de valeurs-clés" dans différents scénarios, et non sur la "bêtise" abstraite. Ou vous pourriez aussi avoir une discussion sur si Noël est supérieur à Thanksgiving.

- une modification, après avoir lu d'autres réponses.

L'une des autres réponses va jusqu'à dire que "c'est difficile d'imaginer un cas où les avantages l'emportent sur les inconvénients".

Parce que toute la discussion doit porter sur des problèmes concrets (sinon nous ne pouvons même pas définir "mieux" et "pire"), permettez-moi de vous donner un exemple concret. C'est complètement inventé, mais j'ai essayé d'étoffer autant de détails que possible.

Imaginez que vous ayez un site de jeu en ligne, avec une base de données qui stocke les statistiques des joueurs dans différents jeux en ligne (joué dans le navigateur, écrit en GWT et compilé en javascript). Certains jeux sont stratégiques, certains sont des jeux d'action, d'autres sont des jeux de plateforme. La base de données est relationnelle et stocke les joueurs et l'historique des jeux et le score.

Un jour, vous obtenez une exigence supplémentaire: laissez les joueurs enregistrer l'état du jeu dans le cloud, pendant le jeu, afin qu'ils puissent redémarrer le jeu plus tard, au même moment. Inutile de dire que la seule raison de stocker cet état temporaire est de revenir au jeu, l'état lui-même ne sera jamais introspection.

Vous avez maintenant deux choix de base:

  • étant donné que les jeux sont écrits en Java, vous pouvez très facilement prendre le modèle, l'envoyer au serveur, le sérialiser en une seule ligne de code et le stocker sous forme de blob. La table sera appelée "jeux_enregistrés" et elle aura des clés étrangères au joueur et ainsi de suite. Du point de vue de la base de données, une "sauvegarde" est une goutte opaque et indivisible.

  • vous pouvez créer un modèle relationnel distinct pour chacun de vos 100 jeux (ce seront des dizaines de tables par jeu). Pour pacman seul, par exemple, vous devrez avoir une table stockant les positions de toutes les pastilles non consommées, les bonus, les positions et l'état actuel des fantômes. Si quelqu'un, un jour, modifie le jeu, même légèrement, vous devrez mettre à jour le modèle relationnel. De plus, pour chaque type de jeu, vous devrez implémenter une logique pour écrire le modèle Java dans la base de données et le relire).

La réponse de Justin Cave dit que vous devriez opter pour la deuxième option. Je pense que ce serait une énorme erreur.

De plus, j'ai l'impression que la perception de Justin Cave est que ce que j'ai présenté ci-dessus est un cas "Edge" ou "rare". Je crois qu'à moins qu'il ne puisse présenter une sorte de données solides (basées sur un échantillon représentatif de tous les projets informatiques dans le monde, pas seulement, disons, les applications d'entreprise aux États-Unis), je considérerai une telle opinion comme un cas classique de projection biais.

En fait, le problème des objets sérialisés Java objets dans une base de données relationnelle est beaucoup plus profond qu'il n'y paraît. Il touche au cœur même du 1NF, à savoir quel est le domaine d'un attribut? . Si vous êtes vraiment intéressé par le sujet, il y a un excellent article de CJ Date, dans sa Date on Database: Writings 2000- 2006 .

34
fdreger

Les gens peuvent-ils (et font-ils) livrer avec succès des projets qui font ce genre de choses? Malheureusement, oui, ils le font assez souvent.

Est-ce une bonne approche? Non ce n'est pas. Vous prenez essentiellement votre base de données relativement chère et la transformez en un système de fichiers relativement lent. Si vous voulez vraiment construire un système qui enregistre son état en sérialisant et désérialisant des objets, vous pouvez également utiliser un système de fichiers plutôt que d'utiliser une base de données.

Si vous créez des systèmes qui stockent des données en sérialisant des objets dans la base de données, vous ne vous lierez pas d'amitié avec votre DBA. Vous finirez par stocker des données redondantes. Vous vous retrouverez avec des données terriblement incohérentes - chaque fois que des données partagées sont mises à jour, certains objets se retrouveront avec les nouvelles valeurs et certains objets se retrouveront avec les anciennes valeurs. Vous ne pourrez pas faire de rapports sur les données, tout ce que quiconque voudra faire avec les données nécessitera que quelqu'un écrive du code supplémentaire. C'est un problème énorme, énorme dans la plupart des entreprises, car elles veulent faire des choses comme extraire des données d'un système pour les charger dans un autre système ou avoir un système de rapports qui peut fournir des rapports à partir de plusieurs applications frontales. De plus, comme vous le faites remarquer, vous devrez constamment faire face à des problèmes lorsque vous faites évoluer votre modèle de données.

Y a-t-il des avantages à cette approche? Je suppose que vous pouvez affirmer qu'il est assez facile de mettre en œuvre la première version de l'application. Et cela permet au développeur d'ignorer complètement tout ce qui concerne l'interaction correcte avec une base de données. J'ai du mal à imaginer de nombreux cas où ces avantages l'emportent sur les nombreux inconvénients de l'approche.

Quant à la façon dont vous devriez traiter avec ce professeur en particulier, c'est une question distincte (et qui est probablement hors de portée de ce forum). Si votre professeur développe activement des projets dans le monde réel, il ne sera probablement pas terriblement réceptif à l'argument d'un étudiant selon lequel son approche est fondamentalement mauvaise (même si l'approche est vraiment fondamentalement mauvaise). Vous pouvez être mieux servi en réalisant votre projet comme le souhaite le professeur et en apprenant la bonne façon de sauvegarder les données par vous-même (ou dans un autre cours).

22
Justin Cave

Il y a des situations où ce type de conception est judicieuse, sans que vous décriviez en quoi consistent vos projets et comment ils sont utilisés, il est difficile de dire si cela est approprié ou non.

Votre DBA peut vous détester si vous stockez des BLOB, mais dans de nombreuses situations, la seule autre alternative est de transformer les tables en Entity-attribute-value, ce qui suscite encore plus de haine de la part des DBA. L'autre alternative consiste à utiliser des bases de données non relationnelles, généralement des bases de données basées sur des objets ou des dictionnaires ou une base de données orientée documents, que certains administrateurs de base de données, en particulier ceux qui ne connaissent que les relations, détesteraient avec encore plus de passion. La base de données non relationnelle a cependant ses propres problèmes à gérer, il peut certainement être le cas que l'utilisation de la base de données d'objets pour stocker des objets puisse exposer d'autres problèmes que vous auriez pu résoudre facilement dans les systèmes relationnels.

Y a-t-il un avantage à faire cela auquel je n'ai pas pensé?

Stocker un objet sérialisé signifie que vous pouvez stocker des données sans schéma (notez que malgré le nom, sans schéma ne signifie généralement pas qu'il n'y a en fait aucun schéma, mais plutôt qu'il n'y a qu'un schéma implicite). Il existe de nombreux domaines problématiques où vous ne pouvez pas définir le schéma à l'avance au moment du développement, et où suivre la conception de la base de données relationnelle traditionnelle signifierait que vous devez modifier le schéma de la base de données toutes les deux semaines, ou que vous vous retrouvez avec une table qui a 80% des colonnes qui sont inutilisées 80% du temps, ou des centaines de tables différentes pour stocker ce qui est vraiment les mêmes données, dont aucune n'indique une bonne conception. La racine de ce problème est généralement due au fait que vous ajustez de force un domaine de problème non relationnel dans une base de données relationnelle.

Bien sûr, il y a beaucoup de projets où les gens pensent qu'ils doivent utiliser EAV, schemaless ou blob store, ce qui s'avère inutilement causer ce qui aurait été une douleur évitable. Vous devriez certainement discuter avec votre professeur de son raisonnement et fournir vos propres arguments; écoutez les arguments et préparez-vous à ce que vous finissiez par être d'accord avec lui, ou non, peut-être qu'il a tort.

10
Lie Ryan

Je l'ai déjà fait auparavant - sa technique utile dans certains scénarios dépend cependant du format de sérialisation utilisé. Si je le fais, je m'assure d'utiliser un format de sérialisation qui me permet de désérialiser les anciennes versions de mon modèle (par exemple XML).

Je l'utilise normalement dans des scénarios où le format de données entraînerait un modèle relationnel compliqué qui n'offre aucun avantage (par exemple, lorsque les exigences commerciales ne nécessitent aucun filtrage, etc.) et que j'utilise déjà une base de données (pour autres données relationnelles). Un de ces cas était une application qui avait des requêtes d'utilisateurs - le modèle relationnel avait une poignée de tables pour stocker des choses comme des conditions, des conditions imbriquées (OR/AND etc ...), des options de tri, etc. C'était assez compliqué et donc quand nous devions ajouter une nouvelle fonctionnalité qui nécessitait une modification de la base de données. J'ai remplacé le tout par une seule table de requêtes avec un blob sérialisé représentant toutes les autres options.

Un autre cas était un système qui traitait divers "travaux". Il y avait plusieurs types d'emplois différents et chaque emploi avait des paramètres différents, sans aucune exigence métier pour pouvoir rechercher/filtrer des emplois en fonction de ces paramètres. Le stockage en tant que base de données relationnelle aurait nécessité au moins 1 nouvelle table par type de travail, ce qui rend difficile l'ajout de nouveaux types de travail. Au lieu de cela, les paramètres sont stockés sous forme de blob dans la base de données - chaque type de travail est responsable de la sérialisation et de la désérialisation de ses propres paramètres.

Ce n'est pas très souvent que vous rencontrerez des scénarios comme celui-ci, mais de temps en temps une situation comme celle ci-dessus se présente où la sérialisation des données d'objets blob vous fait économiser beaucoup d'efforts, rend votre application plus maintenable et n'a pas de réels inconvénients.

7
Justin

Justin Cave a raison de dire que cela peut conduire à des données redondantes, mais cela dépend vraiment de la façon dont vous concevez votre base de données.

L'approche consistant à sérialiser un objet entier en blob n'est pas aussi scandaleuse que la plupart des gens ici le pensent. En fait, pour certaines applications, cela peut être la meilleure conception que vous puissiez faire, comme je l'ai expliqué ici: https://stackoverflow.com/a/12644223/1121352 .

En effet, la sérialisation d'un objet entraîne au moins deux avantages:

1- Réduction de l'inadéquation de l'impédance : certains types Java ne sont tout simplement pas disponibles en SQL, en particulier si vous utilisez beaucoup de les classes et les types personnalisés, convertissant ainsi d'avant en arrière de Java en SQL peuvent être un énorme problème, et même conduire à des ambiguïtés.

2- Plus de flexibilité dans votre schéma . En effet, les schémas relationnels sont vraiment parfaits pour les données qui partagent la même structure, mais si certains de vos objets au sein d'une même classe peuvent avoir des propriétés différentes selon les conditions au moment de l'exécution, les schémas relationnels peuvent entraver considérablement votre flux de travail.

Ainsi, il y a certainement des avantages à cette approche (au moins ces deux, mais certainement d'autres que je n'ai pas cités), mais bien sûr, le coût énorme à payer est que vous perdez presque tous les avantages des schémas relationnels.

Cependant, vous pouvez tirer le meilleur parti des deux mondes si vous concevez soigneusement votre base de données: vous pouvez toujours définir un schéma relationnel (c'est-à-dire: des colonnes de clés uniques) en utilisant les attributs qui sont uniques pour chaque objet, puis stocker l'objet dans le blob . De cette façon, vous pouvez toujours assurer une récupération rapide de votre objet étant donné un identifiant unique qui est défini par les attributs de votre objet, réduisant également la redondance, tout en annulant la non-correspondance d'impédance et en conservant une flexibilité totale des objets Java .

En guise de remarque, quelques fabricants de bases de données tentent de mélanger les modèles relationnels et objets, comme le type de données JSON dans PostSQL et PostgreSQL afin que vous puissiez traiter directement JSON comme n'importe quelle colonne relationnelle, et également SQL3 et OQL (Object Query Language) pour ajouter la prise en charge (limitée) d'objets dans SQL.

Au final, tout est affaire de conception et de compromis entre le modèle relationnel et le modèle objet.

/EDIT après avoir lu les commentaires: bien sûr, si vos données doivent être consultables ("interrogeables"), vous ne devez PAS stocker vos données en tant qu'objet blob. Mais si certaines parties de vos données ne sont pas censées être consultables , mais plutôt une sorte de métadonnées, le stockage de cette partie de données en tant qu'objet dans un blob peut être une bonne solution, surtout si ces métadonnées ont une structure flexible et peuvent changer d'objet en objet.

6
gaborous

Donnons un exemple pratique de quand j'ai fait cela dans le passé.

Nous avons une base de données qui contient toutes les données pour une application multi-utilisateurs; la base de données dispose également d'une table d'utilisateurs avec leurs droits d'accès. Toutes ces données sont normalisées comme prévu.

Ensuite, nous avons une demande pour que l'application se souvienne des fenêtres ouvertes par un utilisateur et de ce qu'il faisait, afin qu'il puisse restaurer l'état lorsque l'utilisateur commence à travailler le lendemain matin.

  • Premièrement, si cela échoue parfois, n'est-ce pas impertinent

    • Par exemple, si la première fois que quelqu'un utilise une nouvelle version de l'application, il oublie les fenêtres qu'il avait ouvertes, alors quoi…
  • Par conséquent, il y a un repli de 100% si les objets changent, et donc nous ne pouvons pas lire le bloc.

  • Nous avons déjà une base de données centralisée avec contrôle d'accès, sauvegarde, etc.
  • Le coût de stockage des données dans des fichiers est élevé, car les fichiers devront être placés sur une sorte de serveur de fichiers auquel toutes les machines utilisateur ont accès, ou une API devra être écrite pour lire ces fichiers.

ne autre fois, nous avions une application qui faisait beaucoup de calculs de longue durée et les utilisateurs souhaitaient pouvoir redémarrer les calculs à partir du dernier bon point en cas de coupure de courant, etc. Il y a aucun moyen de prévoir une version différente des applications pour redémarrer les calculs, et comme il y avait beaucoup d'objets à sauvegarder, normaliser les données aurait été coûteux.

Étant donné que la base de données est déjà en place et utilisée pour les données d'application normalisées bien définies, et qu'il n'y a aucune raison réelle de ne pas l'utiliser pour stocker les blogs, nous avons pris l'option raisonnable et rapide.

5
Ian Ringrose

Un facteur très important: Java (celle qui est activée en implémentant Serializable) est un très mauvais format en soi, donc vous ne devriez pas vraiment l'utiliser pour un objet permanent espace de rangement.

Les inconvénients de Java incluent:

  • Les données ne sont pas vraiment lisibles dans d'autres langues.
  • Il n'est pas très facile de maintenir la compatibilité ascendante des objets sérialisés, c'est-à-dire: si vous ajoutez (ou supprimez) des champs à la classe, il n'est pas si facile de lire les objets créés par une version antérieure de la classe.
  • Ce n'est pas si rapide (mais votre kilométrage peut varier)

Donc, si vous utilisez un autre format de sérialisation, vous obtenez un joli magasin de valeurs-clés, si vous utilisez Java sérialisation, vous obtenez un désordre.

4
jb.

Il s'agit d'un fil intéressant avec des réponses bien pensées. Ne connaissant pas toutes les implications du stockage et de la récupération d'objets sérialisés, je pense qu'il serait intéressant de fournir la réponse que je pourrais donner à une équipe DBA ou une équipe de développement:

La clé est de répondre aux exigences actuelles et futures et de garder la solution aussi simple que possible afin de minimiser les futurs travaux de support. Les exigences fonctionnelles et non fonctionnelles (par exemple, infrastructure et base de données) doivent être respectées. N'oubliez pas la règle des 80/20. Comprendre l'importance de l'application pour l'entreprise et les efforts de développement appropriés.

Ne vous attardez pas sur l'espace, la vitesse et la mémoire de la base de données s'ils ne sont pas des problèmes.

Si un SGBD figure sur votre liste approuvée, vous pouvez l'utiliser dans une solution tant que les coûts sont appropriés. Il n'y a aucun problème à utiliser une base de données relationnelle pour stocker des objets blob simples, surtout si cela simplifie les choses.

Si la solution doit être un prototype ou une version ou un stade précoce, il faut encore insister pour que les choses restent simples. Vous pouvez toujours étendre le schéma de données plus tard tant que vous le planifiez.

N'oubliez pas que les bases de données relationnelles n'appliquent pas l'intégrité ou la cohérence à moins que le schéma ne couvre un domaine d'activité autonome et que les règles métier soient strictes. (par exemple, la solution à la question des objets sérialisés peut envisager un référentiel de style dictionnaire/ontologie pour appliquer les règles).

Il convient de noter que toutes les bases de données relationnelles n'utilisent pas de schémas de base de données relationnelles purs (par exemple, étoiles, spatiales, non relationnelles ..), les applications peuvent également utiliser les bases de données relationnelles comme des magasins non relationnels, comme dans la question. De nombreuses bases de données commerciales de base fonctionnent de cette façon.

3
Dave