Εισαγωγή στη Reactive Relational Access Database με Spring και R2DBC

Πριν από λίγο καιρό, κυκλοφόρησε μια αντιδραστική παραλλαγή του προγράμματος οδήγησης JDBC, γνωστή ως R2DBC. Επιτρέπει τη ροή δεδομένων ασύγχρονα σε οποιαδήποτε τελικά σημεία που έχουν εγγραφεί σε αυτό. Χρησιμοποιώντας ένα αντιδραστικό πρόγραμμα οδήγησης όπως το R2DBC μαζί με το Spring, το WebFlux σάς επιτρέπει να γράφετε μια πλήρη εφαρμογή που χειρίζεται τη λήψη και την αποστολή δεδομένων ασύγχρονα.

Σε αυτήν την ανάρτηση, θα επικεντρωθούμε στη βάση δεδομένων, από τη σύνδεση στη βάση δεδομένων και, στη συνέχεια, την αποθήκευση και ανάκτηση δεδομένων. Για να γίνει αυτό, θα χρησιμοποιούμε τα Spring Data. Όπως συμβαίνει με όλες τις λειτουργικές μονάδες Spring Data, μας παρέχει τη διαμόρφωση του κουτιού. Αυτό μειώνει τον αριθμό του κωδικού boilerplate που πρέπει να γράψουμε για να ξεκινήσουμε την εφαρμογή μας. Επιπλέον, παρέχει ένα στρώμα στο πρόγραμμα οδήγησης βάσης δεδομένων που καθιστά ευκολότερη την εκτέλεση των απλών εργασιών και τις πιο δύσκολες εργασίες λίγο λιγότερο επώδυνες.

Για το περιεχόμενο αυτής της ανάρτησης, χρησιμοποιώ μια βάση δεδομένων Postgres. Τη στιγμή της σύνταξης, μόνο οι Postgres, H2 και Microsoft SQL Server έχουν τις δικές τους υλοποιήσεις προγραμμάτων οδήγησης R2DBC.

Έχω γράψει προηγουμένως δύο δημοσιεύσεις σχετικά με τις αντιδραστικές βιβλιοθήκες Spring Data, μία στο Mongo και άλλη για την Cassandra. Ίσως έχετε παρατηρήσει ότι καμία από αυτές τις βάσεις δεδομένων δεν είναι βάσεις δεδομένων RDBMS. Τώρα υπάρχουν και άλλα αντιδραστικά προγράμματα οδήγησης διαθέσιμα για μεγάλο χρονικό διάστημα (έγραψα το Mongo post σχεδόν πριν από 2 χρόνια), αλλά τη στιγμή της σύνταξης ενός αντιδραστικού προγράμματος οδήγησης για μια βάση δεδομένων RDBMS εξακολουθεί να είναι ένα πολύ νέο πράγμα. Αυτή η ανάρτηση θα έχει παρόμοια μορφή με αυτήν.

Επιπλέον, έχω γράψει επίσης μια ανάρτηση σχετικά με τη χρήση του Spring WebFlux που ανέφερα στην εισαγωγή. Μη διστάσετε να το δείτε αν ενδιαφέρεστε να δημιουργήσετε μια πλήρως αντιδραστική εφαρμογή Ιστού.

Εξαρτήσεις

Υπάρχουν μερικά πράγματα που πρέπει να επισημάνουμε εδώ.

Όσο περισσότερο χρησιμοποιείτε το Spring Boot, τόσο περισσότερο θα συνηθίζετε να εισάγετε μια μόνο spring-boot-starterεξάρτηση για το υπέροχο πράγμα που θέλετε να κάνετε. Για παράδειγμα, ήλπιζα ότι θα υπήρχε spring-boot-starter-r2dbcεξάρτηση, αλλά δυστυχώς δεν υπάρχει. Ακόμη.

Με απλά λόγια, αυτή η βιβλιοθήκη βρίσκεται στη νεότερη πλευρά και κατά τη στιγμή της σύνταξης, δεν διαθέτει τη δική της μονάδα Spring Boot που περιέχει οποιεσδήποτε εξαρτήσεις που χρειάζεται μαζί με ταχύτερη εγκατάσταση μέσω αυτόματης διαμόρφωσης. Είμαι βέβαιος ότι αυτά τα πράγματα θα έρθουν κάποια στιγμή και θα κάνουν τη ρύθμιση ενός προγράμματος οδήγησης R2DBC ακόμα πιο εύκολη.

