Προγραμματισμός

Διατήρηση δεδομένων με αντικείμενα δεδομένων Java, μέρος 1

"Όλα πρέπει να γίνουν όσο το δυνατόν πιο απλά, αλλά όχι απλούστερα."

Albert Einstein

Η ανάγκη διατήρησης δεδομένων που δημιουργούνται κατά το χρόνο εκτέλεσης είναι τόσο παλιά όσο και ο υπολογιστής. Και η ανάγκη αποθήκευσης αντικειμενοστρεφών δεδομένων μειώθηκε όταν ο αντικειμενοστρεφής προγραμματισμός έγινε διάχυτος. Επί του παρόντος, οι περισσότερες σύγχρονες, μη-ασυνήθιστες εφαρμογές χρησιμοποιούν ένα αντικειμενοστρεφές παράδειγμα για τη μοντελοποίηση τομέων εφαρμογών. Αντίθετα, η αγορά βάσεων δεδομένων είναι πιο διαιρεμένη. Τα περισσότερα συστήματα βάσεων δεδομένων χρησιμοποιούν το σχεσιακό μοντέλο, αλλά τα αντικείμενα βάσει αντικειμένων αποδεικνύονται απαραίτητα σε πολλές εφαρμογές. Επιπλέον, διαθέτουμε επίσης κληρονομικά συστήματα στα οποία συχνά χρειαζόμαστε διασύνδεση.

Αυτό το άρθρο προσδιορίζει τα ζητήματα που σχετίζονται με την επιμονή δεδομένων σε περιβάλλοντα συναλλαγών μεσαίου λογισμικού, όπως το J2EE (Java 2 Platform, Enterprise Edition) και δείχνει πώς τα Java Data Objects (JDO) επιλύουν ορισμένα από αυτά τα ζητήματα. Αυτό το άρθρο παρέχει μια επισκόπηση, όχι ένα λεπτομερές σεμινάριο και είναι γραμμένο από την άποψη ενός προγραμματιστή εφαρμογών και όχι ενός σχεδιαστή υλοποίησης JDO.

Διαβάστε ολόκληρη τη σειρά σε Java Data Objects:

  • Μέρος 1. Πιάστε τις ιδιότητες πίσω από ένα ιδανικό στρώμα επιμονής
  • Μέρος 2. Sun JDO εναντίον Castor JDO

Αυτοί οι προγραμματιστές Java, σχεδιαστές και αρχιτέκτονες J2EE που εργάζονται σε συστήματα που πρέπει να αποθηκεύουν δεδομένα σε σχεσιακές βάσεις δεδομένων ή αντικειμένων ή σε άλλα μέσα αποθήκευσης θα πρέπει να διαβάσουν αυτό το άρθρο. Υποθέτω ότι έχετε μια βασική γνώση της Java και κάποια εξοικείωση με αντικείμενα και θέματα ορολογίας.

Διαφανής επιμονή: Γιατί να ενοχλείτε;

