JavaRush /Java Blog /Random-TW /Maven、Spring、MySQL、Hibernate 和第一個 CRUD 應用程式簡介(第 3 部分)
Макс
等級 41

Maven、Spring、MySQL、Hibernate 和第一個 CRUD 應用程式簡介(第 3 部分)

在 Random-TW 群組發布
午安. 在這篇文章中,我想分享我在創建一個簡單的 CRUD 應用程式的過程中第一次接觸到 Maven、Spring、Hibernate、MySQL 和 Tomcat 等東西。這是 4 的第三部分。本文主要針對那些已經完成 30-40 級,但尚未超越純 Java 並剛開始(或即將開始)進入開放世界的人所有這些技術、框架和其他陌生的詞語。 Maven、Spring、MySQL、Hibernate 和第一個 CRUD 應用程式簡介(第 3 部分)- 1這是文章《Maven、Spring、MySQL、Hibernate 簡介和第一個 CRUD 應用程式》的第三部分。前面的部分可以透過以下連結查看:

內容:

建立並連接資料庫

好吧,是時候開始處理資料庫了。在連接Hibernate並思考它應該如何在那裡工作之前,首先讓我們看看資料庫本身,即 讓我們創建它、連結它、製作它並填寫標誌。我們將使用DBMS(資料庫管理系統)MySQL(當然,您必須先下載並安裝)。 SQL(結構化查詢語言)是一種聲明性程式語言,用於建立、修改和操作關聯式資料庫中的資料。在此類資料庫中,資料以表格的形式儲存。應用程式如何與資料庫通訊(將SQL查詢傳輸到資料庫並傳回結果)。為此,Java 提供了JDBC(Java 資料庫連接)這樣的東西,簡單地說,它是一組用於處理資料庫的介面和類別。要與資料庫交互,您需要建立一個連接;為此,包java.sql有一個類別Connection。建立連線的方法有多種,例如可以使用getConnection類別方法DriverManager。但是與資料庫的互動並不是直接進行的,因為資料庫有很多,而且各不相同。因此,它們每個都有自己的 JDBC 驅動程式。使用該驅動程序,可以建立與資料庫的連接。所以,首先,為了以後不被這個分心,我們先安裝MySQL驅動程式。讓我們新增pom.xml以下相依性:
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.11</version>
</dependency>
現在讓我們建立資料庫。 檢視 -> 工具視窗 -> 資料庫- 將開啟資料庫面板。 新建(綠色+)->資料來源->MySQL - 將開啟一個窗口,您需要在其中指定使用者名稱和密碼,我們在安裝MySQL時設定它們(例如,我使用root和root)。連接埠(MySQL 預設為 3306)、名稱等。保持原樣。您可以使用「測試連線」按鈕測試連線。 Maven、Spring、MySQL、Hibernate 和第一個 CRUD 應用程式簡介(第 3 部分)- 2按一下「確定」,現在我們已連接到 MySQL 伺服器。接下來,讓我們建立一個資料庫。為此,您可以在打開的控制台中編寫一個腳本:
CREATE DATABASE test
按一下「執行」,資料庫已準備就緒,現在您可以連接它。為此,請返回「資料來源屬性」並在「資料庫」欄位中輸​​入資料庫名稱(test),然後再次輸入使用者名稱和密碼,然後單一擊“確定”。現在我們需要製作一張桌子。您可以使用圖形工具,但第一次,可能值得手動編寫腳本來看看它是什麼樣子:
USE test;

CREATE TABLE films
(
  id int(10) PRIMARY KEY AUTO_INCREMENT,
  title VARCHAR(100) NOT NULL,
  year int(4),
  genre VARCHAR(20),
  watched BIT DEFAULT false  NOT NULL
)
COLLATE='utf8_general_ci';
CREATE UNIQUE INDEX films_title_uindex ON films (title);

INSERT INTO `films` (`title`,`year`,`genre`, watched)
VALUES
  ("Inception", 2010, "sci-fi", 1),
  ("The Lord of the Rings: The Fellowship of the Ring", 2001, "fantasy", 1),
  ("Tag", 2018, "comedy", 0),
  ("Gunfight at the O.K. Corral", 1957, "western", 0),
  ("Die Hard", 1988, "action", 1);
