1
votes

Clojure - moyen idiomatique de gérer la persistance de la base de données

Je suis un développeur Java et SQL expérimenté qui envisage Clojure pour mon prochain projet. J'ai passé du temps à étudier les bases mais j'ai toujours du mal à comprendre la manière idiomatique de gérer sans douleur les interactions avec une base de données relationnelle en ce qui concerne les mises à jour .

La plupart des threads que j'ai lus se concentrent sur le côté requête, ce qui pour moi n'est en fait pas un problème car je suis très à l'aise avec SQL et considère que jdbc.next est plus que suffisant pour mes besoins en matière de requêtes (peut-être augmenté par le support `` hydratation '' de Toucan si nécessaire).

Ma principale préoccupation est de savoir comment gérer la persistance, par exemple comment conserver automatiquement une carte modifiée (imbriquée) (?) Dans la base de données sans avoir besoin de garder une trace de l'état moi-même.

En passant, j'ai suffisamment d'expérience avec Hibernate lui-même et JPA et je pense toujours qu'ils sont trop rigides et verbeux.

L'outil que je considère idéal à cet égard est https://www.sqlalchemy.org/ que j'ai précédemment utilisé via jython avec un grand sentiment de satisfaction.

Merci beaucoup pour toutes vos contributions.

Mise à jour basée sur quelques commentaires / questions ci-dessous:

Pour - espérons-le - définir le contexte plus clairement, supposons un scénario de panier d'achat d'application Web: un nouveau client effectue la vérification. Une insertion doit être réalisée pour le client, éventuellement une autre pour l'adresse de livraison, une autre pour la commande et celles-ci doivent être synchronisées de manière à préserver l'intégrité référentielle. Faire toutes les étapes manuellement est bien sûr une option, mais plus le scénario est complexe, plus la manipulation devient complexe. Ma base de données est relationnelle.

Deuxième mise à jour

Pour éclaircir davantage ma question, mon problème n'est pas de savoir comment émettre les déclarations «insérer / mettre à jour / supprimer», mais plutôt de savoir quelles déclarations doivent être émises en fonction de l'état actuel des choses.

Je m'attendrais à ce que la couche `` ORM '' suive lesquelles de mes `` données '' sont nouvelles, qui ont été modifiées, supprimées, etc. et exécutent l'extrait de code ci-dessus automatiquement d'une manière cohérente similaire au gestionnaire d'entités d'Hibernate (veuillez consulter ce qui suit lien https://www.sitepoint.com/hibernate-introduction-persisting-java-objects/ dans la section "Exécution des opérations CRUD sur les entités" pour un exemple de la fonctionnalité prévue).

Sinon, je voudrais être en mesure d'identifier ce qui s'est passé sur chaque `` élément '' de mes données (graphique d'objet dans le jargon d'hibernation), puis d'exécuter l'extrait que vous avez partagé en parcourant chaque élément, en `` interrogeant '' son état / statut et en déduisant la déclaration correcte à renvoyer à la base de données.

D'après ma compréhension du langage jusqu'à présent, cette fonctionnalité est native (?) Pour clojurer les structures de données - mais je n'ai pas encore pu mettre le doigt dessus.


4 commentaires

Je ne comprends peut-être pas bien votre problème, mais je pense que la manière Clojure serait d'éviter l'état si possible. Interrogez votre dB en cas de besoin, transformez les données, affichez le résultat. De même, une transaction de retour dans le dB ne changera pas l'état de votre application.


quelle est votre question alors? si vous souhaitez effectuer une mise à jour, exécutez-la simplement avec jdbc. si vous souhaitez garder une trace de "l'état" (ou des "modifications"), vous pouvez consulter datomic.com


Pour - espérons-le - définir le contexte plus clairement, supposons un scénario de panier d'achat d'application Web: un nouveau client effectue la vérification. Un insert doit être réalisé pour le client, un autre pour la commande et ceux-ci doivent être synchronisés de manière à préserver l'intégrité référentielle. Faire toutes les étapes manuellement est bien sûr une option, mais plus le scénario est complexe, plus la manipulation devient complexe. Ma base de données est relationnelle.


