CodeGym /בלוג Java /Random-HE /אפליקציית Hibernate הראשונה שלך
John Squirrels
רָמָה
San Francisco

אפליקציית Hibernate הראשונה שלך

פורסם בקבוצה
במאמר זה, תכירו את אחת מהמסגרות הארגוניות הפופולריות ביותר עבור Java ותצרו את יישום Hibernate הראשון שלכם. מעולם לא שמעתי על Hibernate? או שאולי שמעתם עליו, אך לא השתמשתם בו? או שאולי ניסית להשתמש בו, אך נכשלת? בשלושת המקרים - ברוכים הבאים מתחת לגזרה :) אפליקציית Hibernate הראשונה שלך - 1 שלום לכולם! במאמר זה, אדבר על התכונות העיקריות של מסגרת Hibernate ואעזור לך לכתוב את המיני-יישום הראשון שלך. בשביל זה, אנחנו צריכים:
  1. IntelliJ IDEA Ultimate Edition
    הורד אותה מהאתר הרשמי והפעל את גרסת הניסיון ל-30 יום.
  2. PostgreSQL - אחת ממערכות ניהול מסדי הנתונים המודרניות הפופולריות ביותר (DBMS)
  3. Maven (כבר מחובר ל-IDEA)
  4. קצת סבלנות.
ליתר בטחון, פרסמתי את קוד האפליקציה ב- GitHub . המאמר מיועד בעיקר לאלה שמעולם לא עבדו עם הטכנולוגיה הזו לפני כן, אז צמצמתי את כמות הקוד. בואו נתחיל!

מה זה Hibernate?

זהו אחד המימושים הפופולריים ביותר של מיפוי יחסי אובייקט (ORM). מיפוי יחסי אובייקט מגדיר את הקשר בין אובייקטי תוכנה לרשומות מסד נתונים. כמובן של Hibernate יש פונקציונליות רחבה מאוד, אבל נתמקד בפונקציות הפשוטות ביותר. המטרה שלנו היא ליצור יישום CRUD (צור, קרא, עדכן, מחק) שתוכל:
  1. צור משתמשים (User), חפש אותם במסד הנתונים לפי מזהה, עדכן את הנתונים שלהם במסד הנתונים ומחק אותם מהמסד.
  2. הקצה אובייקטים מכונית (אוטומטי) למשתמשים. צור, עדכן, מצא ומחק מכוניות ממסד הנתונים.
  3. בנוסף, היישום אמור להסיר אוטומטית מכוניות "חסרות בעלים" ממסד הנתונים. במילים אחרות, כאשר משתמש נמחק, יש למחוק גם את כל המכוניות השייכות לאותו משתמש ממסד הנתונים.