Προς το παρόν, θα χρειαστεί να συμπληρώσουμε μερικές επιπλέον εξαρτήσεις με μη αυτόματο τρόπο.

Επιπλέον, οι βιβλιοθήκες R2DBC έχουν μόνο εκδόσεις Milestone (περισσότερες αποδείξεις ότι είναι νέες), οπότε πρέπει να βεβαιωθούμε ότι φέρουμε στο αποθετήριο Spring Milestone. Πιθανότατα θα χρειαστεί να ενημερώσω αυτήν την ανάρτηση στο μέλλον όταν λάβει μια έκδοση κυκλοφορίας.

Σύνδεση στη βάση δεδομένων

Χάρη στο Spring Data που κάνει πολλή δουλειά για εμάς, το μόνο Bean που πρέπει να δημιουργηθεί χειροκίνητα είναι ConnectionFactoryαυτό που περιέχει τα στοιχεία σύνδεσης της βάσης δεδομένων:

Το πρώτο πράγμα που πρέπει να παρατηρήσετε εδώ είναι η επέκταση του AbstractR2dbcConfiguration. Αυτή η τάξη περιέχει ένα φορτίο φασολιών που δεν χρειάζεται πλέον να δημιουργούμε χειροκίνητα. Η εφαρμογή connectionFactoryείναι η μόνη απαίτηση της τάξης, καθώς απαιτείται για τη δημιουργία του DatabaseClientBean. Αυτό το είδος δομής είναι χαρακτηριστικό των Spring Data modules, οπότε είναι αρκετά οικείο όταν δοκιμάζετε ένα διαφορετικό. Επιπλέον, θα περίμενα να αφαιρεθεί αυτή η μη αυτόματη διαμόρφωση όταν η αυτόματη διαμόρφωση είναι διαθέσιμη και θα οδηγείται αποκλειστικά μέσω του application.properties.

Έχω συμπεριλάβει την portιδιότητα εδώ, αλλά εάν δεν έχετε παίξει με τη διαμόρφωση Postgres, τότε μπορείτε να βασιστείτε στην προεπιλεγμένη τιμή του 5432.

Οι τέσσερις ιδιότητες: host, database, usernameκαι passwordορίζεται από το PostgresqlConnectionFactoryείναι το ελάχιστο για να το πάρει εργασίας. Εν πάση περιπτώσει και θα αντιμετωπίσετε εξαιρέσεις κατά την εκκίνηση.

Χρησιμοποιώντας αυτήν τη διαμόρφωση, το Spring μπορεί να συνδεθεί σε μια τρέχουσα παρουσία Postgres.

Το τελευταίο κομμάτι των αξιοσημείωτων πληροφοριών από αυτό το παράδειγμα είναι η χρήση του @EnableR2dbcRepositories. Αυτός ο σχολιασμός δίνει εντολή στο Spring να βρει οποιεσδήποτε διεπαφές αποθετηρίου που επεκτείνουν τη Repositoryδιεπαφή του Spring . Αυτό χρησιμοποιείται ως βασική διεπαφή για την οργάνωση αποθετηρίων Spring Data. Θα το εξετάσουμε λίγο πιο κοντά στην επόμενη ενότητα. Το κύριο κομμάτι των πληροφοριών που πρέπει να αφαιρέσετε από εδώ είναι ότι πρέπει να χρησιμοποιήσετε τον @EnableR2dbcRepositoriesσχολιασμό για να αξιοποιήσετε πλήρως τις δυνατότητες της Spring Data.

Δημιουργία ενός εαρινού αποθετηρίου δεδομένων

Όπως αναφέρθηκε παραπάνω, σε αυτήν την ενότητα θα εξετάσουμε την προσθήκη ενός Spring Data Repository. Αυτά τα αποθετήρια είναι ένα ωραίο χαρακτηριστικό του Spring Data, που σημαίνει ότι δεν χρειάζεται να γράψετε έναν επιπλέον κωδικό για να γράψετε ένα ερώτημα.

Δυστυχώς, τουλάχιστον προς το παρόν, το Spring R2DBC δεν μπορεί να συμπεράνει ερωτήματα με τον ίδιο τρόπο που κάνουν άλλες μονάδες Spring Data (είμαι σίγουρος ότι αυτό θα προστεθεί κάποια στιγμή). Αυτό σημαίνει ότι θα πρέπει να χρησιμοποιήσετε τον @Queryσχολιασμό και να γράψετε το SQL με το χέρι. Ας ΡΙΞΟΥΜΕ μια ΜΑΤΙΑ:

Αυτή η διεπαφή επεκτείνεται R2dbcRepository. Αυτό με τη σειρά του επεκτείνεται ReactiveCrudRepositoryκαι στη συνέχεια κάτω Repository. ReactiveCrudRepositoryπαρέχει τις τυπικές λειτουργίες CRUD και από ό, τι καταλαβαίνω, R2dbcRepositoryδεν παρέχει επιπλέον λειτουργίες και αντ 'αυτού είναι μια διεπαφή που δημιουργήθηκε για καλύτερη ονομασία κατάστασης.

R2dbcRepositoryπαίρνει δύο γενικές παραμέτρους, μία είναι η κλάση οντοτήτων που παίρνει ως είσοδος και παράγει ως έξοδος. Το δεύτερο είναι ο τύπος του Πρωτεύοντος Κλειδιού. Επομένως σε αυτήν την περίπτωση, η Personτάξη διαχειρίζεται από το PersonRepository(έχει νόημα) και το πεδίο Κύριο κλειδί μέσα Personείναι ένα Int.

Οι τύποι επιστροφών συναρτήσεων σε αυτήν την τάξη και αυτές που παρέχονται ReactiveCrudRepositoryείναι Fluxκαι Mono(δεν φαίνονται εδώ). Αυτοί είναι τύποι Project Reactor που χρησιμοποιεί το Spring ως οι προεπιλεγμένοι τύποι Reactive Stream. Fluxαντιπροσωπεύει μια ροή πολλαπλών στοιχείων ενώ το α Monoείναι ένα μοναδικό αποτέλεσμα.

Τέλος, όπως ανέφερα πριν από το παράδειγμα, κάθε συνάρτηση σχολιάζεται με @Query. Η σύνταξη είναι αρκετά ευθεία προς τα εμπρός, με το SQL να είναι μια συμβολοσειρά μέσα στον σχολιασμό. Το $1( $2, $3κ.λπ.… για περισσότερες εισόδους) αντιπροσωπεύει την τιμή εισόδου στη συνάρτηση. Μόλις το κάνετε αυτό, το Spring θα χειριστεί τα υπόλοιπα και θα περάσει τις εισόδους στις αντίστοιχες παραμέτρους εισόδου, θα συγκεντρώσει τα αποτελέσματα και θα τα χαρτογραφήσει στην καθορισμένη κατηγορία οντοτήτων του αποθετηρίου.

Μια πολύ γρήγορη ματιά στην οντότητα

Δεν πρόκειται να πω πολλά εδώ, αλλά απλά δείξτε την Personτάξη που χρησιμοποιείται από το PersonRepository.

Στην πραγματικότητα, υπάρχει ένα σημείο που πρέπει να κάνετε εδώ. idέχει καταστεί άκυρη και παρείχε μια προεπιλεγμένη τιμή για nullνα επιτρέψει στους Postgres να δημιουργήσουν την ίδια την επόμενη κατάλληλη τιμή. Εάν αυτό δεν είναι ακυρώσιμο και παρέχεται μια idτιμή, το Spring θα προσπαθήσει πραγματικά να εκτελέσει μια ενημέρωση αντί για ένθετο κατά την αποθήκευση. Υπάρχουν άλλοι τρόποι γύρω από αυτό, αλλά νομίζω ότι είναι αρκετά καλός.

Αυτή η οντότητα θα αντιστοιχιστεί στον peopleπαρακάτω πίνακα:

Βλέποντας τα όλα σε δράση

Τώρα ας ρίξουμε μια ματιά ότι πραγματικά κάνει κάτι. Ακολουθεί ένας κώδικας που εισάγει μερικές εγγραφές και τις ανακτά με διάφορους τρόπους:

