JPA基本介紹以及使用
阿新 • • 發佈:2018-12-25
JPA即Java Persistence Architecture,Java持久化規範,從EJB2.x版本中原來的實體Bean分離出來的,EJB3.x中不再有實體Bean,而是將實體Bean放到JPA中來實現。可以說,JPA借鑑了Hibernate的設計,JPA的設計者就是Hibernate框架的作者。
JPA的底層實現是一些流行的ORM框架,比如Hibernate,EclipseLink,OpenJPA等實現方式。
EntityManagerFactory作為EntityManager的工廠類,建立並管理多個EntityManager例項;EntityManager介面管理持久化操作的物件,其中包含了對實體(Entity,儲存在資料庫中的記錄物件表示)的所有增刪改查操作。
EntityManagerFactory是一個spi實現的工廠類,可以建立多個不同的EntityManager;每個EntityManager中只有一個EntityTransaction例項,但可以建立多個不同的Query例項,並執行查詢,管理多個Entity實體。 JPA中比較核心的配置檔案是persistence.xml檔案,基本樣式如下:
本例程中使用了Hibernate3.6作為JPA的實現,並以hsqldb作為測試資料庫進行配置,在使用Spring容器的場景下通過下面的配置方式進行設定:
EntityManagerFactory作為EntityManager的工廠類,建立並管理多個EntityManager例項;EntityManager介面管理持久化操作的物件,其中包含了對實體(Entity,儲存在資料庫中的記錄物件表示)的所有增刪改查操作。
EntityManagerFactory是一個spi實現的工廠類,可以建立多個不同的EntityManager;每個EntityManager中只有一個EntityTransaction例項,但可以建立多個不同的Query例項,並執行查詢,管理多個Entity實體。 JPA中比較核心的配置檔案是persistence.xml檔案,基本樣式如下:
<?xml version="1.0"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0"> <persistence-unit name="hsqldb-unit" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/> <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/> <property name="hibernate.connection.username" value="sa"/> <property name="hibernate.connection.password" value=""/> <property name="hibernate.connection.url" value="jdbc:hsqldb:hsql://localhost/test"/> <property name="hibernate.max_fetch_depth" value="3"/> <property name="hibernate.hbm2ddl.auto" value="update"/> <property name="hibernate.jdbc.fetch_size" value="18"/> <property name="hibernate.jdbc.batch_size" value="10"/> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.format_sql" value="true"/> </properties> </persistence-unit> </persistence>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdaptor"/> <property name="packagesToScan" value="xxx"/> <property name="loadTimeWeaver"> <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/> </property> <property name="persistenceXmlLocation" value="/WEB-INF/config/persistence.xml"/> </bean> <bean id="hibernateJpaVendorAdaptor" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="databasePlatform" value="org.hibernate.dialect.H2Dialect"/> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean>
JPA的持久化對映的資料表
作為ORM框架,肯定是有一套對應Java物件實體到關係資料庫對映的工具。在Hibernate誕生之初使用的是.hibernate.xml配置檔案的方式,而最近通過註解工具的發展(Annotation,@),已經可以通過更便於管理的方式定義這種關係(當然還可以採取更加靈活的註解+配置檔案的混合方式)。 使用@Entity來標識一個持久化物件,所有對應資料庫表的持久化物件都必須宣告該註解,並可以定義name欄位的名稱來自定義資料表的內容。 使用@Id來標識主鍵,持久化物件必須含有主鍵,主鍵一般使用與業務無關的自增/隨機欄位來表示(不建議使用聯合主鍵的方式),以獲得更好的擴充套件性。 可以使用@GenerateValue方式來宣告主鍵自動生成的策略,有下面四種方式:- GenerationType.TABLE:使用獨立表來記錄主鍵,適用於各種資料庫,但效能會差一些,因其每次進行insert時都會額外發出一次主鍵查詢;
- GenerationType.SEQUENCE:只適用於oracle資料庫;
- GenerationType.IDENTITY:適用於Sqlserver等資料庫;
- GenerationType.AUTO:由JPA實現來探測底層使用的資料庫,自動採取一種主鍵自增的策略,可以指定生成器。如對Oracle採用SEQUENCE策略,對Sqlserver採用IDENTITY策略。AUTO策略支援目前絕大多數已知的資料庫,這是預設的策略也是我們目前採用的策略。
- Clob:java.lang.String, java.lang.Character[],java.lang.char[], java.sql.Clob可對映為Clob;
- Blob:java.lang.byte[], java.lang.Byte[], java.sql.Blob及實現了Serializable物件的類可對映為Blob。
資料表之間的關聯關係對映
資料表之間的關聯關係在JPA中有三種:@OneToOne
一對一對映分為主鍵關聯和外來鍵關聯兩種方式,如果使用主鍵關聯,那麼從表的的主鍵同時也是外來鍵,主從表中關聯的記錄主鍵完全一致,需要在被維護端使用@PrimaryKeyJoinColumn指定對應的關係,比如下面的例子:@Entity
public class Husband {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToOne(mappedBy="husband", cascade=CascadeType.ALL)
private Wife wife;
...
}
@Entity
public class Wife {
@Id
private Long id;
private String name;
@OneToOne(cascade=CascadeType.ALL)
@PrimaryKeyJoinColumn
@MapsId
private Husband husband;
}
如果是外來鍵關聯,則會使用一個額外的外來鍵欄位來建立關聯關係,比如下面的例子:
@Entity
public class Car {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE}, fetch=FetchType.LAZY) @JoinColumn(name="engine_id")//外來鍵關聯欄位
private Engine engine;
@Entity
public class Engine {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToOne(mappedBy="engine", fetch=FetchType.LAZY, cascade={CascadeType.PERSIST, CascadeType.MERGE})
private Car car;
}
@OneToMany @ManyToOne
一對多/多對一對映註解,在雙向一對多關係中,一端是關係維護端,只能在另一端中新增mapped屬性,多端是關係被維護端,建表時在關係被維護端(多的那一端)中建立一個外來鍵指向關係維護端的主鍵一列。 比如:@OneToMany(mappedBy = "executableSubTaskDefinition", fetch = FetchType.LAZY)
private List<ExecutableSubTaskStatus> executableSubTaskStatusList = new ArrayList<>();
注意,mappedBy即為ExecuteableSubTaskStatus中的@ManyToOne成員變數名稱而非資料庫欄位名稱,那麼在另一端,
@ManyToOne(cascade = CascadeType.ALL, optional = false)
private ExecutableSubTaskDefinition executableSubTaskDefinition;
@ManyToMany
多對多對映是相對來說最為複雜的一種對映關係,會採取中間表連線的對映策略,建立的中間表分別引入兩邊的主鍵作為外來鍵,形成兩個一對多關係。 在雙向的多對多關係中,在關係維護端(owner side)的 @ManyToMany 註解中新增 mappedBy 屬性,另一方是關係的被維護端(inverse side),關係的被維護端不能加 mappedBy 屬性,建表時,根據兩個多端的主鍵生成一箇中間表,中間表的外來鍵是兩個多端的主鍵: 關係維護端——> @ManyToMany(mappedBy="另一方的關係引用屬性") 關係被維護端——> @ManyToMany(cascade=CascadeType.ALL ,fetch = FetchType.Lazy) 比如下面的例項:@ManyToMany
@JoinColumn(name = "task_data_range")
private List<SubTaskDefinition> subTaskDefinitions = new ArrayList<>();
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "sub_task_data_range", joinColumns = @JoinColumn(name = "sd_task_id", referencedColumnName = "sub_task_definition_id"),
inverseJoinColumns = @JoinColumn(name = "sd_data_id", referencedColumnName = "task_data_range_id"))
private List<TaskDataRange> taskDataRanges = new ArrayList<>();