הפרויקט שלנו יהיה בנוי כך: אפליקציית Hibernate הראשונה שלך - 2כפי שאתה יכול לראות, שום דבר לא מסובך. 6 מחלקות + קובץ אחד עם הגדרות. ראשית, צור פרויקט חדש של Maven ב-IntelliJ IDEA. קובץ -> פרויקט חדש. בחר Maven מבין סוגי הפרויקטים המוצעים ועבור לשלב הבא. אפליקציית Hibernate הראשונה שלך - 3Apache Maven היא מסגרת לבנייה אוטומטית של פרויקטים על סמך תיאור המבנה שלהם בקבצי POM. כל המבנה של הפרויקט שלך יתואר ב-pom.xml, קובץ ש-IDEA בעצמה תיצור בשורש הפרויקט שלך. בהגדרות הפרויקט, עליך לציין את הגדרות Maven הבאות: groupId ו-artifactId. בפרויקטים, groupId הוא בדרך כלל תיאור של החברה או היחידה העסקית. שם הדומיין של החברה או האתר יכול להיכנס לכאן. בתורו, artifactId הוא שם הפרויקט. עבור groupdId, אתה יכול להזין com.yourNickname.codegym. זה לא ישפיע על היישום. עבור artifactId, בחר כל שם פרויקט שאתה אוהב. ניתן להשאיר את הגרסה ללא שינוי. אפליקציית Hibernate הראשונה שלך - 4במסך האחרון, פשוט אשר את הנתונים שהוזנו קודם לכן. אפליקציית Hibernate הראשונה שלך - 5אז, יצרנו את הפרויקט. עכשיו כל מה שנותר לעשות הוא לכתוב קצת קוד ולגרום לו לעבוד :) דבר ראשון: אם אנחנו רוצים ליצור אפליקציה שעובדת עם מסד נתונים, אנחנו בהחלט לא יכולים בלי מסד נתונים! הורד את PostgreSQL מכאן ( אני משתמש בגרסה 9). ל-PostgreSQL יש ברירת מחדל למשתמש 'postgres' - תצטרך לחשוב על סיסמה עבורו בעת ההתקנה. אל תשכח את הסיסמה. נצטרך את זה אחר כך! (באופן כללי, שימוש במסד הנתונים המוגדר כברירת מחדל ביישומים הוא תרגול גרוע, אך נעשה זאת על מנת להפחית את מספר הגורמים לכיבים על ידי יצירת מסד נתונים משלך). אם אינך חברים עם שורת הפקודה ושאילתות SQL, יש חדשות טובות. IntelliJ IDEA מספק ממשק משתמש מתאים לחלוטין לעבודה עם מסד הנתונים. זה נראה כך: אפליקציית Hibernate הראשונה שלך - 6(ממוקם בחלונית הימנית של IDEA, הכרטיסייה מסד נתונים). כדי ליצור חיבור, לחץ על "+" ובחר במקור הנתונים שלנו (PostgeSQL). מלא את השדות עבור המשתמש ומסד הנתונים ("postgres" עבור שניהם) והזן את הסיסמה שהוגדרה במהלך ההתקנה של PostgreSQL. במידת הצורך, הורד את מנהל ההתקן של Postgres. אתה יכול לעשות זאת באותו עמוד. לחץ על "בדוק חיבור" כדי לוודא שחיבור מסד הנתונים נוצר. אם אתה רואה את "מוצלח", המשך הלאה. כעת ניצור את הטבלאות שאנו צריכים. יהיו בסך הכל שניים: משתמשים ומכוניות. פרמטרים לטבלת המשתמשים: אפליקציית Hibernate הראשונה שלך - 7שימו לב שמזהה הוא המפתח הראשי. אם אינך יודע מהו המפתח הראשי ב-SQL, חפש בגוגל. זה חשוב. הגדרות לטבלת מכוניות: אפליקציית Hibernate הראשונה שלך - 8עבור טבלת המכוניות, עליך להגדיר מפתח זר. זה ישמש לקשר בין הטבלאות שלנו. אני ממליץ לך לקרוא עוד על זה. במילים פשוטות, זה מתייחס לטבלה חיצונית, במקרה שלנו, משתמשים. אם מכונית שייכת למשתמש עם id = 1, אזי השדה user_id של האוטו'ים יהיה שווה ל-1. כך אנו מקשרים משתמשים עם המכוניות שלהם באפליקציה שלנו. בטבלת המכוניות שלנו, השדה user_id ישמש כמפתח הזר. זה יפנה לשדה המזהה של טבלת המשתמשים. אפליקציית Hibernate הראשונה שלך - 9אז, יצרנו מסד נתונים עם שתי טבלאות. מה שנשאר זה להבין איך לנהל את זה מקוד Java. נתחיל בקובץ pom.xml, בו עלינו לכלול את הספריות הדרושות (ב-Maven הן נקראות dependencies). כל הספריות מאוחסנות במאגר המרכזי של מייבן. הספריות שאתה מציין ב-pom.xml זמינות לשימושך בפרויקט. ה-pom.xml שלך אמור להיראות כך: אפליקציית Hibernate הראשונה שלך - 10שום דבר מסובך, כפי שאתה יכול לראות. הוספנו רק 2 יחסי תלות - לשימוש ב-PostgreSQL וב-Hibernate. כעת נעבור לקוד Java. צור את כל החבילות והשיעורים הדרושים בפרויקט. כדי להתחיל, אנחנו צריכים מודל נתונים: ה- Userand Autoclasses.
package models;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table (name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @Column(name = "name")
    private String name;
    // You can omit the Column attribute if the name property matches the column name in the table
    private int age;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Auto> autos;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
        autos = new ArrayList<>();
    }

    public void addAuto(Auto auto) {
        auto.setUser(this);
        autos.add(auto);
    }

    public void removeAuto(Auto auto) {
        autos.remove(auto);
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<Auto> getAutos() {
        return autos;
    }

    public void setAutos(List<Auto> autos) {
        this.autos = autos;
    }

    @Override
    public String toString() {
        return "models.User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package models;

import javax.persistence.*;

@Entity
@Table(name = "autos")
public class Auto {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column (name = "model")
    private String model;

    // You can omit the Column attribute if the name property matches the column name in the table
    private String color;


    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    public Auto() {
    }

    public Auto(String model, String color) {
        this.model = model;
        this.color = color;
    }

    public int getId() {
        return id;
    }

    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return color + " " + model;
    }
}
כפי שאתה יכול לראות, לשיעורים יש הרבה הערות לא ברורות. בואו נתחיל לחפור בהם. עבורנו, ההערה העיקרית היא @Entity. קרא על זה בויקיפדיה ולמד הכל בעל פה. זה היסוד של הקרן. הערה זו מאפשרת למפות אובייקטים של מחלקת Java שלך למסד נתונים. כדי שכיתה תהיה ישות, עליה לעמוד בדרישות הבאות:
  • חייב להיות בו בנאי ריק ( publicאו protected)
  • זה לא יכול להיות מקונן, ממשק אוenum
  • זה לא יכול להיות finalולא יכול להיות finalשדות/מאפיינים
  • עליו לכלול לפחות שדה @Id אחד.
בדוק את שיעורי הישות שלך: הם מקומות פופולריים מאוד לירות לעצמך ברגל. קל מאוד לשכוח משהו. יתר על כן, ישות יכולה לעשות את הפעולות הבאות:
  • יכולים להיות בו בנאים לא ריקים
  • זה יכול לרשת ולהיות בירושה
  • זה יכול לקבל שיטות אחרות ולהטמיע ממשקים.
כפי שאתה יכול לראות, המחלקה Userדומה מאוד לטבלת המשתמשים. יש בו id, name, ושדות age. ההערות שממוקמות מעליהן אינן זקוקות להסבר מסוים: ברור ש-@Id מציין שהשדה הוא מזהה של אובייקטים מהמחלקה הזו. ההערה @Table מעל המחלקה מציינת את שם הטבלה שבה כתובים האובייקטים. שימו לב להערה מעל שדה הגיל: אם שם השדה בכיתה זהה לשם הטבלה, אפשר להשמיט את ההערה @Column וזה יעבוד. לגבי החלק המצוין בסוגריים ("אסטרטגיה = GenerationType.IDENTITY"): ישנן מספר אסטרטגיות ליצירת מזהים. אתה יכול לגגל אותם, אבל עבור היישום שלנו, אין צורך לטרוח. העיקר שעבור האובייקטים שלנו הערך של id יווצר אוטומטית. בהתאם לכך, אין מגדיר עבור id, ואנחנו גם לא מגדירים אותו בקונסטרוקטור. עם זאת, יש כמה דרכים שבהן Userהכיתה אכן בולטת. יש לו רשימה של מכוניות! אפליקציית Hibernate הראשונה שלך - 11 ההערה @OneToMany תלויה מעל הרשימה. זה אומר שכמה מכוניות יכולות להתאים לאותו אובייקט של מחלקת המשתמש. האלמנט "mappedBy" מתייחס לשדה המשתמש של המחלקה Auto. לפיכך, מכוניות ומשתמשים קשורים זה לזה. האלמנט orphanRemoval מציין אם להחיל את פעולת ההסרה על ישויות שכבר אין להן קשר. אם נמחק משתמש מהמאגר, אזי יימחקו גם כל המכוניות המשויכות אליו. בתורו, בכיתה Auto, תראה את שדה המשתמש עם ההערה @ManyToOne (משתמש אחד יכול להתאים לרבים אוטומטיים) ואת ההערה @JoinColumn. זה מציין באיזו עמודה בטבלת האוטומטיות משתמשים כדי להתייחס לטבלת המשתמשים (כלומר המפתח הזר שעליו דיברנו קודם). לאחר יצירת מודל הנתונים, הגיע הזמן ללמד את התוכנית שלנו לבצע פעולות עם הנתונים שבבסיס הנתונים. נתחיל עם מחלקת השירות HibernateSessionFactoryUtil. יש לו רק עבודה אחת - ליצור מפעל הפעלה עבור האפליקציה שלנו שתעבוד עם מסד הנתונים (תגידו שלום לתבנית העיצוב של המפעל!). זה לא יודע איך לעשות שום דבר אחר.
package utils;

import models.Auto;
import models.User;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;

public class HibernateSessionFactoryUtil {
    private static SessionFactory sessionFactory;

    private HibernateSessionFactoryUtil() {}

    public static SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            try {
                Configuration configuration = new Configuration().configure();
                configuration.addAnnotatedClass(User.class);
                configuration.addAnnotatedClass(Auto.class);
                StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
                sessionFactory = configuration.buildSessionFactory(builder.build());

            } catch (Exception e) {
                System.out.println("Exception!" + e);
            }
        }
        return sessionFactory;
    }
}
במחלקה זו, אנו יוצרים אובייקט Configuration חדש, ומעבירים לו את המחלקות שעליו להתייחס כאל ישויות: Userו Auto. שימו לב לשיטה configuration.getProperties(). איזה עוד נכסים יש? מאיפה הם באו? מאפיינים הם הגדרות ה-hibernate המצוינות בקובץ hibernate.cfg.xml המיוחד. אפליקציית Hibernate הראשונה שלך - 12Hibernate.cfg.xml נקרא כאן: new Configuration().configure(); כפי שאתה רואה, אין בו שום דבר מיוחד: הוא מכיל את הפרמטרים לחיבור למסד הנתונים, כמו גם את הפרמטר show_sql. זה נדרש כדי שכל שאילתות sql שבוצעו על ידי Hibernate יוצגו במסוף. כך תוכלו לראות בדיוק מה Hibernate עושה בכל רגע נתון, ולבטל כל תחושת "קסם". בשלב הבא אנחנו צריכים את UserDAOהכיתה. השיטה הטובה ביותר היא לתכנת דרך הממשקים - ליצור UserDAOממשק נפרד ויישום UserDAOImpl, אבל אני אדלג על זה כדי להפחית את כמות הקוד. אל תעשה את זה בפרויקטים אמיתיים! דפוס העיצוב של DAO (אובייקט גישה לנתונים) הוא אחד הנפוצים ביותר. הרעיון הוא פשוט - צור שכבת אפליקציה האחראית רק לגישה לנתונים, לא יותר. אחזר נתונים ממסד הנתונים, עדכן נתונים, מחק נתונים - זה הכל. למד עוד על DAO. אתה תשתמש באובייקטי גישה לנתונים כל הזמן בעבודה שלך. מה הכיתה שלנו יכולה UserDaoלעשות? ובכן, כמו כל ה-DAOs, זה יכול לעבוד רק עם נתונים. מצא משתמש לפי מזהה, עדכן את הנתונים שלו, מחק אותם, קבל רשימה של כל המשתמשים ממסד הנתונים, או שמור משתמש חדש במסד הנתונים - זה מכלול הפונקציונליות שלו.
package dao;

