JavaRush /בלוג Java /Random-HE /אפליקציית Hibernate הראשונה שלך

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

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

מה זה Hibernate?

זהו אחד המימושים הפופולריים ביותר של מודל ORM. מודל יחסי האובייקט מתאר את היחסים בין אובייקטי תוכנה לרשומות במסד הנתונים. כמובן שהפונקציונליות של Hibernate רחבה מאוד, אך נתמקד בפונקציות הפשוטות ביותר. המטרה שלנו: ליצור אפליקציית CRUD (יצירה, קריאה, עדכון, מחיקה) שתהיה מסוגלת:
  1. צור משתמשים (User), כמו גם חפש אותם במסד הנתונים לפי מזהה, עדכן את הנתונים שלהם במסד הנתונים וגם מחק אותם מהמסד.
  2. הקצה אובייקטי רכב (אוטומטי) למשתמשים. צור, ערוך, מצא ומחק מכוניות ממסד הנתונים.
  3. בנוסף, האפליקציה אמורה להסיר אוטומטית מכוניות "יתומות" ממסד הנתונים. הָהֵן. כאשר משתמש נמחק, יש למחוק מהמאגר גם את כל המכוניות השייכות לו.
מבנה הפרויקט שלנו יהיה כדלקמן: אפליקציית Hibernate הראשונה שלך - 2כפי שאתה יכול לראות, שום דבר לא מסובך. 6 מחלקות + קובץ אחד עם הגדרות. ראשית, בואו ניצור פרויקט מייבן חדש ב-Intellij Idea. קובץ -> פרויקט חדש. מבין סוגי הפרויקטים המוצעים, בחר Maven ועבור הלאה. אפליקציית Hibernate הראשונה שלך - 3Apache Maven היא מסגרת לאוטומציה של הרכבה של פרויקטים על סמך תיאור המבנה שלהם בקבצים בשפת POM. כל המבנה של הפרויקט שלך יתואר בקובץ pom.xml, ש-IDEA בעצמה תיצור בשורש הפרויקט שלך. בהגדרות הפרויקט תצטרכו לציין את הפרמטרים של Maven - groupId ו-artifactId. בדרך כלל בפרויקטים groupId הוא שם הארגון או החטיבה, ושם כתוב שם הדומיין של הארגון או אתר הפרויקט. בתורו, artifactId הוא שם הפרויקט. עבור groupdId אתה יכול לציין com.вашНикнейм.javarush, זה לא ישפיע על פעולת היישום בשום אופן. עבור 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. צור את כל החבילות והשיעורים הדרושים לפרויקט. מלכתחילה, נצטרך מודלים של נתונים - מחלקות Userו Auto.
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 not specify Column name if it matches the name of the column 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 not specify Column name if it matches the name of the column 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, ואנחנו לא מציינים את זה גם בקונסטרוקטור. Userעם זאת, הכיתה עדיין בולטת במובנים מסוימים . יש לו רשימה של מכוניות! ההערה @OneToMany מופיעה מעל הרשימה. זה אומר שאובייקט אחד של מחלקת המשתמש יכול להתאים למספר מכונות. ההגדרה "mappedBY" מצביעה על שדה המשתמש של המחלקה Auto. בדרך זו, מכונות ומשתמשים מחוברים זה לזה. ההגדרה 'הסרה יתומים' מתורגמת די טוב מאנגלית - "הסר יתומים". אם נמחק משתמש מהמאגר, יימחקו גם כל המכוניות המשויכות אליו. בתורו, בכיתה 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.cfg.xml. אפליקציית Hibernate הראשונה שלך - 11Hibernate.cfg.xml נקרא כאן: new Configuration().configure(); כפי שאתה יכול לראות, אין בו שום דבר מיוחד - פרמטרים לחיבור לבסיס הנתונים, ופרמטר מיוחד show_sql. זה נחוץ כדי שכל שאילתות SQL שמצב שינה יבוצעו מול מסד הנתונים שלנו ייצאו לקונסולה. כך תוכלו לראות בדיוק מה Hibernate עושה בכל רגע בזמן ולהיפטר מאפקט ה"קסם". בשלב הבא אנחנו צריכים את הכיתה UserDAO. (בצורה טובה, אתה צריך לתכנת דרך ממשקים - ליצור ממשק UserDAOולהטמיע אותו בנפרד UserDAOImpl, אבל כדי להפחית את כמות הקוד אני אשמיט את זה. אל תעשה את זה בפרויקטים אמיתיים!). DAO (אובייקט גישה לנתונים) הוא אחד מדפוסי העיצוב הנפוצים ביותר, "גישה לנתונים". המשמעות שלו פשוטה - ליצור שכבה באפליקציה שאחראית רק על הגישה לנתונים, ותו לא. קבל נתונים ממסד הנתונים, עדכן את הנתונים, מחק את הנתונים - וזהו. קרא עוד על DAOs; אתה תשתמש בהם כל הזמן בעבודה שלך. מה הכיתה שלנו יכולה לעשות 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);
    }


}
שירות הוא שכבת נתונים באפליקציה שאחראית על ביצוע לוגיקה עסקית. אם התוכנית שלך צריכה לבצע הגיון עסקי כלשהו, ​​היא עושה זאת באמצעות שירותים. השירות מכיל בתוכו את עצמו UserDaoוקורא לשיטות 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("Masha",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("Masha",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("Sasha");
        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("Masha",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("Sasha");
        userService.updateUser(user);
        userService.deleteUser(user);
    }
}
והשולחנות שלנו ריקים לחלוטין (שימו לב לקונסולה, כל השאילתות שה-Hibernate ביצע יוצגו שם). אתה יכול לשחק עם האפליקציה ולנסות את כל התכונות שלה. לדוגמה, צור משתמש עם מכונות, שמור אותו במסד הנתונים, ראה איזה ID מוקצה לו, ונסה להשתמש בשיטה main()"למשוך" את המשתמש מהמסד על ידי המזהה הזה ולהציג רשימה של המכונות שלו בקונסולה . כמובן, ראינו רק חלק קטן מהפונקציונליות של Hibernate. היכולות שלו רחבות מאוד, והוא כבר מזמן אחד מהסטנדרטים בתעשייה לפיתוח Java. אם אתה רוצה ללמוד אותו בפירוט, אני יכול להמליץ ​​על הספר "Java Persistence API and Hibernate", אותו סקרתי באחד מהמאמרים הקודמים שלי. אני מקווה שמאמר זה היה שימושי לקוראים. אם יש לכם שאלות, שאלו אותן בתגובות, אשמח לענות :) כמו כן, אל תשכחו לתמוך בכותב בתחרות על ידי "לייק" לו. או יותר טוב - "אני אוהב את זה מאוד" :) בהצלחה בלימודים!
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION