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

Java επιμονή με JPA και Hibernate, Μέρος 1: Οντότητες και σχέσεις

Το Java Persistence API (JPA) είναι μια προδιαγραφή Java που γεφυρώνει το χάσμα μεταξύ σχεσιακών βάσεων δεδομένων και αντικειμενοστραφούς προγραμματισμού. Αυτό το σεμινάριο δύο μερών εισάγει το JPA και εξηγεί πώς τα αντικείμενα Java μοντελοποιούνται ως οντότητες JPA, πώς ορίζονται οι σχέσεις οντοτήτων και πώς να χρησιμοποιηθούν τα JPA EntityManager με το μοτίβο Repository στις εφαρμογές Java.

Σημειώστε ότι αυτό το σεμινάριο χρησιμοποιεί το Hibernate ως πάροχο JPA. Οι περισσότερες έννοιες μπορούν να επεκταθούν σε άλλα πλαίσια επιμονής Java.

Τι είναι το JPA;

Ανατρέξτε στην ενότητα "Τι είναι το JPA; Εισαγωγή στο Java Persistence API" για να μάθετε σχετικά με την εξέλιξη του JPA και σχετικά συναφή πλαίσια, συμπεριλαμβανομένου του EJB 3.0. και JDBC.

Αντικειμενικές σχέσεις στο JPA

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

Τα αντικείμενα Java σε σχεσιακό πλαίσιο βάσης δεδομένων ορίζονται ως οντότητες. Οι οντότητες τοποθετούνται σε πίνακες όπου καταλαμβάνουν στήλες και σειρές. Χρησιμοποιούν προγραμματιστές ξένα κλειδιά και εγγραφείτε σε τραπέζια για να καθορίσουμε τις σχέσεις μεταξύ οντοτήτων - συγκεκριμένα σχέσεις one-to-one, one-to-many και many-to-many. Μπορούμε επίσης να χρησιμοποιήσουμε το SQL (Structured Query Language) για να ανακτήσουμε και να αλληλεπιδράσουμε με δεδομένα σε μεμονωμένους πίνακες και σε πολλαπλούς πίνακες, χρησιμοποιώντας περιορισμούς ξένου κλειδιού. Το σχεσιακό μοντέλο είναι επίπεδο, αλλά οι προγραμματιστές μπορούν να γράψουν ερωτήματα για την ανάκτηση δεδομένων και την κατασκευή αντικειμένων από αυτά τα δεδομένα.

Αντιστοιχία αντίστασης αντικειμένων-σχέσεων

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

  • Εάν ένα αντικείμενο περιέχει ένα άλλο αντικείμενο, το ορίζουμε μέσω αυτού ενθυλάκωση--ένα έχει ένα σχέση.
  • Εάν ένα αντικείμενο είναι μια εξειδίκευση ενός άλλου αντικειμένου, το ορίζουμε μέσω αυτού κληρονομία--ένα είναι ένα σχέση.

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

ORM: Αντιστοίχιση-σχεσιακής χαρτογράφησης

Η αναντιστοιχία μεταξύ αντικειμενοστρεφούς σχεδιασμού και σχεσιακής μοντελοποίησης βάσεων δεδομένων οδήγησε σε μια κατηγορία εργαλείων που αναπτύχθηκαν ειδικά για αντικειμενοσχεσιακή χαρτογράφηση (ORM). Τα εργαλεία ORM όπως το Hibernate, το EclipseLink και το iBatis μεταφράζουν μοντέλα σχεσιακών βάσεων δεδομένων, συμπεριλαμβανομένων οντοτήτων και των σχέσεών τους, σε αντικειμενοστρεφή μοντέλα. Πολλά από αυτά τα εργαλεία υπήρχαν πριν από την προδιαγραφή JPA, αλλά χωρίς πρότυπο τα χαρακτηριστικά τους εξαρτώνταν από τον προμηθευτή.