建立一個表,其名稱films為 columns等idtitle對於每一列,都會指示類型(括號中是最大輸出大小)。
  • PRIMARY KEY- 這是主鍵,用於唯一標識表中的記錄(意味著唯一性)
  • AUTO_INCREMENT— 該值將自動產生(當然它將是非零的,因此您不必指定它)
  • NOT NULL- 這裡一切也很明顯,它不能為空
  • DEFAULT— 設定預設值
  • COLLATE- 編碼
  • CREATE UNIQUE INDEX— 讓該領域獨一無二
  • INSERT INTO— 新增一筆記錄到表中
結果是這樣的標誌: 也許值得嘗試連接到它,只是暫時,與我們的 Web 應用程式分開。如果出現問題怎麼辦,我們會立即解決。否則,稍後我們將連接Hibernate,做一些事情,配置,修補,如果我們在某個地方搞砸了,那麼至少我們會知道問題不在這裡。好吧,為了檢查連接,我們main暫時建立一個方法。原則上,你可以把它放在任何地方,甚至在控制器類別中,甚至在模型或配置中,都沒關係,你只需要使用它來確保連接一切正常,然後就可以刪除它。但為了更加小心,讓我們為它創建一個單獨的類別Main
package testgroup.filmography;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class Main {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/test";
        String username = "root";
        String password = "root";
        System.out.println("Connecting...");

        try (Connection connection = DriverManager.getConnection(url, username, password)) {
            System.out.println("Connection successful!");
        } catch (SQLException e) {
            System.out.println("Connection failed!");
            e.printStackTrace();
        }
    }
}
這裡一切都很簡單,我們設定資料庫的連接參數並嘗試建立連接。讓我們啟動這個main並看一下。因此,我遇到了異常、一些時區問題以及一些有關 SSL 的其他警告。瀏覽互聯網後,您可以發現這是一個相當普遍的問題,並且當使用不同版本的驅動程式(mysql-connector-java)時,它可以發誓不同。例如,我透過實驗發現,使用5.1.47版本時,沒有因為時區的原因出現異常,連接正常創建,但仍然彈出SSL警告。對於其他一些版本,似乎存在有關 SSL 的例外,而不僅僅是警告。好吧,這不是重點。你可以嘗試單獨處理這個問題,但我們現在不討論它。解決這個問題的方法非常簡單,您需要在url中指定其他參數,即serverTimezone問題是否與時區有關,以及useSSL是否與 SSL 有關:
String url = "jdbc:mysql://localhost:3306/test?serverTimezone=Europe/Minsk&useSSL=false";
現在我們已經設定了時區並停用了 SSL。我們再次啟動它main,瞧 - 連接成功!好吧,太好了,我們找到瞭如何建立連接。該類別Main已基本完成其任務,可以將其刪除。

ORM 和 JPA

好的方面,為了更好的理解,最好是按順序開始熟悉資料庫,從一開始,沒有任何hibernate之類的東西。因此,最好找到一些指南並先嘗試使用 JDBC 類別、手動編寫 SQL 查詢等。好吧,讓我們立即轉向ORM模型。這是什麼意思?當然,再次建議單獨閱讀這一點,但我將嘗試簡要描述它。ORM(Object-Relational Mapping 或物件關係映射)是一種將物件對應到關聯式資料庫結構的技術,即 將我們的 Java 物件表示為表格行。感謝 ORM,您不必擔心編寫 SQL 腳本,而可以專注於處理物件。如何使用它。Java還有一個很棒的東西,JPA(Java Persistence API),它實作了ORM概念。JPA 就是這樣一個規格;它描述了物件的需求,它定義了使用資料庫的各種介面和註解。JPA本質上是一種描述,一種標準。因此,具體的實現有很多,其中之一(也是最受歡迎的之一)就是Hibernate,它是這個框架的精髓。Hibernate 是 JPA 規範的實現,旨在解決物件關係映射 (ORM) 問題。我們需要將這整件事連接到我們的專案中。另外,為了讓我們的 Spring 不袖手旁觀,也參與到資料庫的所有運動中,我們需要連接更多的模組,因為 我們從spring-webmvc依賴項中獲得的所有內容都不足以滿足此目的。我們還需要spring-jdbc來處理資料庫,spring-tx來支援事務,以及spring-orm來處理 Hibernate。讓我們新增依賴項pom.xml
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>5.1.1.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.3.7.Final</version>
</dependency>
這兩個依賴就夠了。javax.persistence-api將與hibernate-core一起到達,spring-jdbcspring-txspring-orm一起到達。