import models.Auto;
import models.User;
import org.hibernate.Session;
import org.hibernate.Transaction;
import utils.HibernateSessionFactoryUtil;
import java.util.List;

public class UserDao {

    public User findById(int id) {
        return HibernateSessionFactoryUtil.getSessionFactory().openSession().get(User.class, id);
    }

    public void save(User user) {
        Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        Transaction tx1 = session.beginTransaction();
        session.save(user);
        tx1.commit();
        session.close();
    }

    public void update(User user) {
        Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        Transaction tx1 = session.beginTransaction();
        session.update(user);
        tx1.commit();
        session.close();
    }

    public void delete(User user) {
        Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        Transaction tx1 = session.beginTransaction();
        session.delete(user);
        tx1.commit();
        session.close();
    }

    public Auto findAutoById(int id) {
        return HibernateSessionFactoryUtil.getSessionFactory().openSession().get(Auto.class, id);
    }

    public List<User> findAll() {
        List<User> users = (List<User>) HibernateSessionFactoryUtil.getSessionFactory().openSession().createQuery("From User").list();
        return users;
    }
}
UserDaoהשיטות של זה דומות זו לזו. ברובם, אנו מקבלים אובייקט Session (סשן חיבור למסד נתונים) באמצעות Session Factory שלנו, יוצרים טרנזקציה בודדת בתוך הפעלה זו, מבצעים את מניפולציות הנתונים הדרושות, שומרים את תוצאת העסקה במסד הנתונים ולאחר מכן סוגרים את הסשן. השיטות עצמן, כפי שאתה יכול לראות, הן די פשוטות. DAO הוא "הלב" של האפליקציה שלנו. עם זאת, לא ניצור DAO ישירות ונקרא לשיטות שלו בשיטה שלנו main(). כל ההיגיון יועבר לכיתה UserService.
package services;

