JPA Java Persistence API
1、 JPA是Java EE 平台标准的ORM(对象关系映射)规范
2、 JPA通过注解或XML描述对象关系表的映射关系,并将运行期的实体对象持久化到数据库中。
3、 JPA的宗旨是为POJO(简单的Java对象)提供持久化标准规范
4、 元数据被定义为:在程序中不是被加工的对象,而是通过其值的改变来改变程序的行为的数据。它在运行过程中起着以解释方式控制程序行为的作用。在程序的不同位置配置不同值的元数据,就可以得到与原来等价的程序行为。
JPA包括以下3方面的技术:
1、 ORM (Object –Relation Mapping) 映射元数据,元数据描述对象和表之间的映射关系
2、 JPA的API,用来操作实体对象、执行CRUD操作
3、 查询语句(JPQL语句)
具有ORM元数据的领域对象称为实体(Entity),按JPA的规范,实体具备以下的条件:
1、 必须使用javax.persistence.Entity注解或者XML映射文件中对应的元素。
2、 必须具有一个不带参数的构造函数,类不能声明为final,方法和需要持久化的属性也不能声明为final。
3、 如果游离状态的实体对象需要以值的方式进行传递,如通过Session bean的远程业务接口传递,则必须实现Serializable接口
4、 需要持久化的属性,其访问修饰符不能是public,它们必须通过实体类方法进行访问
使用注解元数据
@Entity(name = "T_TOPIC")
//将领域对象标注为一个实体,表示需要保存到数据库中
public class Topic implements Serializable {
@Id
// 对应的属性是表的主键
@GeneratedValue(strategy = GenerationType.TABLE)
// 主键的产生策略,默认为ATUO,JPA自动选择最合适的生成策略。TABLE:通过表产生主键
@Column(name = "TOPIC_ID")
// 属性对应的表字段
private String topicId;
@Column(name = "TOPIC_TITLE", length = 100)
// 如果属性对应的字段是字符串类型,可以指定长度
private String topicTitle;
@Column(name = "TOPIC_TIME")
@Temporal(TemporalType.DATE)
// 指定具体的时间类型,共有三种类型
//DATE:等于java.sql.Date 2008-01-01
//Time:等于java.sql.Time 12:22
//TIMESTAMP:返回1970年至今的毫秒数
private Date topicTime;
@Column(name = "TOPIC_VIEWS")
private int topicViews;
}
继承关系
JPA采用多种方法来支持实体继承,在父类中必须声明继承实体的映射策略
@Entity(name = "T_TOPIC")
//将领域对象标注为一个实体,表示需要保存到数据库中
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
//SINGLE_TABLE:父子类都保存到同一个表中,通过字段进行区分。
//JOINED:父子类相同的部分保存在同一个表中,不同的部分分开存放
//TABLE_PER_CLASS:每一个类对应自己的表
@DiscriminatorColumn(name="TOPIC_TYPE",discriminatorType=DiscriminatorType.INTEGER,length=1)
//区别的字段通过DiscriminatorColumn说明,"TOPIC_TYPE"代表区别字段名
@DiscriminatorValue(value="1")
//区别字段对应的实体值通过DiscriminatorValue指定
public class Topic implements Serializable {
}
关联关系
@Entity
@DiscriminatorValue(value = "2")
//由于PollTopic实体继承了Topic实体,其他的元数据信息直接从Topic获得
public class PollTopic {
private boolean multiple;
//JPA规定任何属性都默认映射到表中,虽然multiple没有注解信息,但也被映射到表中,
//字段名和属性名相同,类型相同,如果我们不希望将这个字段持久化到数据库中,可以使用@Transient注解
//@Transient
//private boolean multiple;
@Column(name = "MAX_CHOICES")
private int maxChoices;
@OneToMany(mappedBy = "pollTopic", cascade = CascadeType.ALL)
//mappedBy属性指定"Many"方类引用"One"方类的属性名
private Set options = new HashSet();
}
Lob字段
@Entity(name = "T_POST")
public class Post implements Serializable {
@Lob
//JPA通过@Lob将属性标注为Lob类型
@Basic(fetch = FetchType.EAGER)
//通过@Basic指定Lob类型数据的获取策略,FetchType.EAGER表示非延迟加载
@Column(name = "POST_TEXT", columnDefinition = "LONGTEXT NOT NULL")
//postText属性对应T_POST表的POST_TEXT字段,该字段的类型是LONGTEXT,非空
private String postText;
@Lob
@Column(name = "POST_ATTACH", columnDefinition = "BLOB")
//通过@Column的columnDefinition指定数据表对应的Lob字段类型
@Basic(fetch = FetchType.LAZY)
//FetchType.LAZY表示延迟加载
private byte[] postAttach;
}
关于XML元数据
按照JPA的规范,如果你提供了XML元数据描述信息,它将覆盖实体类中的注解元数据信息,XML元数据以orm.xml
命名,放置在类路径的META-INF目录下
JPA重要API
JPA接口位于javax.persistence和javax.persistence.spi两个包中,javax.persistence包中大部分API都是注解类、EntityManager、Query等持久化操作接口。而javax.persistence.spi包中的4个API,是JPA的服务层接口
EntityManager
实体对象由实体管理器进行管理,通过EntityManager和持久化上下文进行交互
实体管理器有两种:
容器类:容器型的实体管理器由容器负责试题管理器之间的协作,Java EE应用服务器提供的就是管理型的实体管理器。
应用程序型:实体管理器的生命周期由应用程序控制,应用程序通过javax.persistence.EntityManagerFactoty的creaeEntityManager创建EntityManager实例
实体的状态
实体共有4种状态:
1、 新建态:新创建的实体对象,尚未拥有持久化主键,没有和一个持久化上下文关联起来
2、 受控态:已经拥有持久化主键和持久化上下文建立了联系
3、 游离态:拥有持久化主键,但尚未和持久化上下文建立联系
4、 删除态:拥有持久化主键,已经和持久化上下文建立了联系,但已经被安排从数据库中删除
EntityManager的API
void persist(Object entity)
通过persist方法,新实体实例将转换为受控状态,就是说,当persist()方法所在的事务提交时,实体的数据保存到数据库中。
如果实体已经被持久化,那么调用persist()方法不会发生任何事情。
如果对一个已经删除的实体调用persist()方法,删除态的实体又转变为受控态
如果对游离状态的实体执行persist()操作,抛出IllegalArgumentException
一个实体调用persist()方法后,所有与之关联的实体,都将执行持久化操作
void remove(Object entity)
删除一个受控态的实体。
如果实体声明为级联删除(cascade=REMOVE或者cascade=ALL),被关联的实体也会被删除
在一个新建态或删除态的实体上调用remove()方法,将被忽略
在游离态的实体上调用remove()方法,将抛出IllegalArgumentException,相关事务将回滚
void flush()
将受控态的实体数据同步到数据库中
T merge(T entity)
将一个游离态的实体持久化到数据库中,并转换为受控态的实体
T find(Class entityClass.Object primaryKey)
以主键查询实体对象,entityClass是实体的类,primaryKey是主键值
Eg:Topic t = em.find(Topic.class,1);