Ένα πράγμα που θα αναφέρω για αυτόν τον κώδικα. Υπάρχει μια πολύ πραγματική πιθανότητα να εκτελείται χωρίς να εισάγετε ή να διαβάζετε κάποια από τα αρχεία. Όμως, όταν το σκέφτεστε, έχει νόημα. Οι αντιδραστικές εφαρμογές προορίζονται να κάνουν τα πράγματα ασύγχρονα και επομένως αυτή η εφαρμογή έχει ξεκινήσει την επεξεργασία των κλήσεων λειτουργίας σε διαφορετικά νήματα. Χωρίς να μπλοκάρει το κύριο νήμα, αυτές οι ασύγχρονες διεργασίες ενδέχεται να μην εκτελούνται ποτέ πλήρως. Για αυτόν τον λόγο, υπάρχουν ορισμένες Thread.sleepκλήσεις σε αυτόν τον κώδικα, αλλά τις κατάργησα από το παράδειγμα για να διατηρήσω τα πάντα καθαρά.

Η έξοδος για την εκτέλεση του παραπάνω κώδικα θα μοιάζει με το παρακάτω:

[ main] onSubscribe(FluxConcatMap.ConcatMapImmediate)[ main] request(unbounded)[actor-tcp-nio-1] onNext(Person(id=35, name=Dan Newton, age=25))[actor-tcp-nio-1] onNext(Person(id=36, name=Laura So, age=23))[actor-tcp-nio-1] onComplete()[actor-tcp-nio-2] findAll - Person(id=35, name=Dan Newton, age=25)[actor-tcp-nio-2] findAll - Person(id=36, name=Laura So, age=23)[actor-tcp-nio-4] findAllByName - Person(id=36, name=Laura So, age=23)[actor-tcp-nio-5] findAllByAge - Person(id=35, name=Dan Newton, age=25)

Μερικά πράγματα που μπορείτε να πάρετε εδώ:

  • onSubscribeκαι requestεμφανίζονται στο κύριο νήμα από το Fluxοποίο κλήθηκε. saveAllΑυτό το εξάγει μόνο αφού έχει συμπεριλάβει τη logλειτουργία. Η προσθήκη αυτού στις άλλες κλήσεις θα οδηγούσε στο ίδιο αποτέλεσμα της σύνδεσης στο κύριο νήμα.
  • Η εκτέλεση που περιέχεται στη συνδρομή συνάρτηση και τα εσωτερικά βήματα του Fluxεκτελούνται σε ξεχωριστά νήματα.

Αυτό δεν είναι πουθενά κοντά σε μια πραγματική αναπαράσταση του τρόπου με τον οποίο θα χρησιμοποιούσατε το Reactive Streams σε μια πραγματική εφαρμογή, αλλά ελπίζουμε ότι δείχνει πώς να τα χρησιμοποιήσετε και δίνει λίγη εικόνα για τον τρόπο εκτέλεσης.

συμπέρασμα

Συμπερασματικά, το Reactive Streams έχει φτάσει σε ορισμένες βάσεις δεδομένων RDBMS χάρη στο πρόγραμμα οδήγησης R2DBC και το Spring Data που δημιουργεί ένα στρώμα στην κορυφή για να κάνει τα πάντα πιο τακτοποιημένα. Χρησιμοποιώντας το Spring Data R2DBC είμαστε σε θέση να δημιουργήσουμε μια σύνδεση σε μια βάση δεδομένων και να αρχίσουμε να την ρωτάμε χωρίς την ανάγκη υπερβολικού κώδικα.

Αν και η Άνοιξη κάνει ήδη πολλά για εμάς, θα μπορούσε να κάνει περισσότερα. Προς το παρόν, δεν διαθέτει υποστήριξη αυτόματης διαμόρφωσης Spring Boot. Αυτό είναι λίγο ενοχλητικό. Όμως, είμαι σίγουρος ότι κάποιος θα το κάνει σύντομα και θα τα κάνει ακόμα καλύτερα από ό, τι είναι ήδη.

Ο κωδικός που χρησιμοποιείται σε αυτήν την ανάρτηση βρίσκεται στο GitHub μου.

Εάν θεωρήσατε χρήσιμη αυτήν την ανάρτηση, μπορείτε να με ακολουθήσετε στο Twitter στο @LankyDanDev για να παρακολουθείτε τις νέες δημοσιεύσεις μου.

Δείτε όλες τις δημοσιεύσεις του Dan Newton

Αρχικά δημοσιεύθηκε στο lankydanblog.com στις 16 Φεβρουαρίου 2019.