Πάνω από μια δεκαετία συνεχών προσπαθειών για γεφύρωση αντικειμενοστρεφούς χρόνου εκτέλεσης και επιμονής δείχνουν πολλές σημαντικές παρατηρήσεις (παρατίθενται κατά σειρά σπουδαιότητας):

  1. Η απόκρυψη τυχόν λεπτομερειών επιμονής και η ύπαρξη ενός καθαρού, απλού αντικειμενοστραφούς API για την εκτέλεση αποθήκευσης δεδομένων είναι υψίστης σημασίας. Δεν θέλουμε να χειριστούμε τις λεπτομέρειες της εμμονής και την εσωτερική αναπαράσταση δεδομένων στα καταστήματα δεδομένων, είτε είναι σχεσιακά, βάσει αντικειμένων ή κάτι άλλο. Γιατί πρέπει να αντιμετωπίσουμε κατασκευές χαμηλού επιπέδου του μοντέλου αποθήκευσης δεδομένων, όπως σειρές και στήλες, και να τις μεταφράζουμε συνεχώς εμπρός και πίσω; Αντ 'αυτού, πρέπει να επικεντρωθούμε σε αυτήν την περίπλοκη εφαρμογή που έπρεπε να παραδώσουμε χθες.
  2. Θέλουμε να χρησιμοποιήσουμε την προσέγγιση plug-and-play με τα καταστήματα δεδομένων μας: Θέλουμε να χρησιμοποιήσουμε διαφορετικούς παρόχους / υλοποιήσεις χωρίς να αλλάξουμε μια γραμμή του πηγαίου κώδικα της εφαρμογής - και ίσως χωρίς να τροποποιήσουμε περισσότερες από μερικές γραμμές στο κατάλληλο αρχείο διαμόρφωσης ( μικρό). Με άλλα λόγια, χρειαζόμαστε ένα βιομηχανικό πρότυπο για την πρόσβαση σε δεδομένα που βασίζονται σε αντικείμενα Java, ένα που παίζει ρόλο παρόμοιο με αυτό που παίζει το JDBC (Java Database Connectivity) ως βιομηχανικό πρότυπο για την πρόσβαση σε δεδομένα που βασίζονται σε SQL.
  3. Θέλουμε να χρησιμοποιήσουμε την προσέγγιση plug-and-play με διαφορετικά παραδείγματα βάσης δεδομένων - δηλαδή, θέλουμε να αλλάξουμε από μια σχεσιακή βάση δεδομένων σε μια αντικειμενοστραφή με ελάχιστες αλλαγές στον κώδικα της εφαρμογής. Αν και είναι ωραίο να υπάρχει, στην πράξη, αυτή η ικανότητα συχνά δεν απαιτείται.

    Ένα σχόλιο εδώ: Ενώ οι σχεσιακές βάσεις δεδομένων απολαμβάνουν τη μεγαλύτερη παρουσία στην αγορά, παρέχοντας ένα ενοποιημένο API επιμονής και επιτρέποντας στους παρόχους αποθήκευσης δεδομένων να ανταγωνίζονται στις δυνατότητες εφαρμογής, έχει νόημα, ανεξάρτητα από το παράδειγμα που χρησιμοποιούν αυτοί οι πάροχοι. Αυτή η προσέγγιση θα μπορούσε τελικά να βοηθήσει να ισορροπήσει το πεδίο ανταγωνισμού μεταξύ των δύο κυρίαρχων ομάδων προμηθευτών βάσεων δεδομένων: το καλά εδραιωμένο σχεσιακό στρατόπεδο και το στρατόπεδο αντικειμενοστρεφής που αγωνίζεται για αγορά.

Οι τρεις ανακαλύψεις που αναφέρονται παραπάνω μας οδηγούν στον καθορισμό ενός επίπεδο επιμονής, ένα πλαίσιο που παρέχει ένα Java API υψηλού επιπέδου για αντικείμενα και σχέσεις ώστε να ξεπεράσουν τη διάρκεια ζωής του περιβάλλοντος χρόνου εκτέλεσης (JVM). Ένα τέτοιο πλαίσιο πρέπει να περιλαμβάνει τις ακόλουθες ιδιότητες:

  • Απλότητα
  • Ελάχιστη εισβολή
  • Διαφάνεια, που σημαίνει ότι το πλαίσιο κρύβει την εφαρμογή αποθήκευσης δεδομένων
  • Σταθερά, συνοπτικά API για αποθήκευση / ανάκτηση / ενημέρωση αντικειμένων
  • Υποστήριξη συναλλαγών, που σημαίνει ότι το πλαίσιο ορίζει τη σημασιολογική συναλλαγή που σχετίζεται με επίμονα αντικείμενα
  • Υποστήριξη τόσο για διαχειριζόμενα (π.χ. διακομιστές εφαρμογών) όσο και για μη διαχειριζόμενα (αυτόνομα) περιβάλλοντα
  • Υποστήριξη για τα απαραίτητα πρόσθετα, όπως caching, ερωτήματα, δημιουργία βασικών κλειδιών και εργαλεία χαρτογράφησης
  • Λογικά τέλη αδειοδότησης - όχι τεχνική απαίτηση, αλλά όλοι γνωρίζουμε ότι τα φτωχά οικονομικά μπορούν να καταστρέψουν ένα εξαιρετικό έργο

Αναλύω τις περισσότερες από τις παραπάνω ιδιότητες στις ακόλουθες ενότητες.

Απλότητα

