(二)JPA 連接工廠、主鍵生成策略、DDL自動更新
- 2022 年 9 月 24 日
- 筆記
- spring, SpringData
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為了適應這些不同的數據表的定義,也提供有不同的主鍵生成策略。
3、DDL自動更新
在實際的開發之中你是否會出現這樣的一種比較 尷尬 的問題,在進行開發的時候有人修改數據表,而後當前的實體類結構和數據表的結構不統一,但是在JPA設計的時候,充分的考慮到了這種數據表修改的問題(表可能存在,也可能不存在,或者表的結構可能修改了),所以在這樣的環境下就需要讓程式碼可以自動的進行數據表的糾正。
在傳統的項目開發之中,常規的做法是先進行數據表的創建,而後在圍繞數據表進行業務功能的實現。在每次業務發生改變時,也是先進行表結構的修改,而後再進行程式的變更,這樣的資料庫維護是非常繁瑣的,考慮到資料庫更新以及 資料庫移植 方面的設計,在 Hibernate 之中提供了 DDL 自動創建以及表更新策略
JPA現在主要是基於 Hibernate 實現,那麼 Hibernate 開發框架最早的一個特點就在於 可移植性,也就是說一個項目是在MySQL資料庫下開發的,那麼通過簡單的配置修改,可以讓程式碼直接在Oracle資料庫中運行。
對於當前市面上可以見到的ORM開發框架來講,只有JPA標準規定了資料庫移植性的話題,而Hibernate 實現了JPA標準,所以只有Hibernate 開發框架具有移植性的功能,而像大家所熟悉的MyBatis是沒有這樣的功能。
DDL更新策略
3.1、使用
去到JPA配置文件中,修改DDL更新策略、
3.1.1、create
每次載入時,根據實體類生成表,如果表存在於資料庫,會先刪除
<!-- JPA更新策略 -->
<property name="hibernate.hbm2ddl.auto" value="create"/>
查看執行日誌信:可以看到 drop table if exists course (刪除表,然後會依據實體類,重新創建表)
3.1.2、update
如果表不存在,重建表。
存在:如:實體類某個欄位,在數據表中不存在,這個時候會添加。但是,刪除實體類的某個欄位,資料庫對應的欄位並不會刪除。
修改實體類: 添加教師
修改配置文件-更新策略為update
查看執行日誌:
表不存在,創建表
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即可