在本文中,您將熟悉最流行的 Java 企業框架之一,並創建您的第一個 Hibernate 應用程序。從未聽說過 Hibernate?或者,也許您聽說過它,但還沒有使用過它?或者也許您嘗試使用它,但失敗了?在所有三種情況下 - 歡迎來到下面的剪輯 :)
大家好!在本文中,我將討論 Hibernate 框架的主要特性並幫助您編寫您的第一個迷你應用程序。為此,我們需要:
如您所見,沒有什麼複雜的。6 個類 + 1 個帶有配置的文件。首先,在 IntelliJ IDEA 中新建一個 Maven 項目。文件 -> 新項目。從建議的項目類型中選擇 Maven,然後轉到下一步。
Apache Maven 是一個框架,用於根據 POM 文件中的結構描述自動構建項目。你的項目的整個結構將在 pom.xml 中描述,這是一個 IDEA 本身將在你的項目的根目錄中創建的文件。在項目設置中,您需要指定以下 Maven 設置:groupId 和 artifactId。在項目中,groupId 通常是對公司或事業部的描述。公司或網站的域名可以放這裡。反過來,artifactId 是項目的名稱。對於 groupdId,您可以輸入
在最後一個屏幕上,只需確認之前輸入的數據。
所以,我們創建了這個項目。現在剩下要做的就是編寫一些代碼並使其運行 :) 首先是第一件事:如果我們想創建一個使用數據庫的應用程序,我們絕對不能沒有數據庫!從這裡下載 PostgreSQL (我使用的是版本 9)。PostgreSQL 有一個默認用戶“postgres”——您需要在安裝時為它想一個密碼。不要忘記密碼。我們稍後會需要它!(一般來說,在應用程序中使用默認數據庫是不好的做法,但我們會這樣做是為了通過創建您自己的數據庫來減少導致潰瘍的數量)。如果您不熟悉命令行和 SQL 查詢,那麼有個好消息。IntelliJ IDEA 提供了一個完全適合使用數據庫的用戶界面。
(位於 IDEA 的右窗格中,數據庫選項卡)。要創建連接,請單擊“+”並選擇我們的數據源 (PostgeSQL)。填寫用戶和數據庫字段(兩者均為“postgres”)並輸入在安裝 PostgreSQL 期間設置的密碼。如有必要,請下載 Postgres 驅動程序。您可以在同一頁面上執行此操作。單擊“測試連接”以驗證數據庫連接是否已建立。如果您看到“成功”,則繼續。現在我們將創建我們需要的表。一共有兩個:用戶和汽車。users 表的參數:
請注意,id 是主鍵。如果您不知道 SQL 中的主鍵是什麼,請谷歌一下。這個很重要。汽車錶的設置:
對於autos表,需要配置一個外鍵。它將用於鏈接我們的表格。我建議您閱讀更多相關信息。簡而言之,它引用了一個外部表,在我們的例子中是用戶。如果汽車屬於 id = 1 的用戶,則汽車的 user_id 字段將等於 1。這就是我們在應用程序中將用戶與其汽車相關聯的方式。在我們的 autos 表中,user_id 字段將充當外鍵。它將引用用戶表的 id 字段。
因此,我們創建了一個包含兩個表的數據庫。剩下的就是了解如何從 Java 代碼管理它。我們將從 pom.xml 文件開始,我們需要在其中包含必要的庫(在 Maven 中,它們稱為依賴項)。所有庫都存儲在中央 Maven 存儲庫中。您在 pom.xml 中指定的庫可供您在項目中使用。您的 pom.xml 應該如下所示:
如您所見,沒什麼複雜的。我們只添加了 2 個依賴項——用於使用 PostgreSQL 和 Hibernate。現在讓我們繼續處理 Java 代碼。在項目中創建所有必需的包和類。首先,我們需要一個數據模型:
@OneToMany 註釋掛在列表上方。就是說幾輛車可以對應同一個User類的對象。“mappedBy”元素指的是類的用戶字段
Hibernate.cfg.xml 看這裡:![你的第一個 Hibernate 應用程序 - 13]()
讓我們嘗試重命名我們的用戶。清除用戶表並執行代碼
如果刪除用戶怎麼辦?清除用戶表(autos 會自行清除)並執行代碼