Τα ποσοστά απλότητας είναι υψηλά στη λίστα των απαιτούμενων χαρακτηριστικών για οποιοδήποτε πλαίσιο λογισμικού ή βιβλιοθήκη (δείτε την εισαγωγική πρόταση αυτού του άρθρου). Η ανάπτυξη κατανεμημένων εφαρμογών είναι ήδη αρκετά δύσκολη και πολλά έργα λογισμικού αποτυγχάνουν λόγω κακής πολυπλοκότητας (και, κατ 'επέκταση, διαχείρισης) κινδύνου. Απλός δεν είναι συνώνυμο με απλοϊκός το λογισμικό πρέπει να έχει όλες τις απαραίτητες δυνατότητες που επιτρέπουν σε έναν προγραμματιστή να κάνει τη δουλειά του / της.

Ελάχιστη εισβολή

Κάθε μόνιμο σύστημα αποθήκευσης εισάγει μια συγκεκριμένη ποσότητα εισβολής στον κώδικα της εφαρμογής. Το ιδανικό επίπεδο επιμονής θα πρέπει να ελαχιστοποιεί την εισβολή για να επιτυγχάνει καλύτερη αρθρωτότητα και, επομένως, λειτουργικότητα plug-and-play.

Για τους σκοπούς αυτού του άρθρου, ορίζω την εισβολή ως:

  • Ο αριθμός των κωδικών για την ανθεκτικότητα διασπάστηκε σε ολόκληρο τον κώδικα της εφαρμογής
  • Η ανάγκη τροποποίησης του μοντέλου αντικειμένου της εφαρμογής σας είτε πρέπει να εφαρμόσετε κάποια διεπαφή επιμονής - όπως Ανθεκτικό ή παρόμοια - ή με μετα-επεξεργασία του παραγόμενου κώδικα

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

Διαφάνεια

Η έννοια της διαρκούς διαφάνειας επιπέδου είναι αρκετά απλή: η εφαρμογή χρησιμοποιεί το ίδιο API ανεξάρτητα από τον τύπο αποθήκευσης δεδομένων (διαφάνεια τύπου αποθήκευσης δεδομένων) ή τον προμηθευτή αποθήκευσης δεδομένων (διαφάνεια αποθήκευσης δεδομένων-προμηθευτή). Η διαφάνεια απλοποιεί σημαντικά τις εφαρμογές και βελτιώνει τη συντηρησιμότητά τους αποκρύπτοντας τις λεπτομέρειες εφαρμογής της αποθήκευσης δεδομένων στο μέγιστο δυνατό βαθμό. Συγκεκριμένα, για τις επικρατούσες σχεσιακές αποθήκες δεδομένων, σε αντίθεση με το JDBC, δεν χρειάζεται να κάνετε κωδικοποιήσεις SQL ή ονόματα στηλών ή να θυμάστε τη σειρά στηλών που επιστράφηκε από ένα ερώτημα. Στην πραγματικότητα, δεν χρειάζεται να γνωρίζετε SQL ή σχεσιακή άλγεβρα, επειδή είναι πολύ συγκεκριμένες για την εφαρμογή. Η διαφάνεια είναι ίσως το πιο σημαντικό χαρακτηριστικό του επιπέδου επιμονής.

Συνεπές, απλό API

Το API επιπέδου επιμονής βασίζεται σε ένα σχετικά μικρό σύνολο λειτουργιών:

  • Στοιχειώδεις λειτουργίες CRUD (δημιουργία, ανάγνωση, ενημέρωση, διαγραφή) σε αντικείμενα πρώτης κατηγορίας
  • Διαχείριση συναλλαγών
  • Διαχείριση εφαρμογών και ταυτότητας αντικειμένων
  • Διαχείριση προσωρινής μνήμης (δηλ. Ανανέωση και έξωση)
  • Δημιουργία και εκτέλεση ερωτημάτων

Ένα παράδειγμα α Επίπεδο επιμονής API:

 το δημόσιο κενό παραμένει (Object obj). // Αποθήκευση obj στο χώρο αποθήκευσης δεδομένων. δημόσιο φορτίο αντικειμένου (κλάση c, αντικείμενο pK) · // Διαβάστε το obj με ένα δεδομένο πρωτεύον κλειδί. δημόσια άκυρη ενημέρωση (Object obj) // Ενημερώστε το τροποποιημένο αντικείμενο obj. δημόσια διαγραφή κενού (Object obj). // Διαγραφή obj από τη βάση δεδομένων. δημόσια Συλλογή εύρεση (Query q); // Βρείτε αντικείμενα που ικανοποιούν τις προϋποθέσεις του ερωτήματός μας. 

Υποστήριξη συναλλαγών

Ένα καλό επίπεδο επιμονής χρειάζεται αρκετές στοιχειώδεις λειτουργίες για να ξεκινήσει, να πραγματοποιήσει ή να επαναφέρει μια συναλλαγή. Εδώ είναι ένα παράδειγμα:

// Οριοθέτηση συναλλαγής (tx). δημόσιο άκυρο startTx (); δημόσιο άκυρο commitx (); δημόσιο άκυρο rollbackTx (); // Επιλέξτε τελικά να κάνετε ένα επίμονο αντικείμενο παροδικό. public void makeTransient (αντικείμενο o) 

Σημείωση: Τα API οριοθέτησης συναλλαγών χρησιμοποιούνται κυρίως σε μη διαχειριζόμενα περιβάλλοντα. Σε διαχειριζόμενα περιβάλλοντα, ο ενσωματωμένος διαχειριστής συναλλαγών αναλαμβάνει συχνά αυτήν τη λειτουργικότητα.

Υποστήριξη διαχειριζόμενων περιβαλλόντων

Τα διαχειριζόμενα περιβάλλοντα, όπως οι διακομιστές εφαρμογών J2EE, έχουν γίνει δημοφιλή στους προγραμματιστές. Ποιος θέλει να γράψει μεσαία επίπεδα από το μηδέν αυτές τις μέρες, όταν διαθέτουμε εξαιρετικούς διακομιστές εφαρμογών; Ένα επίπεδο αξιοπρεπούς επιμονής θα πρέπει να μπορεί να λειτουργεί εντός του κοντέινερ EJB (Enterprise JavaBean) οποιουδήποτε μεγάλου διακομιστή εφαρμογών και να συγχρονίζεται με τις υπηρεσίες του, όπως το JNDI (Java Naming and Directory Interface) και τη διαχείριση συναλλαγών.

Ερωτήματα

Το API θα πρέπει να μπορεί να εκδίδει αυθαίρετα ερωτήματα για αναζητήσεις δεδομένων. Θα πρέπει να περιλαμβάνει μια ευέλικτη και ισχυρή, αλλά εύχρηστη, γλώσσα - το API πρέπει να χρησιμοποιεί αντικείμενα Java, όχι πίνακες SQL ή άλλες παραστάσεις αποθήκευσης δεδομένων ως τυπικές παραμέτρους ερωτήματος.

Διαχείριση προσωρινής μνήμης

Η διαχείριση της προσωρινής μνήμης μπορεί να κάνει θαύματα για την απόδοση της εφαρμογής. Ένα επίπεδο επιμονής ήχου θα πρέπει να παρέχει πλήρη αποθήκευση δεδομένων, καθώς και κατάλληλα API για να ορίσετε την επιθυμητή συμπεριφορά, όπως επίπεδα κλειδώματος, πολιτικές εξώθησης, τεμπέλης φόρτωσης και υποστήριξη κατανεμημένης προσωρινής αποθήκευσης.

Κύρια δημιουργία κλειδιών

Η παροχή αυτόματης δημιουργίας ταυτότητας για δεδομένα είναι μία από τις πιο κοινές υπηρεσίες επιμονής. Κάθε επίπεδο αξιοπρεπούς επιμονής θα πρέπει να παρέχει δημιουργία ταυτότητας, με υποστήριξη για όλους τους κύριους βασικούς αλγόριθμους δημιουργίας κλειδιών. Η δημιουργία βασικών κλειδιών είναι ένα καλά ερευνημένο ζήτημα και υπάρχουν πολλοί αλγόριθμοι πρωτεύοντος κλειδιού.

Χαρτογράφηση, μόνο για σχεσιακές βάσεις δεδομένων

Με σχεσιακές βάσεις δεδομένων, προκύπτει ένα ζήτημα χαρτογράφησης δεδομένων: η ανάγκη μετάφρασης αντικειμένων σε πίνακες και η μετάφραση σχέσεων, όπως εξαρτήσεις και αναφορές, σε πρόσθετες στήλες ή πίνακες. Αυτό είναι ένα ασήμαντο πρόβλημα από μόνο του, ειδικά με πολύπλοκα μοντέλα αντικειμένων. Το θέμα του αντικειμενο-σχεσιακού μοντέλου αναντιστοιχία αντίστασης υπερβαίνει το πεδίο εφαρμογής αυτού του άρθρου, αλλά είναι καλά δημοσιευμένο. Δείτε τους πόρους για περισσότερες πληροφορίες.

Ο ακόλουθος κατάλογος πρόσθετων στοιχείων που σχετίζονται με τη χαρτογράφηση και / ή τις σχετικές αποθήκες δεδομένων δεν απαιτείται στο επίπεδο επιμονής, αλλά διευκολύνουν τη ζωή ενός προγραμματιστή:

  • Ένα εργαλείο χαρτογράφησης GUI (γραφική διεπαφή χρήστη)
  • Γεννήτριες κώδικα: Αυτόματη δημιουργία DDL (γλώσσα περιγραφής δεδομένων) για δημιουργία πινάκων βάσης δεδομένων ή αυτόματη δημιουργία κώδικα Java και αντιστοίχιση αρχείων από το DDL
  • Κύριες γεννήτριες κλειδιών: Υποστήριξη πολλαπλών αλγορίθμων δημιουργίας κλειδιών, όπως UUID, HIGH-LOW και SEQUENCE
  • Υποστήριξη για δυαδικά μεγάλα αντικείμενα (BLOBs) και μεγάλα αντικείμενα που βασίζονται σε χαρακτήρες (CLOBs)
  • Αυτοαναφορές σχέσεις: Ένα αντικείμενο τύπου Μπαρ αναφορά σε άλλο αντικείμενο τύπου Μπαρ, για παράδειγμα
  • Υποστήριξη Raw SQL: Περάστε τα ερωτήματα SQL

Παράδειγμα

Το παρακάτω απόσπασμα κώδικα δείχνει τον τρόπο χρήσης του API επιπέδου επιμονής. Ας υποθέσουμε ότι έχουμε το ακόλουθο μοντέλο τομέα: Μια εταιρεία έχει μία ή περισσότερες τοποθεσίες και κάθε τοποθεσία έχει έναν ή περισσότερους χρήστες. Τα ακόλουθα θα μπορούσαν να είναι ένα παράδειγμα παραδείγματος κώδικα:

PersistenceManager pm = PMFactory.initialize (..); Εταιρεία co = νέα εταιρεία ("MyCompany"); Τοποθεσία l1 = νέα Τοποθεσία1 ("Βοστώνη"); Τοποθεσία l2 = νέα τοποθεσία ("Νέα Υόρκη"); // Δημιουργήστε χρήστες. Χρήστης u1 = νέος χρήστης ("Mark"); Χρήστης u2 = νέος χρήστης ("Τομ"); Χρήστης u3 = νέος χρήστης ("Mary"); // Προσθήκη χρηστών. Ένας χρήστης μπορεί να "ανήκει" μόνο σε μία τοποθεσία. L1.addUser (u1); L1.addUser (u2); L2.addUser (u3); // Προσθέστε τοποθεσίες στην εταιρεία. co.addLocation (l1); co.addLocation (l2); // Και τέλος, αποθηκεύστε ολόκληρο το δέντρο στη βάση δεδομένων. pm.persist (γ); 

Σε μια άλλη συνεδρία, μπορείτε να αναζητήσετε εταιρείες που χρησιμοποιούν τον χρήστη Κάποιος:

PersistenceManager pm = PMFactory.initialize (...) Εταιρείες συλλογής EmployingToms = pm.find ("company.location.user.name = 'Tom'"); 

Για σχεσιακές αποθήκες δεδομένων, πρέπει να δημιουργήσετε ένα επιπλέον αρχείο αντιστοίχισης. Μπορεί να μοιάζει με αυτό:

    Χρήστης τοποθεσιών εταιρείας 

Το στρώμα επιμονής φροντίζει τα υπόλοιπα, τα οποία περιλαμβάνουν τα ακόλουθα:

  • Εύρεση εξαρτημένων ομάδων αντικειμένων
  • Διαχείριση ταυτότητας αντικειμένου εφαρμογής
  • Διαχείριση μόνιμων ταυτοτήτων αντικειμένων (πρωτεύοντα κλειδιά)
  • Επιμονή κάθε αντικειμένου με την κατάλληλη σειρά
  • Παροχή διαχείρισης προσωρινής μνήμης
  • Παρέχοντας το κατάλληλο πλαίσιο συναλλαγών (δεν θέλουμε να παραμείνει μόνο ένα μέρος του δέντρου αντικειμένων, έτσι;)
  • Παροχή επιλογών κλειδώματος που επιλέγονται από τον χρήστη