(三)JPA – EntityManager的使用

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

建議在需要使用時,看看之前的文章,先把環境搭起來。

4、EntityManager

EntityManager 是完成持久化操作的核心對象。

EntityManager 對象在一組實體類與底層數據源之間進行 O/R 映射的管理。它可以用來管理和更新 Entity Bean, 根椐主鍵查找 Entity Bean, 還可以通過JPQL語句查詢實體。

上面測試程式碼中,已經使用過EntityManager完成持久化操作。

實體類的狀態:

新建狀態: 新創建的對象,尚未擁有持久性主鍵;

持久化狀態:已經擁有持久性主鍵並和持久化建立了上下文環境;

遊離狀態:擁有持久化主鍵,但是沒有與持久化建立上下文環境;

刪除狀態: 擁有持久化主鍵,已經和持久化建立上下文環境,但是從資料庫中刪除。

4.1 persist 增

persist (Object entity):用於將新創建的 Entity 納入到 EntityManager 的管理。該方法執行後,傳入 persist() 方法的 Entity 對象轉換成持久化狀態。

如果傳入 persist() 方法的 Entity 對象已經處於持久化狀態,則 persist() 方法什麼都不做。

如果對刪除狀態的 Entity 進行 persist() 操作,會轉換為持久化狀態。

如果對遊離狀態的實體執行 persist() 操作,可能會在 persist() 方法拋出 EntityExistException(也有可能是在flush或事務提交後拋出)。

測試程式碼:

   @Test
    public void testPersist() {
        // 獲取連接
        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();
    }
// 日誌資訊
insert into course (cname, credit, end, num, start) values (?, ?, ?, ?, ?)

如果設置了id,就說明這是一個遊離狀態的實體類,執行會出現異常

4.2 merge 增\改

merge() 用於處理 Entity的同步。即資料庫的插入和更新操作。

image-20220921215136231

測試程式碼: 傳入新建狀態的對象

    @Test
    public void testMerge() {
        // 獲取連接
        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.merge(course);
        // 提交事務
        entityManager.getTransaction().commit();
        // 關閉連接
        JPAEntityFactory.close();
    }

查看日誌,可以看到,執行的是插入操作。

insert into course (cname, credit, end, num, start) values (?, ?, ?, ?, ?)

測試程式碼: 傳入遊離狀態對象

    @Test
    public void testMerge() {
        // 獲取連接
        EntityManager entityManager = JPAEntityFactory.getEntityManager();
        // 開啟事務
        entityManager.getTransaction().begin();
        Course course = new Course();
        course.setCid(2L);
        course.setCname("Spring編程實戰");
        course.setStart(DateUtil.stringToDate("2022-09-19"));
        course.setEnd(DateUtil.stringToDate("2022-12-30"));
        course.setCredit(2);
        course.setNum(88);
        // 對新建狀態 持久化
        entityManager.merge(course);
        // 提交事務
        entityManager.getTransaction().commit();
        // 關閉連接
        JPAEntityFactory.close();
    }

查看日誌,可以看到,執行的是Update語句

update course set cname=?,credit=?,end=?, num=?, start=? where cid=?

4.3 remove 刪

刪除實例。如果實例是被管理的,即與資料庫實體記錄關聯,則同時會刪除關聯的資料庫記錄。

注意:該方法只能移除持久化對象。

 @Test
    public void testRemove() {
        // 獲取連接
        EntityManager entityManager = JPAEntityFactory.getEntityManager();
        // 開啟事務
        entityManager.getTransaction().begin();
        // 查詢
        Course course = entityManager.find(Course.class, 2);
        // 對新建狀態 持久化
        entityManager.remove(course);
        // 提交事務
        entityManager.getTransaction().commit();
        // 關閉連接
        JPAEntityFactory.close();
    }

查看日誌,可以看到,執行的是Delete語句

delete from course where cid=?

4.4 find 查

find (Class<T> entityClass,Object primaryKey):返回指定的 OID 對應的實體類對象。

第一個參數為被查詢的實體類類型,第二個參數為待查找實體的主鍵值。

如果這個實體存在於當前的持久化環境,則返回一個被快取的對象;否則會創建一個新的 Entity, 並載入資料庫中相關資訊;若 OID 不存在於資料庫中,則返回一個 null。

    @Test
    public void testFind() {
        // 獲取連接
        EntityManager entityManager = JPAEntityFactory.getEntityManager();
        // 開啟事務
        entityManager.getTransaction().begin();
        // 查詢主鍵為3L
        Course course = entityManager.find(Course.class, 3L);
        loggerFactory.info("【find查詢結果:】{}", course);
        // 提交事務
        entityManager.getTransaction().commit();
        // 關閉連接
        JPAEntityFactory.close();
    }

查看日誌資訊:【find查詢結果:】Course(cid=3, cname=Spring編程實戰, start=2022-09-19, end=2022-12-30, credit=2, num=88)

4.5 getReference

getReference (Class<T> entityClass,Object primaryKey):與find()方法類似。

不同的是:如果快取中不存在指定的 Entity, EntityManager 會創建一個 Entity 類的代理,但是不會立即載入資料庫中的資訊,只有第一次真正使用此 Entity 的屬性才載入,所以如果此 OID(主鍵) 在資料庫不存在,getReference() 不會返回 null 值, 而是拋出EntityNotFoundException。

    @Test
    public void testGetReference() {
        // 獲取連接
        EntityManager entityManager = JPAEntityFactory.getEntityManager();
        // 開啟事務
        entityManager.getTransaction().begin();
        Course course = entityManager.getReference(Course.class, 3L);
        loggerFactory.info("【find查詢結果:】{}", course);
        // 提交事務
        entityManager.getTransaction().commit();
        // 關閉連接
        JPAEntityFactory.close();
    }

查看日誌資訊:【find查詢結果:】Course(cid=3, cname=Spring編程實戰, start=2022-09-19, end=2022-12-30, credit=2, num=88)

不存在,則會拋出異常:

image-20220921222722234