(二)JPA 連接工廠、主鍵生成策略、DDL自動更新

(一)JPA的快速入門

2、JPA連接工廠

通過之前的 程式碼 實現已經清楚的發現了整個的JPA實現步驟,但是這個步驟似乎有一些繁瑣了,畢竟最終所關心的一定是EntityManager對象實例,而要想獲取到此對象的實例,那麼要經過許多的步驟,這樣如果每一次都重複的進行處理,會非常的繁瑣了,那麼就需要進行程式碼的抽象規定。

        // 創建JPA Entity工廠
        EntityManagerFactory factory =
                Persistence.createEntityManagerFactory("YootkJPA");
        // JPA操作對象
        EntityManager entityManager = factory.createEntityManager();

對等概念: DataSource -> EntityMannagerFactory

​ Connection -> EntityMannager,每一個對象的實例都表示一個Session的操作

所以此時可以考慮將部分的程式碼移交給JPA的專屬連接管理類,用這個類可以基於ThreadLocal實現EntityManager存儲,這樣每一次通過該類的方法獲取EntityManager的時候如果不關閉,則獲取到的是同一個實例

對於上敘測試類的優化。

  • 一個工具類,簡化EntityManagerFactory的創建與關閉
public class JPAEntityFactory {
    /**
     * JPA持久單元
     */
    private static final String PERSISTENCE_UNIT = "YootkJPA";
    /**
     * 等同於 數據源
     */
    private static EntityManagerFactory entityManagerFactory;
    /**
     * EntityManager 等同於 連接
     */
    private static ThreadLocal<EntityManager> entityManagerThreadLocal =
            new ThreadLocal<>();

    static {
        // 初始化創建數據源 靜態程式碼塊只會創建一次
        rebuildEntityManagerFactory();
    }
    
    /**
     * 獲取連接
     */
    public static EntityManager getEntityManager() {
        // 本機執行緒獲取連接
        EntityManager entityManager = entityManagerThreadLocal.get();
        if (entityManager == null) {
            // 從數據源獲取新的連接
            entityManager = getEntityManagerFactory().createEntityManager();
            // 存入本地執行緒
            entityManagerThreadLocal.set(entityManager);
        }
        return entityManager;
    }
    
    private static EntityManagerFactory getEntityManagerFactory() {
        if (entityManagerFactory == null) {
            // 創建數據源
            rebuildEntityManagerFactory();
        }
        return entityManagerFactory;
    }
    
    private static void rebuildEntityManagerFactory() {
        // 持久單元 創建 數據源
        entityManagerFactory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT);
    }
    
    /**
     * 關閉EntityManager
     */
    public static void close() {
        // 獲取實例
        EntityManager entityManager = entityManagerThreadLocal.get();
        if (entityManager != null) {
            // 關閉連接  entityManager類似於Connection
            entityManager.close();
            // 刪除本地執行緒中的連接
            entityManagerThreadLocal.remove();
        }
    }
}

修改測試類:

    @Test
    public void testAdd2() {
        // 獲取連接
        EntityManager entityManager = JPAEntityFactory.getEntityManager();
        // 開啟事務
        entityManager.getTransaction().begin();
        Course course = new Course();
        course.setCname("Spring編程實戰");
        // 字元串 日期對象
        course.setStart(DateUtil.stringToDate("2022-09-19"));
        course.setEnd(DateUtil.stringToDate("2022-12-30"));
        course.setCredit(2);
        course.setNum(88);
        // 執行插入
        entityManager.persist(course);
        // 提交事務
        entityManager.getTransaction().commit();
        // 關閉連接
        JPAEntityFactory.close();
    }

3、主鍵生成

在JPA開發之中,主鍵數據的生成主要是基於@Id註解定義的,而在實際的項目開發之中,數據表的設計結構是有所不同的,所以JPA為了適應這些不同的數據表的定義,也提供有不同的主鍵生成策略。

image-20220923235348927

3、DDL自動更新

在實際的開發之中你是否會出現這樣的一種比較 尷尬 的問題,在進行開發的時候有人修改數據表,而後當前的實體類結構和數據表的結構不統一,但是在JPA設計的時候,充分的考慮到了這種數據表修改的問題(表可能存在,也可能不存在,或者表的結構可能修改了),所以在這樣的環境下就需要讓程式碼可以自動的進行數據表的糾正。

在傳統的項目開發之中,常規的做法是先進行數據表的創建,而後在圍繞數據表進行業務功能的實現。在每次業務發生改變時,也是先進行表結構的修改,而後再進行程式的變更,這樣的資料庫維護是非常繁瑣的,考慮到資料庫更新以及 資料庫移植 方面的設計,在 Hibernate 之中提供了 DDL 自動創建以及表更新策略

image-20220921111235152

JPA現在主要是基於 Hibernate 實現,那麼 Hibernate 開發框架最早的一個特點就在於 可移植性,也就是說一個項目是在MySQL資料庫下開發的,那麼通過簡單的配置修改,可以讓程式碼直接在Oracle資料庫中運行。

對於當前市面上可以見到的ORM開發框架來講,只有JPA標準規定了資料庫移植性的話題,而Hibernate 實現了JPA標準,所以只有Hibernate 開發框架具有移植性的功能,而像大家所熟悉的MyBatis是沒有這樣的功能

DDL更新策略

image-20220921111527086

3.1、使用

去到JPA配置文件中,修改DDL更新策略、

3.1.1、create

每次載入時,根據實體類生成表,如果表存在於資料庫,會先刪除

            <!-- JPA更新策略 -->
            <property name="hibernate.hbm2ddl.auto" value="create"/>

image-20220921123218377

查看執行日誌信:可以看到 drop table if exists course (刪除表,然後會依據實體類,重新創建表)

3.1.2、update

如果表不存在,重建表。

存在:如:實體類某個欄位,在數據表中不存在,這個時候會添加。但是,刪除實體類的某個欄位,資料庫對應的欄位並不會刪除。

修改實體類: 添加教師

image-20220921125003973

修改配置文件-更新策略為update

image-20220921125110845

查看執行日誌:

表不存在,創建表

create table course (
cid bigint not null auto_increment,
cname varchar(255),
credit integer,
end date,
num integer,
start date,
teacher varchar(255),
primary key (cid)
) engine=InnoDB

排除屬性

假如,我們相使實體類中的某個欄位,在執行時,不創建資料庫中的對應欄位。使用@Transient即可

image-20220921130257497