import dao.UserDao;
import models.Auto;
import models.User;

import java.util.List;

public class UserService {

    private UserDao usersDao = new UserDao();

    public UserService() {
    }

    public User findUser(int id) {
        return usersDao.findById(id);
    }

    public void saveUser(User user) {
        usersDao.save(user);
    }

    public void deleteUser(User user) {
        usersDao.delete(user);
    }

    public void updateUser(User user) {
        usersDao.update(user);
    }

    public List<User> findAllUsers() {
        return usersDao.findAll();
    }

    public Auto findAutoById(int id) {
        return usersDao.findAutoById(id);
    }


}
שירות הוא שכבת נתוני אפליקציה האחראית על ביצוע ההיגיון העסקי. אם התוכנית שלך צריכה לבצע איזשהו היגיון עסקי, היא עושה זאת באמצעות שירותים. שירות מכיל a UserDaoוקורא לשיטות DAO בשיטות שלו. זה אולי נראה כאילו אנחנו משכפלים כאן פונקציות (למה לא פשוט לקרוא את המתודות מאובייקט DAO?), אבל עם הרבה אובייקטים והיגיון מורכב, שכבות האפליקציה מספקות יתרונות עצומים (לעשות זאת היא תרגול טוב - זכור זאת בעתיד ולקרוא על "שכבות יישום"). לשירות שלנו יש היגיון פשוט, אבל שיטות שירות בפרויקטים בעולם האמיתי מכילות הרבה יותר משורת קוד אחת :) עכשיו יש לנו את כל מה שצריך כדי להפעיל את האפליקציה! בשיטה main(), בואו ניצור משתמש ומכונית שלו, נקשר אחד לשני ונשמור אותם במסד הנתונים.
import models.Auto;
import models.User;
import services.UserService;