實體

所以我們希望類別物件能夠Film儲存在資料庫中。為此,類別必須滿足許多條件。在 JPA 中有一個實體( Entity)。實體類別是一個普通的POJO類,具有私有欄位以及它們的 getter 和 setter。它必須有一個不帶參數的非私有建構函數(或預設建構函數),並且必須有一個主鍵,即 唯一標識資料庫中此類的每個記錄的東西。您也可以單獨閱讀此類課程的所有要求。讓我們Film使用 JPA 註解使我們的類別成為一個實體:
package testgroup.filmography.model;

import javax.persistence.*;

@Entity
@Table(name = "films")
public class Film {

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

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

    @Column(name = "year")
    private int year;

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

    @Column(name = "watched")
    private boolean watched;

    // + getters and setters
}
  • @Entity- 表示該類別是一個實體。
  • @Table- 指向一個特定的表格來顯示該實體。
  • @Id— 表示該欄位是主鍵,即 該屬性將用於標識每個唯一的條目。
  • @Column— 將欄位連接到表格列。如果欄位名稱和表格列名相同,則可以省略。
  • @GeneratedValue— 此屬性將自動產生;您可以在括號中指定如何產生。我們現在無法理解不同策略到底是如何運作的。知道在這種情況下每個新值都會比前一個值增加 1 就足夠了。
對於每個屬性,您還可以指定許多其他內容,例如,什麼應該是非零或唯一的、指定預設值、最大大小等。如果您需要基於此類生成表,這將很有用;Hibernate 有此選項。但我們已經自己創建了表並配置了所有屬性,所以我們可以不用它。 一個小筆記。Hibernate 文件建議不要在欄位上使用註釋,而是在 getter 上使用註釋。然而,這些方法之間的差異非常微妙,在我們的簡單應用程式中這不會產生任何影響。另外,大多數人無論如何都會在字段上方添加註釋。因此,就這樣吧,看起來更整潔。

休眠屬性

好吧,讓我們開始設定 Hibernate。首先,讓我們將一些資訊(例如使用者名稱和密碼、網址和其他內容)放入一個單獨的檔案中。當然,您可以直接在類別中將它們指定為常規行,就像我們檢查連接時所做的那樣(String username = "root";然後將其傳遞給創建連接的方法)。但將此類靜態資料儲存在某個文件中仍然更正確property。例如,如果您需要更改資料庫,那麼您不必遍歷所有類別並查找使用它的位置;更改此文件中的值一次就足夠了。讓我們在資源目錄中建立一個db.properties檔案:
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?serverTimezone=Europe/Minsk&useSSL=false
jdbc.username=root
jdbc.password=root

hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
hibernate.show_sql=true
好吧,從上面一切都清楚了,連接資料庫的參數,即 驅動程式類別名稱、url、使用者名稱和密碼。 hibernate.dialect- 需要此屬性來指示 Hibernate 使用的是 SQL 語言的特定版本。事實上,在每個 DBMS 中,為了擴展功能、添加一些功能或最佳化某些內容,它們通常會對語言進行稍微現代化。結果是,每個 DBMS 都有自己的 SQL 方言。就像英語一樣,看起來語言是一樣的,但在澳洲、美國或英國會略有不同,有些單字可能有不同的意思。為了避免任何理解問題,您需要直接告訴 Hibernate 它到底要處理什麼。 hibernate.show_sql— 由於此屬性,對資料庫的查詢將顯示在控制台中。這不是必要的,但是有了這個東西你至少可以看看正在發生什麼,否則看起來 Hibernate 正在做某種魔法。好吧,當然,它不會完全清晰地顯示;最好使用某種記錄器來實現這一點,但那是另一次的事情了,現在就可以了。