- IntelliJ IDEA 旗艦版官網
下載,激活30天試用版。 - PostgreSQL - 最流行的現代數據庫管理系統 (DBMS) 之一
- Maven(已經連接到 IDEA)
- 有點耐心。
什麼是休眠?
它是最流行的對象關係映射 (ORM) 實現之一。對象關係映射定義了軟件對象和數據庫記錄之間的關係。當然,Hibernate 具有非常廣泛的功能,但我們將專注於最簡單的功能。我們的目標是創建一個 CRUD(創建、讀取、更新、刪除)應用程序,它將能夠:- 創建用戶(User),通過ID在數據庫中查找,更新他們在數據庫中的數據,從數據庫中刪除。
- 將汽車對象(汽車)分配給用戶。從數據庫中創建、更新、查找和刪除汽車。
- 此外,應用程序應自動從數據庫中刪除“無主”汽車。換句話說,當一個用戶被刪除時,屬於該用戶的所有汽車也必須從數據庫中刪除。


com.yourNickname.codegym
. 這不會對應用程序產生任何影響。對於 artifactId,選擇您喜歡的任何項目名稱。版本可以保持不變。 






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 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 註解,它會起作用。至於大括號中指示的部分(“strategy = GenerationType.IDENTITY”):有幾種生成ID的策略。您可以用 Google 搜索它們,但對於我們的應用程序,無需費心。最主要的是,對於我們的對象,id 的值將自動生成。因此,沒有 id 的 setter,我們也不在構造函數中設置它。然而,User
類確實脫穎而出。它有一個汽車清單! 
Auto
。因此,汽車和用戶是相關的。orphanRemoval 元素指示是否將刪除操作應用於不再有關係的實體。如果我們從數據庫中刪除一個用戶,那麼與其關聯的所有汽車也將被刪除。反過來,在Auto
類,你會看到帶有@ManyToOne註解(一個User可以對應多個Auto)和@JoinColumn註解的user字段。它指示 autos 表中的哪一列用於引用 users 表(即我們之前談到的外鍵)。創建數據模型後,就該教我們的程序對數據庫中的數據執行操作了。讓我們從 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("Исключение!" + e);
}
}
return sessionFactory;
}
}
在這個類中,我們創建了一個新的 Configuration 對象,並將它應該視為實體的類傳遞給它:User
和Auto
。注意方法configuration.getProperties()
。還有哪些其他屬性?他們來自哪裡?屬性是特殊 hibernate.cfg.xml 文件中指示的休眠設置。 
new Configuration().configure();
如您所見,它沒有什麼特別之處:它包含連接數據庫的參數,以及 show_sql 參數。這是必需的,以便 Hibernate 執行的所有 sql 查詢都顯示在控制台上。這樣您就可以準確地看到 Hibernate 在任何給定時刻正在做什麼,從而消除任何“魔法”的感覺。接下來我們需要UserDAO
班級。最佳實踐是通過接口進行編程——創建一個單獨的UserDAO
接口和UserDAOImpl
實現,但為了減少代碼量,我將跳過這一點。不要在實際項目中這樣做!DAO(數據訪問對象)設計模式是最常見的一種。這個想法很簡單——創建一個只負責訪問數據的應用層,僅此而已。從數據庫中獲取數據、更新數據、刪除數據——僅此而已。學習更多關於 DAO 的知識。您將在工作中經常使用數據訪問對象。我們UserDao
班能做什麼?好吧,就像所有的 DAO 一樣,它只能處理數據。通過 ID 查找用戶、更新其數據、刪除它、從數據庫中獲取所有用戶的列表,或者在數據庫中保存一個新用戶——這就是它的全部功能。
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
的方法彼此相似。在大多數情況下,我們使用會話工廠獲取會話對象(數據庫連接會話),在該會話中創建單個事務,執行必要的數據操作,將事務結果保存在數據庫中,然後關閉會話。如您所見,這些方法本身非常簡單。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 方法。看起來我們在這裡複製了函數(為什麼不直接從 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);
}
}
如您所見,users 表有自己的記錄,autos 表也有自己的記錄。 

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);
}
}
有用! 
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 執行的所有請求都將顯示在那裡)。您可以試用該應用程序並嘗試其所有功能。比如創建一個有cars的用戶,保存在數據庫中,查看分配給用戶的id,嘗試在main()
方法從數據庫中獲取用戶並在控制台上顯示其汽車列表。當然,我們只看到了 Hibernate 功能的一小部分。它的功能非常廣泛,長期以來一直是 Java 開發的標準行業工具。如果想深入研究,可以推薦《Java Persistence API and Hibernate》這本書。我在之前的文章中回顧過。我希望這篇文章對讀者有所幫助。如果您有任何疑問,請在評論中提問。我很樂意回答 :) 另外,不要忘記通過張貼“贊”來支持作者參加比賽。或者更好——“喜歡它”:)祝你學業順利!
GO TO FULL VERSION