Το Java Persistence API (JPA) κυκλοφόρησε για πρώτη φορά ως μέρος του EJB 3.0 το 2006, προσφέρει έναν τυπικό τρόπο σχολιασμού αντικειμένων, ώστε να μπορούν να χαρτογραφηθούν και να αποθηκευτούν σε σχεσιακή βάση δεδομένων. Η προδιαγραφή ορίζει επίσης ένα κοινό κατασκεύασμα για αλληλεπίδραση με βάσεις δεδομένων. Η ύπαρξη προτύπου ORM για Java προσφέρει συνέπεια στις υλοποιήσεις προμηθευτών, ενώ επιτρέπει επίσης ευελιξία και πρόσθετα. Για παράδειγμα, ενώ η αρχική προδιαγραφή JPA ισχύει για σχεσιακές βάσεις δεδομένων, ορισμένες εφαρμογές προμηθευτών έχουν επεκτείνει το JPA για χρήση με βάσεις δεδομένων NoSQL.

Εξέλιξη της JPA

Η πρώτη έκδοση του JPA, έκδοση 1.0, δημοσιεύθηκε το 2006 μέσω της Java Community Process (JCP) ως Java Specification Request (JSR) 220. Η έκδοση 2.0 (JSR 317) δημοσιεύθηκε το 2009, έκδοση 2.1 (JSR 338) το 2013, και η έκδοση 2.2 (μια έκδοση συντήρησης του JSR 338) δημοσιεύθηκε το 2017. Το JPA 2.2 επιλέχθηκε για ένταξη και συνεχιζόμενη ανάπτυξη στην Τζακάρτα ΕΕ.

Ξεκινώντας με το JPA

Το Java Persistence API είναι μια προδιαγραφή και όχι μια εφαρμογή: καθορίζει μια κοινή αφαίρεση που μπορείτε να χρησιμοποιήσετε στον κώδικά σας για να αλληλεπιδράσετε με προϊόντα ORM. Αυτή η ενότητα εξετάζει μερικά από τα σημαντικά μέρη της προδιαγραφής JPA.

Θα μάθετε πώς να:

  • Ορίστε οντότητες, πεδία και πρωτεύοντα κλειδιά στη βάση δεδομένων.
  • Δημιουργήστε σχέσεις μεταξύ οντοτήτων στη βάση δεδομένων.
  • Εργαστείτε με το EntityManager και τις μεθόδους του.

Καθορισμός οντοτήτων

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

 @Entity δημόσια τάξη Βιβλίο {...} 

Από προεπιλογή, αυτή η οντότητα θα αντιστοιχιστεί στο Βιβλίο πίνακα, όπως καθορίζεται από το δεδομένο όνομα τάξης. Εάν θέλετε να αντιστοιχίσετε αυτήν την οντότητα σε έναν άλλο πίνακα (και, προαιρετικά, ένα συγκεκριμένο σχήμα) θα μπορούσατε να χρησιμοποιήσετε το @Τραπέζι σχολιασμός για να γίνει αυτό. Δείτε πώς θα χαρτογραφήσετε το Βιβλίο τάξη σε πίνακα ΒΙΒΛΙΑ:

 @Entity @Table (name = "BOOKS") δημόσια τάξη Βιβλίο {...} 

Εάν ο πίνακας BOOKS βρισκόταν στο σχήμα PUBLISHING, θα μπορούσατε να προσθέσετε το σχήμα στο @Τραπέζι σχόλιο:

 @ Πίνακας (όνομα = "ΒΙΒΛΙΑ", σχήμα = "ΕΚΔΟΣΗ") 

Αντιστοίχιση πεδίων σε στήλες

Με την οντότητα που έχει αντιστοιχιστεί σε έναν πίνακα, η επόμενη εργασία σας είναι να ορίσετε τα πεδία της. Πεδία ορίζονται ως μεταβλητές μέλους στην τάξη, με το όνομα κάθε πεδίου να αντιστοιχίζεται σε ένα όνομα στήλης στον πίνακα. Μπορείτε να παρακάμψετε αυτήν την προεπιλεγμένη αντιστοίχιση χρησιμοποιώντας το @Στήλη σχολιασμός, όπως φαίνεται εδώ:

 @Entity @Table (name = "BOOKS") δημόσια τάξη Βιβλίο {private String name; @Column (name = "ISBN_NUMBER") ιδιωτική συμβολοσειρά isbn; ...} 

