1. JPA核心API對象 1.1.Persistence持久化對象 Persisitence主要用於創建EntityMangerFactory,它可以根據傳入的持久化單元名稱來創建對應的EntityMangerFactory。 // 對應配置文件裡面的persistence-unit name=" ...
1. JPA核心API對象
1.1.Persistence持久化對象
Persisitence主要用於創建EntityMangerFactory,它可以根據傳入的持久化單元名稱來創建對應的EntityMangerFactory。
// 對應配置文件裡面的persistence-unit name="cn.yif.jpa02" // 通過持久化類創建一個實體類管理工廠 EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("cn.yif.jpa02");
1.2.EntityMangerFactory實體管理工廠
EntityMangerFactory是一個線程安全的對象,在一個項目中只需要一個EntityManger對象,對應一個資料庫資源,EntityMangerFactory對象是一個重量級對象,創建與銷毀是比較耗費資源的,其中包含了資料庫的配置信息,所有實體及關係,預定義JPQL語句、二級緩存。
1.3.EntityManger實體管理對象
EntityManger提供和持久化相關的操作:包括增、刪、改、查等,是線程不安全的對象,因此在項目中應該每次只能讓一個線程所使用,避免多個線程共用使用。EntityManger是輕量級的,創建與銷毀不需要消耗太多的資源,應該用完就關閉。Web中對應一次請求,創建一個EntityManger對象。
1.4.Transcation事務
分為javax.persistence.EntityTransaction與javax.transaction.Transaction JTA事務兩種。
javax.persistence.EntityTransaction:只能控制相同一個資料庫不同表的事務管理,大多數情況使用這種。
javax.transaction.Transaction:處理不同資料庫不同表的事務管理。Tomcat預設不支持JTA事務(可以通過插件來解決),或者需要用JavaEE伺服器:如jboss、weblogic伺服器。
JTA事務使用場景:比如跨行轉賬、事務列表。
2. 主鍵生成策略
主鍵實現有兩種類型,分為:自然主鍵與代理主鍵。
自然主鍵:表示把含有業務意義的欄位作為主鍵,一般比如使用身份證號、手機號等作為自然主鍵,而且此欄位必須唯一。
註意:在JPA中不定義@GeneratedValue則表示自然主鍵,在保存之前自己設置主鍵值。
代理主鍵:主鍵一般沒有任何意義,用來區別每行數據是不同的。
在JPA中提供了四種主鍵生成的策略:IDENTITY、SEQUENCE、TABLE、AUTO。
2.1.IDENTITY
IDENTITY表示主鍵自增,JPA配置IDENTITY策略時會自動將主鍵設置為自增+1,具體配置如下:
//@Id是必須的註解,表示對應資料庫的主鍵 @Id //GeneratedValue表示主鍵生成策略 //①IDENTITY:表示的是自增, // 特點:1.主鍵必須是數值類型;2.使用的資料庫必須支持自增功能;3.使用資料庫原生的生成策略,性能是很高的 // 4.支持IDENTITY的資料庫類型:MySQL, SQL Server, DB2, Derby, Sybase, PostgreSQL @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id;
2.2.SEQUENCE
SEQUENCE表示自增方式為序列方式,一般在Oracle中使用,一個Domain創建一張表,對應一個序列,Oracle不支持ID自增長列而是使用序列機制生成主鍵ID。
//②SEQUENCE:序列 //特點:1.主鍵必須是數值類型;2.使用的資料庫必須支持序列;3.使用資料庫原生的生成策略,性能上是很高的 //4.會預設去創建一個序列,這個序列的名稱叫做:HIBERNATE_SEQUENCE,所有Domain都預設使用這個序列,ID在這個序列基礎上自增 //使用名叫SEQ特定的序列 @GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "SEQ") //name:序列生成器的名稱,會在@GeneratedValue中進行引用 //sequenceName會對應真實資料庫中序列的名稱OIDDOMAIN_SEQUENCE,在資料庫中創建名稱為OIDDOMAIN_SEQUENCE的序列 //如果不指定序列生成器的名稱sequenceName = "OIDDOMAIN_SEQUENCE", //則使用廠商提供的預設序列生成器,比如Hibernate預設提供的序列名稱為HIBERNATE_SEQUENCE @SequenceGenerator(name = "SEQ", sequenceName = "OIDDOMAIN_SEQUENCE") private Integer id;
支持SEQUENCE的資料庫:Oracle、Post greSQL、DB2。
2.3.TABLE
TABLE支持所有的資料庫類型,在實際項目中如果前期確定不了資料庫,可以使用TABLE。
//③TABLE(高低位) //特點:1.主鍵必須是數值類型;2.支持所有的資料庫類型(使用預設的序列);3.性能超級低,每次使用都要進行查詢與修改(相容性犧牲) //如果不使用表生成器,會使用預設的表,比如Oracle中使用HIBERNATE_SEQUENCE @TableGenerator(name = "SEQ", table = "OidDomain_TABLE", pkColumnName = "SEQUENCE_NAME", valueColumnName = "SEQUENCE_COUNT", initialValue = 1, allocationSize = 1) @GeneratedValue(strategy = GenerationType.TABLE, generator = "SEQ") private Integer id;
2.4.AUTO
//④AUTO 自動根據具體的資料庫選擇合適的策略,可以是TABLE/SEQUENCE/IDENTITY中的一種 //假如資料庫是Oracle,則選擇顯示配置Sequence,不使用預設序列配置 //假如資料庫是MySQL,則選擇Identity //如果不特別指定,這是預設的主鍵生成策略 @GeneratedValue(strategy = GenerationType.AUTO) private Integer id;
3. JPA持久對象狀態
JPA中有四種持久化對象的狀態:臨時狀態(transient):瞬時狀態、持久化狀態(persistent):托管狀態、游離狀態(detached):脫管狀態、刪除狀態(removed)。
臨時狀態:表示該對象剛剛使用new語句創建,沒有和EntityManager發生關係。沒有被持久化,不處於EntityManager中。
持久化狀態:表示該對象和EntityManager發生了關係,被加入到EntityManager的一級緩存中,一級緩存中有數據了。
游離狀態:這個對象和EntityManager解除了關係,已經被持久化,但不處於EntityManager中。
刪除狀態:調用了EntityManager.remove()方法,對象有關聯的ID,並且在EntityManager的管理下,可能計劃被刪除,事務被commit提交後真正刪除。
3.1.臟數據更新
臟數據:一個持久化對象在事務管理內,發生在事務訪問數據並對數據進行了修改,但還未提交到資料庫中,未提交的這個數據就叫做臟數據。
而臟數據在JPA中執行merge時,與是否調用merge方法無關,此時當事務進行提交commit時,會自動更新到資料庫中。
@Test public void JPAUpdate() { EntityManager entityManager = JPAUtil.getEntityManager(); EntityTransaction transaction = entityManager.getTransaction(); transaction.begin(); //從資料庫中拿到的對象是一個持久化的對象 Employee employee = entityManager.find(Employee.class, 1); employee.setName("修改者哈哈"); employee.setAge(223); //執行修改 //在對象是持久化對象的狀態下,用不用merge方法,和修改沒有關係,即調用與否,都會向資料庫做修改 //entityManager.merge(employee); //提交的時候會從資料庫查詢有沒有這個employee,如果變更了,就執行merge進行數據更新 //即commit的時候才執行sql,這個過程叫做臟數據更新(一旦持久化數據對象進行修改,就是臟數據) transaction.commit(); JPAUtil.close(entityManager); }
3.2.臟數據更新執行流程
① 拿到entityManager對象,開啟事務;
② 通過entityManager對象從資料庫中查詢到對應的持久化對象,這個對象會放入到一級緩存中,JPA會為當前的這個對象準備一個快照(相當於把這個對象進行一個備份);
③ 在提交事務之前,JPA會將當前這個快照對象與資料庫中查詢到的對象做一個對比,如果相同,就不需要進行修改了,也不會發送對應的merge SQL進行修改;如果對比發現不同,那麼JPA就會認為現在這個數據是臟數據,臟數據在事務進行提交的時候,發送merge SQL語句進行資料庫數據的同步。
3.3.Persist與Merge對比
@Test public void JPAPersistOrMerge() { Employee employee = new Employee("創建者001", 20); EntityManager entityManager = JPAUtil.getEntityManager(); EntityTransaction transaction = entityManager.getTransaction(); transaction.begin(); /** * persist:放到方法中的對象會變成持久化對象,改變的是原對象(這個對象就在一級緩存當中) */ entityManager.persist(employee); employee.setName("更新創建者001"); transaction.commit(); JPAUtil.close(entityManager); }
對應會執行兩條SQL語句:先發送insert語句,之後發送update語句進行臟數據更新。
@Test public void JPAPersistOrMerge() { Employee employee = new Employee("創建者001", 20); EntityManager entityManager = JPAUtil.getEntityManager(); EntityTransaction transaction = entityManager.getTransaction(); transaction.begin(); /** * merge:放到方法中的對象不會變成持久化對象,但是它會返回一個持久化對象,修改持久化對象同樣生效 */ //entityManager.persist(employee); Employee employee1 = entityManager.merge(employee); employee1.setName("更新創建者001"); transaction.commit(); JPAUtil.close(entityManager); }
執行上述操作同樣會發送兩條SQL語句:
3.4.Remove的使用
JPA中remove是不是直接刪除數據,而是修改一個對象的狀態為刪除狀態,當事務提交commit之後,delelte SQL語句才會發送,對應去刪除數據中的臟數據。
@Test public void JPARemove() { EntityManager entityManager = JPAUtil.getEntityManager(); EntityTransaction transaction = entityManager.getTransaction(); transaction.begin(); /** * remove並不是直接刪除數據,而是修改一個持久化對象的狀態為刪除狀態(計劃刪除) * 對應只能有一個entityManager,其它entityManager對象的持久化狀態在這裡是不能使用的 */ Employee employee = entityManager.find(Employee.class, 7); entityManager.remove(employee); transaction.commit(); JPAUtil.close(entityManager); }