休眠配置

讓我們繼續設定配置。讓我們在包中創建config一個類別HibernateConfig
package testgroup.filmography.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.Properties;

@Configuration
@ComponentScan(basePackages = " testgroup.filmography")
@EnableTransactionManagement
@PropertySource(value = "classpath:db.properties")
public class HibernateConfig {
    private Environment environment;

    @Autowired
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
        return properties;
    }

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
        dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
        dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
        dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
        return dataSource;
    }

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan("testgroup.filmography.model");
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
    }

    @Bean
    public HibernateTransactionManager transactionManager() {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(sessionFactory().getObject());
        return transactionManager;
    }
}
這裡有很多新東西,所以最好在不同的來源中額外查找每個項目的資訊。我們在這裡簡單回顧一下。
  • 我們上課的時候@Configuration就已經想好了。@ComponentScanWebConfig
  • @EnableTransactionManagement— 允許您使用它TransactionManager來管理交易。Hibernate 使用事務與資料庫一起工作;它們需要作為一個整體來執行一組特定的操作,即 如果該方法中的任何一項操作出現問題,那麼所有其他操作都不會被執行,這樣就不會像經典的轉帳範例那樣,當從一個帳戶提款的操作完成時,而是發生這種情況。寫信給另一個人的操作不起作用,結果錢消失了。
  • @PropertySource— 連結我們最近建立的屬性檔案。
  • Environment- 為了從property檔案中取得屬性。
  • hibernateProperties- 需要此方法將 Hibernate 屬性表示為 Properties 對象
  • DataSource— 用於建立與資料庫的連線。這是DriverManager的替代方案,我們之前在創建main. 文件說DataSource最好使用。當然,這就是我們要做的,不要忘記在網路上閱讀差異和優勢是什麼。一個特別的好處是能夠建立資料庫連接池 (DBCP)。
  • sessionFactory— 建立會話,借助該會話執行實體物件的操作。這裡我們設定資料來源、Hibernate 屬性以及我們需要在哪個套件中尋找實體類別。
  • transactionManager— 配置事務管理器。
關於 的一個小註DataSource。文件說不DriverManagerDataSource建議使用標準實現,即 ,因為 它只是普通連接池的替代品,通常只適用於測試等。對於普通應用程序,最好使用某種 DBCP 庫。好吧,對於我們的應用程式來說,當然,我們擁有的已經足夠了,但為了完成圖片,也許我們仍然會按照建議使用另一個實現。讓我們新增pom.xml以下相依性:
<dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-dbcp</artifactId>
            <version>9.0.10</version>
</dependency>
dataSource類別方法中HibernateConfig,我們將其替換DriverManagerDataSourceBasicDataSource套件中的方法org.apache.tomcat.dbcp.dbcp2
BasicDataSource dataSource = new BasicDataSource();
好吧,一切似乎都已完成,配置已準備就緒,剩下的就是將其添加到我們的AppInitializer中:
protected Class<?>[] getRootConfigClasses() {
        return new Class[]{HibernateConfig.class};
    }

資料存取層

終於到了開始使用我們的 DAO 的時候了。我們去上課FilmDAOImpl,首先我們從那裡刪除試用列表,我們不再需要它。讓我們添加一個會話工廠並完成它。
private SessionFactory sessionFactory;

    @Autowired
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
首先,我們將建立一個方法來顯示包含電影清單的頁面,在其中我們將接收一個會話並向資料庫發出請求(提取所有記錄並形成一個清單):
public List<Film> allFilms() {
        Session session = sessionFactory.getCurrentSession();
        return session.createQuery("from Film").list();
    }