Les langages de programmation complets de Turing se différencient par ce qu'ils facilitent de ce qu'ils ne font pas. La persistance d'état complexe (comme ak l'a souligné) est à quoi sert la datomic (et elle peut très bien s'asseoir au-dessus des bases de données relationnelles), mais en fonction de votre description de ce que vous voulez, je me demande si vous ne savez pas vraiment ce que Clojure est à propos. "Mettre à jour" n'est pas vraiment quelque chose que Clojure s'efforce de rendre facile. Si vous n'acceptez pas les concepts sous-jacents et que vous pensez que c'est un moyen plus agréable d'écrire Java, je pense que vous allez rencontrer beaucoup de frictions ...


3 Réponses :


1
votes

Vous dites que vous utilisez next.jdbc - la documentation contient des exemples de mise à jour et d'insertion, en utilisant des transactions, pour assurer la cohérence, donc je ne suis pas sûr de ce que vous demandez vraiment ici.

L' next.jdbc.sql noms next.jdbc.sql contient update! et insert! les fonctions. L' next.jdbc noms next.jdbc a with-transaction pour créer des transactions autour de plusieurs opérations.

update! renvoie le nombre de lignes mises à jour. insert! renvoie les clés nouvellement insérées (du mieux possible, en fonction du fonctionnement du pilote de base de données spécifique que vous utilisez).

Il est courant dans les programmes Clojure qui traitent de la base de données d'essayer de séparer le code de persistance de la logique métier pure afin que vous ayez généralement quelque chose comme:

(defn some-process [...]
  (let [data    (some-database-query ...)
        updates (perform-business-logic ...)]
    (with-transaction [tx ...]
      ...based on what is in updates...
      (update-something tx ...)
      (insert-something tx ...)
      (insert-more-stuff tx ...))))

Si les insertions / mises à jour ultérieures reposent sur des clés générées à partir d'insertions précédentes, vous utiliseriez un let pour capturer le résultat des insertions précédentes, afin de pouvoir accéder à ces clés dans les autres insertions / mises à jour.

Il serait raisonnable de refactoriser ce qui précède afin que l'ensemble du formulaire with-transaction soit dans une fonction distincte appelée par un some-process , en passant les updates et la connexion / source de données.

Si cela ne répond pas à votre question, pouvez-vous essayer de clarifier ce que vous demandez vraiment?

N'hésitez pas non plus à rejoindre le Clojurians Slack et à publier des questions sur le canal #sql si vous souhaitez une conversation interactive avec d'autres Clojurians sur la persistance des bases de données relationnelles.

Clojure Slack: https://clojurians.slack.com

Auto-inscription via: http://clojurians.net (ou je peux publier un lien d'invitation personnalisé ici si vous rencontrez des problèmes avec l'auto-inscription)


1 commentaires

Bonjour, merci pour la réponse détaillée et les liens. Je me suis déjà inscrit à closurians.net et j'ai mis à jour ma question en fonction de vos commentaires. Tout autre commentaire serait vraiment apprécié!



0
votes

Je pense avoir trouvé quelque chose qui convient à mon cas d'utilisation. Je peux utiliser datascript comme magasin de données local, puis une fois prêt, je peux (?) Extraire toutes les modifications et les renvoyer dans ma base de données «principale».

Il semble que les gens aient essayé de le faire, comme décrit dans ce fil:

datomic <-> transferts de datascript Je suis en train de mettre hors service une application web, soutenue par datomic côté serveur et prévoyant d'utiliser datascript dans le client.

le plan est de:

  1. exporter un tas de données liées vers le client (requête / extraction / apis d'entité datomic pour créer des données edn adaptées à la transaction en datascript) - pourrait être une chose ponctuelle ou des données de départ avec plus d'être extraites plus tard.
  2. laissez l'utilisateur le modifier (transactions en datascript)
  3. enregistrer toutes les modifications de l'utilisateur dans datomic (pourrait renvoyer la liste complète des transactions effectuées sur le client au serveur, mais idéalement un tx représentant la somme de tous les changements)

Une question à traiter est l'identité. Par exemple, les inversions et les rétractations (à la fois sur le client et sur le serveur) doivent arriver aux bonnes entités.

J'ai quelques plans pour savoir comment tout cela fonctionnera, mais avant d'entrer dans les détails, je suis simplement> curieux de savoir si quelqu'un d'autre a envisagé cette approche générale?

Il y a aussi un lien vers un fichier de code (que je vais devoir digérer).

Merci beaucoup pour tous les commentaires et la réponse!


0 commentaires

0
votes

Un ORM n'a plus de sens, ni plus ni dans Clojure. Une nouvelle technique améliorée est le CQRS, qui peut être appliqué sans outils spéciaux et fonctionne très bien dans Clojure. Voir l'essai de Martin Fowler sur la séparation des responsabilités de commande / requête à https://martinfowler.com/bliki/CQRS.html .


0 commentaires