在本文中,您將熟悉最受歡迎的 Java 企業框架之一,並使用 Hibernate 建立您的第一個應用程式。從未聽過休眠?也許您聽說過它,但沒有使用過?或嘗試開始,但沒有成功?在這三種情況下,歡迎剪切:) 大家好!在這篇文章中,我將討論 Hibernate 框架的主要功能,並幫助您編寫您的第一個迷你應用程式。為此我們需要:
現在讓我們繼續討論 Java 程式碼。為專案建立所有必需的套件和類別。首先,我們需要資料模型 - 類別
- Intellij Idea終極版;從官方網站
下載並啟動30天試用版。 - PostgeSQL 是最受歡迎的現代資料庫管理系統(DBMS)之一;
- Maven(已內建於 IDEA 中);
- 有點耐心。
什麼是休眠?
這是 ORM 模型最受歡迎的實現之一。物件關係模型描述了軟體物件和資料庫中的記錄之間的關係。當然,Hibernate的功能非常廣泛,但我們將專注於最簡單的功能。我們的目標:建立一個 CRUD 應用程式(建立、讀取、更新、刪除),它將能夠:- 建立使用者(User),以及透過ID在資料庫中搜尋他們,更新他們在資料庫中的數據,並從資料庫中刪除他們。
- 將車輛物件(自動)分配給使用者。從資料庫建立、編輯、尋找和刪除汽車。
- 此外,應用程式應自動從資料庫中刪除「孤兒」汽車。那些。當刪除使用者時,屬於該使用者的所有汽車也必須從資料庫中刪除。
com.вашНикнейм.javarush
,這不會以任何方式影響應用程式的操作。對於artifactId,選擇您喜歡的任何項目名稱。您也可以保持版本不變。在最後一個畫面上,只需確認您先前輸入的資料即可。所以,我們已經創建了項目,剩下的就是編寫程式碼並使其運行:)首先,如果我們想創建一個與資料庫一起使用的應用程序,我們絕對不能沒有資料庫!從這裡下載 PostgreSQL (我使用版本 9)。PostgreSQL 有一個預設使用者“postgres”,您需要在安裝過程中為其建立一個密碼。不要忘記您的密碼,我們稍後會需要它!(一般來說,在應用程式中使用預設資料庫是不好的做法,但為了減少痔瘡的數量,我們將湊合創建自己的資料庫)。如果您不熟悉命令列和 SQL 查詢,那麼有個好消息。Intellij IDEA 提供了一個非常適合使用資料庫的使用者介面。它看起來像這樣:(位於 IDEA 右側欄的“資料庫”標籤)要建立連接,請按一下“+”,選擇我們的提供者(PostgeSQL)。在欄位中填寫使用者、資料庫名稱(均為 postgres)並輸入安裝 PostgreSQL 時設定的密碼。如有必要,請下載 Postgres 驅動程序,這可以在同一頁上完成。按一下「測試連線」檢查是否已建立與資料庫的連線。如果您看到“成功”字樣,我們就繼續。現在讓我們建立我們需要的表格。其中有兩個——用戶和汽車。users 表的參數: 請注意 id 是主鍵。如果您不知道 SQL 中的主鍵是什麼,請 Google 一下,這很重要。autos 表的設定: 對於汽車,您需要配置外鍵 - 外鍵。它將連結我們的表。我建議你多讀一些關於他的文章;簡而言之,它指的是外部表,在我們的例子中是使用者。如果汽車屬於 id=1 的用戶,則 autos 表的 user_id 欄位中的值將為 1。這就是我們在應用程式中將用戶與其汽車連接起來的方式。在我們的 autos 表中,user_id 欄位將用作外鍵。它將引用用戶表的 id 欄位。 因此,我們建立了一個包含兩個表的資料庫。仍然需要了解如何從 Java 程式碼中管理它。我們將從 pom.xml 檔案開始,其中需要包含必要的程式庫(在 Maven 語言中它們稱為依賴項)。所有庫都儲存在中央 Maven 儲存庫中。您可以在專案中使用您在 pom.xml 中指定的那些內容。您的 pom.xml 應該如下所示: 正如您所看到的,沒有什麼複雜的。我們只新增了 2 個依賴項 - 用於使用 PostgreSQL 和 Hibernate。
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
-fields/properties; - 必須至少包含一個 @Id 欄位。
- 包含非空構造函數;
- 被繼承,被繼承;
- 包含其他方法並實作介面。
User
與用戶表非常相似。有字段id
, name
, age
。位於它們上方的註解不需要太多解釋:已經很清楚@Id表明該欄位是該類別的物件的識別碼。類別上方的 @Table 註解指定寫入物件的表格的名稱。注意age欄位上面的註解:如果類別中的欄位名稱和表格中的欄位名稱相同,則不必加上@Column註解,就可以了。關於括號中指示的「strategy = GenerationType.IDENTITY」:有多種ID產生策略。您可以用谷歌搜尋它,但在我們的應用程式框架內您不必費心。最主要的是我們的物件的 id 會自動生成,所以沒有 id 的 setter,我們也不在建構函式中指定它。然而,該班級在某些方面User
仍然很突出。他有一份汽車清單!@OneToMany 註釋出現在清單上方。這意味著使用者類別的一個物件可以對應多台機器。“mappedBY”設定指向該類別的使用者欄位Auto
。這樣,機器和使用者就相互連接起來了。orphanRemoval 設定從英文翻譯得很好 - “刪除孤兒”。如果我們從資料庫中刪除一個用戶,與他關聯的所有汽車也將被刪除。反過來,在類別中Auto
您將看到帶有 @ManyToOne 註釋(許多 Auto 可以對應於一個 User)和 @JoinColumn 註釋的使用者欄位。它指示透過 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("Exception!" + e);
}
}
return sessionFactory;
}
}
在此類中,我們建立一個新的配置物件 Configuration,並將其應視為實體的類別傳遞給它 -User
和Auto
。講究方法configuration.getProperties()
。還有哪些屬性?在哪裡?屬性是 hibernate 如何運作的參數,在特殊檔案 hibernate.cfg.xml 中指定。 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("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);
}
}
正如您所看到的,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("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);
}
}
作品! 如果刪除用戶怎麼辦?讓我們清除用戶表(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("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()
透過該id從資料庫中「拉取」用戶並在控制台中顯示他的機器清單。當然,我們只看到了Hibernate的一小部分功能。它的功能非常廣泛,長期以來一直是Java開發的行業標準之一。如果你想詳細研究它,我可以推薦《Java Persistence API and Hibernate》一書,我在之前的一篇文章中評論過這本書。我希望這篇文章對讀者有用。如果您有任何疑問,請在評論中提問,我將很樂意回答:) 另外,不要忘記透過「喜歡」他來支持作者的比賽。或更好 - “我非常喜歡它”:) 祝你學習順利!
GO TO FULL VERSION