Σε αυτό το παράδειγμα, αποδεχτήκαμε την προεπιλεγμένη αντιστοίχιση για το όνομα χαρακτηριστικό αλλά καθορίστηκε μια προσαρμοσμένη αντιστοίχιση για το isbn Χαρακτηριστικό. ο όνομα το χαρακτηριστικό θα αντιστοιχιστεί στο όνομα στήλη, αλλά το isbn Το χαρακτηριστικό θα αντιστοιχιστεί στη στήλη ISBN_NUMBER.

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

Καθορισμός του πρωτεύοντος κλειδιού

Μία από τις απαιτήσεις για έναν σχεσιακό πίνακα βάσης δεδομένων είναι ότι πρέπει να περιέχει ένα πρωτεύων κλειδίή ένα κλειδί που προσδιορίζει μοναδικά μια συγκεκριμένη σειρά στη βάση δεδομένων. Στο JPA, χρησιμοποιούμε το @Ταυτότητα σχολιασμός για να ορίσετε ένα πεδίο ως το βασικό κλειδί του πίνακα. Το πρωτεύον κλειδί απαιτείται να είναι ένας πρωτόγονος τύπος Java, ένα πρωτόγονο περιτύλιγμα, όπως Ακέραιος αριθμός ή Μακρύς, ένα Σειρά, ένα Ημερομηνία, ένα BigInteger, ή α Μεγάλο Δεκαδικό.

Σε αυτό το παράδειγμα, χαρτογραφούμε το ταυτότητα χαρακτηριστικό, το οποίο είναι ένα Ακέραιος αριθμός, στη στήλη Αναγνωριστικό στον πίνακα ΒΙΒΛΙΑ:

 @Entity @Table (name = "BOOKS") δημόσια τάξη Κράτηση {@Id private Integer id; ιδιωτικό όνομα συμβολοσειράς; @Column (name = "ISBN_NUMBER") ιδιωτική συμβολοσειρά isbn; ...} 

Είναι επίσης δυνατό να συνδυαστεί το @Ταυτότητα σχολιασμός με το @Στήλη σχολιασμός για αντικατάσταση της αντιστοίχισης ονόματος-στήλης του πρωτεύοντος κλειδιού.

Σχέσεις μεταξύ οντοτήτων

Τώρα που ξέρετε πώς να ορίσετε μια οντότητα, ας δούμε πώς να δημιουργήσετε σχέσεις μεταξύ οντοτήτων. Το JPA ορίζει τέσσερις σχολιασμούς για τον ορισμό οντοτήτων:

  • @Ενα προς ένα
  • @OneToMany
  • @ManyToOne
  • @ManyToMany

Σχέσεις ένας προς έναν

ο @Ενα προς ένα ο σχολιασμός χρησιμοποιείται για τον καθορισμό μιας σχέσης ένας προς έναν μεταξύ δύο οντοτήτων. Για παράδειγμα, μπορεί να έχετε ένα Χρήστης οντότητα που περιέχει το όνομα χρήστη, το email και τον κωδικό πρόσβασης, αλλά μπορεί να θέλετε να διατηρήσετε επιπλέον πληροφορίες σχετικά με έναν χρήστη (όπως ηλικία, φύλο και αγαπημένο χρώμα) σε ξεχωριστό Προφίλ χρήστη οντότητα. ο @Ενα προς ένα Ο σχολιασμός διευκολύνει την ανάλυση των δεδομένων και των οντοτήτων σας με αυτόν τον τρόπο.

ο Χρήστης Η παρακάτω τάξη έχει ένα Προφίλ χρήστη παράδειγμα. ο Προφίλ χρήστη χάρτες σε ένα Χρήστης παράδειγμα.

 @Entity δημόσια τάξη Χρήστης {@Id ιδιωτικό Integer id; ιδιωτικό email συμβολοσειράς; ιδιωτικό όνομα συμβολοσειράς; ιδιωτικός κωδικός πρόσβασης συμβολοσειράς; @OneToOne (mappedBy = "user") ιδιωτικό προφίλ UserProfile; ...} 
 @Entity δημόσια κλάση UserProfile {@Id ιδιωτικό Integer id; ιδιωτική ηλικία ιδιωτικό φύλο String; ιδιωτικό String favouriteColor; @OneToOne ιδιωτικός χρήστης χρήστη; ...} 