這裡有2點。首先,顯示警告。這是因為我們想要接收一個參數化的List<Film>,但該方法傳回只是List因為在編譯時不知道請求將傳回什麼類型。所以這個想法警告我們,我們正在進行不安全的轉換,這可能會導致麻煩。有幾種更正確的方法可以做到這一點,這樣就不會出現這樣的問題。您可以在網路上搜尋資訊。但現在我們不用擔心這個。事實上,我們確切地知道將返回什麼類型,因此這裡不會出現問題,您可以簡單地忽略該警告。但是,為了不礙眼,您可以在方法上方添加註釋@SupressWarning("unchecked")。透過這樣做,我們有點告訴編譯器,謝謝你,夥計,你的關心,但我知道我在做什麼,一切都在掌控之中,所以你可以放鬆,不用擔心這個方法。其次,這個想法用紅色底線“ from Film”表示。這只是一個 HQL(Hibernate Query Language)查詢,而這個想法不知道是否一切都正確或有錯誤。您可以前往創意設定並手動調整所有內容(如果您有興趣,請在網路上尋找)。或者,您可以簡單地新增對 Hibernate 框架的支持,為此,右鍵單擊該項目,選擇「新增框架支援」 ,選取Hibernate複選框,然後按一下「確定」。此後,很可能在實體類別(Film)中很多東西也會用紅色下劃線表示,例如註解中@Table(name = "films")會發出警告Cannot parse table 'films'。再說一遍,這裡沒有任何問題,這不是設計錯誤,一切都會編譯並運作。這個想法之所以被強調,是因為它對我們的基地一無所知。為了解決這個問題,讓我們將這個想法與資料庫整合起來。查看->工具視窗-> Persistense(將開啟一個選項卡) ->滑鼠右鍵,選擇分配資料來源->在資料來源中,指定與資料庫的連接,然後按一下確定Maven、Spring、MySQL、Hibernate 和第一個 CRUD 應用程式簡介(第 3 部分) - 3當這一切都解決之後,還剩下一些東西。讓我們走向更高的層次,走向服務。在類別中,FilmServiceImpl我們allFilms用註解標記 spring 方法@Transactional,這將表明該方法應該在事務中執行(沒有這個,Hibernate 將拒絕工作):
@Transactional
public List<Film> allFilms() {
    return filmDAO.allFilms();
}
所以,這裡一切都準備好了,你不需要碰控制器裡的任何東西。好吧,看來關鍵時刻已經到來,點擊“運行”,看看會發生什麼。 Maven、Spring、MySQL、Hibernate 和第一個 CRUD 應用程式簡介(第 3 部分)- 4這就是我們的標誌,這次它不是從我們自己在課堂上列出的清單中獲得的,而是從資料庫中獲得的。太好了,一切似乎都正常。現在我們使用會話方法以相同的方式執行所有其他 CRUD 操作。最終的類別如下所示:
package testgroup.filmography.dao;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import testgroup.filmography.model.Film;

import java.util.List;

@Repository
public class FilmDAOImpl implements FilmDAO {
    private SessionFactory sessionFactory;

    @Autowired
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<Film> allFilms() {
        Session session = sessionFactory.getCurrentSession();
        return session.createQuery("from Film").list();
    }

    @Override
    public void add(Film film) {
        Session session = sessionFactory.getCurrentSession();
        session.persist(film);
    }

    @Override
    public void delete(Film film) {
        Session session = sessionFactory.getCurrentSession();
        session.delete(film);
    }

    @Override
    public void edit(Film film) {
        Session session = sessionFactory.getCurrentSession();
        session.update(film);
    }

    @Override
    public Film getById(int id) {
        Session session = sessionFactory.getCurrentSession();
        return session.get(Film.class, id);
    }
}
現在剩下的就是記住轉到服務並向方法添加註釋@Transactional。就這樣,準備好了。您現在可以運行並檢查。點擊連結和按鈕,嘗試新增/刪除/編輯條目。如果一切都正確完成,它應該可以工作。現在,這是一個使用 Hibernate、Spring、MySQL 的成熟 CRUD 應用程式。待續... Maven、Spring、MySQL、Hibernate 簡介和第一個 CRUD 應用程式(第 1 部分) Maven、Spring、MySQL、Hibernate 簡介和第一個 CRUD 應用程式(第 2 部分) Maven、Spring、MySQL 、Hibernate 簡介和第一個 CRUD 應用程式(第 3 部分) Maven、Spring、MySQL、Hibernate 簡介和第一個 CRUD 應用程式(第 4 部分)
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION