使用注解元數據
基本注解:
例子:
@Entity(name = "T_TOPIC") ①
public class Topic implements Serializable ...{
@Id ② -1
@GeneratedValue(strategy = GenerationType.TABLE) ② -2
@Column(name = "TOPIC_ID") ② -3
private int topicId;
@Column(name = "TOPIC_TITLE", length = 100) ③
private String topicTitle;
@Column(name = "TOPIC_TIME") @Temporal(TemporalType.DATE) ④
private Date topicTime;
@Column(name = "TOPIC_VIEWS")
private int topicViews;
...
}
解釋:
① Entity 標明該類 (Topic) 為一個實體類,它對應數據庫中的表表名是 T_TOPIC ,這里也可以寫成: @Entity
@Table(name = "T_TOPIC") 其作用都是一樣的
② -1 Id 標明該屬性對應數據表中的主鍵
② -2 GeneratedValue 通過 strategy 屬性指明主鍵生成策略,默認情況下, JPA 自動選擇一個最適合底層數據庫的主鍵生成策略。在 javax.persistence.GenerationType 中定義了以下幾種可供選擇的策略:
1) IDENTITY :表自增鍵字段, Oracle 不支持這種方式;
2) AUTO : JPA 自動選擇合適的策略,是默認選項;
3) SEQUENCE :通過序列產生主鍵,通過 @SequenceGenerator 注解指定序列名, MySql 不支持這種方式;
4) TABLE :通過表產生主鍵,框架借由表模擬序列產生主鍵,使用該策略可以使應用更易于數據庫移植。
② -3 Column 標明這個屬性是數據表中的一列,該列的名字是 TOPIC_ID
③ Column 的一個屬性 length 指明的是該屬性的允許的長度。 ( 個人認為設定該屬性只是對于程序中操作該屬性時增加了一驗證過程,對數據庫中該列原來的設置并沒有影響,但是 length 屬性指定的值必須不能大于數據庫創建表時給該列限制的最大長度否則會出錯 )
④ Temporal(TemporalType.DATE) :如果屬性是時間類型,因為數據表對時間類型有更嚴格的劃分,所以必須指定具體時間類型。在 javax.persistence.TemporalType 枚舉中定義了 3 種時間類型:
1) DATE :等于 java.sql.Date
2) TIME :等于 java.sql.Time
3) TIMESTAMP :等于 java.sql.Timestamp
繼承關系注解:
對繼承關系進行注解,必須在 父類 中聲明繼承實體的映射策略。
例子:
@Entity(name = "T_TOPIC")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) ① @DiscriminatorColumn(name = "TOPIC_TYPE", discriminatorType =
DiscriminatorType.INTEGER, length = 1) ②
@DiscriminatorValue(value="1") ③
public class Topic implements Serializable ...{ … }
解釋:
① Inheritance 通過 strategy 屬性指明實體的繼承策略。
在 javax.persistence.InheritanceType 定義了 3 種映射策略:
1) SINGLE_TABLE :父子類都保存到同一個表中,通過字段值進行區分。
2) JOINED :父子類相同的部分保存在同一個表中,不同的部分分開存放,通過表連接獲取完整數據;
3) TABLE_PER_CLASS :每一個類對應自己的表,一般不推薦采用這種方式。
② DiscriminatorColumn 如果繼承策略采用第一種繼承策略,則需要指明區分父子類的字段, DiscriminatorColumn 就是用來指明區分字段的注解。
③ DiscriminatorValue 同樣的采用第一種繼承策略通過字段區分父子類,則用這個注解給該實體的區分字段賦值在這里賦的值為 ”1”.
關聯關系注解:
例子:
@Entity @DiscriminatorValue(value="2") ①
public class PollTopic extends Topic ...{ ②繼承于 Topic 實體
private boolean multiple; ③
@Column(name = "MAX_CHOICES")
private int maxChoices; @OneToMany(mappedBy="pollTopic",cascade=CascadeType.ALL) ④
private Set options = new HashSet();
// 省略 get/setter 方法
}
解釋 :
① 通過 @DiscriminatorValue 將區分字段 TOPIC_TYPE 的值為 2 。由于 PollTopic 實體繼承于 Topic 實體,其它的元數據信息直接從 Topic 獲得。
④ OneToMany 指定了一個一對多的關聯關系, mappedBy 屬性指定 “Many” 方類引用 “One” 方類 的屬性名; cascade 屬性指明了級聯方式(如果這里不指定為 CascadeType.ALL 的話,那么有關聯關系的兩個對象在做保存和刪除操作時要分別來進行) 建議 :盡可能使用 cascade=CascadeType.ALL 來減少持久化操作的復雜性和代碼量
注意 : JPA 規范規定任何屬性都默認映射到表中,所以雖然我們沒有給③處的 multiple 屬性提供注解信息,但 JPA 將按照 默認的規則對該字段進行映射:字段名和屬性名相同,類型相同。如果我們不希望將某個屬性持久化到數據表中,則可以通過 @Transient 注解顯式指定:
@Transient
private boolean tempProp1;
@Entity(name="T_POLL_OPTION")
Public class PollOption implements Serializable ...{
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
@Column(name = "OPTION_ID")
private int optionId;
@Column(name = "OPTION_ITEM")
private String optionItem;
@ManyToOne ①
@JoinColumn(name="TOPIC_ID", nullable=false) ②
private PollTopic pollTopic;
}
解釋:
① ManyToOne 描述了多對一的關聯關系,他是對該類引用的 ”One” 類 (PollTopic) 的屬性( pollTopic )進行注解的。
② JoinColumn 指定關聯 ”One”(PollTopic) 實體所對應表的 “ 外鍵 ” 。
Lob 字段的注解:
在 JPA 中 Lob 類型類型的持久化很簡單,僅需要通過特殊的 Lob 注解就可以達到目的。
例子:
@Lob ① -1
@Basic(fetch = FetchType.EAGER) ① -2
@Column(name = "POST_TEXT", columnDefinition = "LONGTEXT NOT NULL") ① -3
private String postText;
@Lob
@Basic(fetch = FetchType. LAZY) ② -2
@Column(name = "POST_ATTACH", columnDefinition = "BLOB") ② -3
private byte[] postAttach;
解釋:
① -1 JPA 通過 @Lob 將屬性標注為 Lob 類型 ;
① -2 通過 @Basic 指定 Lob 類型數據的獲取策略, FetchType.EAGER 表示非延遲 加載,而 FetchType. LAZY 表示延遲加載 ;
① -3 通過 @Column 的 columnDefinition 屬性指定數據表對應的 Lob 字段類型。
使用 XML 元數據
除了使用注解提供元數據信息外, JPA 也允許我們通過 XML 提供元數據信息。按照 JPA 的規范, 如果你提供了 XML 元數據描述信息,它將覆蓋實體類中的注解元數據信息 。 XML 元數據信息以 orm.xml 命名,放置在類路徑的 META-INF 目錄下。
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
version="1.0">
①實體對象所在的包
<package>com.baobaotao.domain</package>
<entity class="Topic">
② Topic 實體配置
<table name="T_TOPIC" />
<attributes>
<id name="topicId">
<column name="TOPIC_ID"/>
<generated-value strategy="TABLE" />
</id>
<basic name="topicTitle">
<column name="TOPIC_TITLE" length="30" />
</basic>
<basic name="topicTime">
<column name="TOPIC_TIME" />
<temporal>DATE</temporal>
</basic>
<basic name="topicViews">
<column name="TOPIC_VIEWS" />
</basic>
</attributes>
</entity>
<entity class="PollTopic">
② PollTopic 實體配置
<discriminator-value>2</discriminator-value>
<attributes>
<basic name="maxChoices">
<column name="MAX_CHOICES" />
</basic>
<one-to-many name="options" mapped-by="pollTopic">
<cascade>
<cascade-all/>
</cascade>
</one-to-many>
</attributes>
</entity>
<entity class="PollOption">
② PollOption 實體配置
<table name="T_POLL_OPTION" />
<attributes>
<id name="optionId">
<column name="OPTION_ID" />
<generated-value strategy="TABLE" />
</id>
<basic name="optionItem">
<column name="OPTION_ITEM"/>
</basic>
<many-to-one name="pollTopic" >
<join-column name="TOPIC_ID" nullable="false"/>
</many-to-one>
</attributes>
</entity>
<entity class="Post">
② Post 實體配置
<table name="T_POST" />
<attributes>
<id name="postId">
<column name="POST_ID" />
<generated-value strategy="TABLE" />
</id>
<basic name="postText" fetch="EAGER">
<column name="POST_TEXT" column-definition="LONGTEXT NOT NULL"/>
<lob/>
</basic>
<basic name="postAttach" fetch="LAZY">
<column name="POST_ATTACH" column-definition="BLOB"/>
<lob/>
</basic>
</attributes>
</entity>
</entity-mappings>
使用這個 orm.xml 來描述實體信息的話,這里并沒有標明兩個繼承類之間的關系,其繼承信息將從實體類反射信息獲取。
到這里我們的實體描述結束了,當然我們只是做了比較簡單的描述,對于那些復雜的信息描述并沒有進行講述。實體描述結束了,有人會問如果我要來操作這些實體該怎么操作?這就是我們接下來要講述的問題。
EntityManager 介紹
實體對象由實體管理器進行管理, JPA 使用 javax.persistence.EntityManager 代表實體管理器。實體管理器和持久化上下文關聯,持久化上下文是一系列實體的管理環境,我們通過 EntityManager 和持久化上下文進