Ο πάροχος JPA χρησιμοποιεί Προφίλ χρήστη'μικρό χρήστης πεδίο στο χάρτη Προφίλ χρήστη προς την Χρήστης. Η χαρτογράφηση καθορίζεται στο χαρτογραφημένος χαρακτηριστικό στο @Ενα προς ένα σχόλιο.

Σχέσεις «ένα προς πολλά» και πολλά προς ένα

ο @OneToMany και @ManyToOne Οι σχολιασμοί διευκολύνουν και τις δύο πλευρές της ίδιας σχέσης. Εξετάστε ένα παράδειγμα όπου a Βιβλίο μπορεί να έχει μόνο ένα Συντάκτης, αλλά ένα Συντάκτης μπορεί να έχει πολλά βιβλία. ο Βιβλίο οντότητα θα ορίσει α @ManyToOne σχέση με Συντάκτης και το Συντάκτης οντότητα θα ορίσει α @OneToMany σχέση με Βιβλίο.

 @Entity δημόσια τάξη Βιβλίο {@Id ιδιωτικό Integer id; ιδιωτικό όνομα συμβολοσειράς; @ManyToOne @JoinColumn (name = "AUTHOR_ID") ιδιωτικός συντάκτης συγγραφέας; ...} 
 @Entity δημόσια τάξη Συγγραφέας {@Id @GeneratedValue ιδιωτικό Integer id; ιδιωτικό όνομα συμβολοσειράς; @OneToMany (mappedBy = "author") ιδιωτικά βιβλία λίστας = νέο ArrayList (); ...} 

Σε αυτήν την περίπτωση, το Συντάκτης Η τάξη διατηρεί μια λίστα με όλα τα βιβλία που γράφτηκαν από αυτόν τον συγγραφέα και το Βιβλίο Το class διατηρεί μια αναφορά στον μοναδικό του συγγραφέα. Επιπλέον, το @JoinColumn καθορίζει το όνομα της στήλης στο Βιβλίο πίνακα για να αποθηκεύσετε το αναγνωριστικό του Συντάκτης.

Πολλές σε πολλές σχέσεις

Τέλος, το @ManyToMany Ο σχολιασμός διευκολύνει τη σχέση μεταξύ πολλών οντοτήτων. Εδώ είναι μια περίπτωση όπου Βιβλίο οντότητα έχει πολλαπλάσια Συντάκτηςμικρό:

 @Entity δημόσια τάξη Βιβλίο {@Id ιδιωτικό Integer id; ιδιωτικό όνομα συμβολοσειράς; @ManyToMany @JoinTable (name = "BOOK_AUTHORS", joinColumns = @ JoinColumn (name = "BOOK_ID"), inverseJoinColumns = @ JoinColumn (name = "AUTHOR_ID")) ιδιωτικοί συντάκτες συνόλου = νέο HashSet (); ...} 
 @Entity δημόσια τάξη Συγγραφέας {@Id @GeneratedValue ιδιωτικό Integer id; ιδιωτικό όνομα συμβολοσειράς; @ManyToMany (mappedBy = "author") ιδιωτικό σύνολο βιβλίων = νέο HashSet (); ...} 

Σε αυτό το παράδειγμα, δημιουργούμε έναν νέο πίνακα, ΚΡΑΤΗΣΗ, με δύο στήλες: BOOK_ID και AUTHOR_ID. Χρησιμοποιώντας το Συμμετοχή σε στήλες και inverseJoinColumns Τα χαρακτηριστικά γνωστοποιούν στο πλαίσιο JPA πώς να χαρτογραφήσετε αυτές τις τάξεις σε μια σχέση πάρα-προς-πολλά. ο @ManyToMany σχολιασμός στο Συντάκτης η τάξη αναφέρει το πεδίο στο Βιβλίο τάξη που διαχειρίζεται τη σχέση? δηλαδή το συγγραφείς ιδιοκτησία.

Αυτή είναι μια γρήγορη επίδειξη για ένα αρκετά περίπλοκο θέμα. Θα βουτήξουμε περαιτέρω στο @JoinTable και @JoinColumn σχολιασμοί στο επόμενο άρθρο.

Εργασία με το EntityManager

EntityManager είναι η κλάση που εκτελεί αλληλεπιδράσεις βάσης δεδομένων σε JPA. Αρχικοποιείται μέσω ενός αρχείου διαμόρφωσης με το όνομα εμμονή.xml. Αυτό το αρχείο βρίσκεται στο ΜΕΤΑ-ΙΝΦ φάκελο στο CLASSPATH, το οποίο συνήθως συσκευάζεται στο αρχείο JAR ή WAR. ο εμμονή.xml το αρχείο περιέχει:

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

Ας δούμε ένα παράδειγμα.

Διαμόρφωση του EntityManager

Πρώτον, δημιουργούμε ένα EntityManager χρησιμοποιώντας το EntityManagerFactory ανακτήθηκε από το επιμονή τάξη:

 EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory ("Βιβλία"); EntityManager entityManager = entityManagerFactory.createEntityManager (); 

Σε αυτήν την περίπτωση έχουμε δημιουργήσει ένα EntityManager που συνδέεται με τη μονάδα επιμονής "Βιβλία", την οποία έχουμε διαμορφώσει στο εμμονή.xml αρχείο.

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

  • εύρημα ανακτά μια οντότητα από το πρωτεύον κλειδί της.
  • createQuery δημιουργεί ένα Ερώτηση περίπτωση που μπορεί να χρησιμοποιηθεί για την ανάκτηση οντοτήτων από τη βάση δεδομένων.
  • createNamedQuery φορτώνει a Ερώτηση που έχει οριστεί στο α @NamedQuery σχολιασμός μέσα σε μία από τις οντότητες επιμονής. Ερωτήματα με όνομα παρέχει έναν καθαρό μηχανισμό για τη συγκέντρωση ερωτημάτων JPA στον ορισμό της κλάσης επιμονής στην οποία θα εκτελεστεί το ερώτημα.
  • getTransaction ορίζει ένα Συναλλαγή οντοτήτων για χρήση στις αλληλεπιδράσεις της βάσης δεδομένων σας. Ακριβώς όπως οι συναλλαγές βάσης δεδομένων, συνήθως θα ξεκινήσετε τη συναλλαγή, θα εκτελέσετε τις λειτουργίες σας και, στη συνέχεια, είτε δεσμεύσετε είτε θα επαναφέρετε τη συναλλαγή σας. ο getTransaction () μέθοδος σας επιτρέπει να αποκτήσετε πρόσβαση σε αυτήν τη συμπεριφορά στο επίπεδο του EntityManager, αντί για τη βάση δεδομένων.
  • συγχώνευση() προσθέτει μια οντότητα στο πλαίσιο εμμονής, έτσι ώστε όταν πραγματοποιείται η συναλλαγή, η οντότητα θα παραμείνει στη βάση δεδομένων. Οταν χρησιμοποιείτε συγχώνευση(), τα αντικείμενα δεν διαχειρίζονται.
  • επιμένω προσθέτει μια οντότητα στο πλαίσιο εμμονής, έτσι ώστε όταν πραγματοποιείται η συναλλαγή, η οντότητα θα παραμείνει στη βάση δεδομένων. Οταν χρησιμοποιείτε επιμένω(), τα αντικείμενα διαχειρίζονται.
  • φρεσκάρω ανανεώνει την κατάσταση της τρέχουσας οντότητας από τη βάση δεδομένων.
  • ξεπλύνετε συγχρονίζει την κατάσταση του περιβάλλοντος επιμονής με τη βάση δεδομένων.

Μην ανησυχείτε για την ολοκλήρωση όλων αυτών των μεθόδων ταυτόχρονα. Θα τους γνωρίσετε δουλεύοντας απευθείας με το EntityManager, το οποίο θα κάνουμε περισσότερα στην επόμενη ενότητα.