import java.sql.SQLException;

public class Main {
    public static void main(String[] args) throws SQLException {

        UserService userService = new UserService();
        User user = new User ("Jenny", 26);
        userService.saveUser(user);
        Auto ferrari = new Auto("Ferrari", "red");
        ferrari.setUser(user);
        user.addAuto(ferrari);
        Auto ford = new Auto("Ford", "black");
        ford.setUser(user);
        user.addAuto(ford);
        userService.updateUser(user);
    }
}
כפי שאתה יכול לראות, לטבלת המשתמשים יש רשומה משלה, ולטבלת המכוניות יש רשומה משלה. אפליקציית Hibernate הראשונה שלך - 13אפליקציית Hibernate הראשונה שלך - 14בואו ננסה לשנות את שם המשתמש שלנו. נקה את טבלת המשתמשים והפעל את הקוד
import models.Auto;
import models.User;
import services.UserService;

import java.sql.SQLException;

public class Main {
    public static void main(String[] args) throws SQLException {

        UserService userService = new UserService();
        User user = new User ("Jenny", 26);
        userService.saveUser(user);
        Auto ferrari = new Auto("Ferrari", "red");
        user.addAuto(ferrari);
        Auto ford = new Auto("Ford", "black");
        ford.setUser(user);
        user.addAuto(ford);
        userService.updateUser(user);
        user.setName ("Benny");
        userService.updateUser(user);
    }
}
זה עובד! אפליקציית Hibernate הראשונה שלך - 15מה אם תמחק את המשתמש? נקה את טבלת המשתמשים (המכוניות ינקו את עצמם) והפעלו את הקוד
import models.Auto;
import models.User;
import services.UserService;

import java.sql.SQLException;

public class Main {
    public static void main(String[] args) throws SQLException {

        UserService userService = new UserService();
        User user = new User ("Jenny", 26);
        userService.saveUser(user);
        Auto ferrari = new Auto("Ferrari", "red");
        user.addAuto(ferrari);
        Auto ford = new Auto("Ford", "black");
        ford.setUser(user);
        user.addAuto(ford);
        userService.updateUser(user);
        user.setName ("Benny");
        userService.updateUser(user);
        userService.deleteUser(user);
    }
}
והשולחנות שלנו ריקים לחלוטין (שימו לב לקונסולה - כל הבקשות שבוצעו על ידי Hibernate יוצגו שם). אתה יכול לשחק עם האפליקציה ולנסות את כל הפונקציות שלה. לדוגמה, צור משתמש עם מכוניות, שמור אותו במסד הנתונים, הסתכל על המזהה שהוקצה למשתמש ונסה להשתמש במזהה זה בשיטה main()כדי להביא את המשתמש מהמסד ולהציג רשימה של המכוניות שלו בקונסולה . כמובן, ראינו רק חלק קטן מהפונקציונליות של Hibernate. היכולות שלו רחבות מאוד, והוא כבר מזמן כלי תעשייתי סטנדרטי לפיתוח Java. אם אתה רוצה ללמוד אותו בפירוט, אני יכול להמליץ ​​על הספר "Java Persistence API and Hibernate". סקרתי במאמר קודם. אני מקווה שמאמר זה עזר לקוראים. אם יש לך שאלות, שאל אותן בתגובות. אשמח לענות :) כמו כן, אל תשכחו לתמוך בכותב בתחרות על ידי פרסום "אהבתי". או יותר טוב — "אוהב את זה" :) בהצלחה בלימודים!
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION