参考链接:http://blog.163.com/hero_213/blog/static/398912142010312024809

近年来ORM(Object-Relational Mapping)对象关系映射,即实体对象和数据库表的映射)技术市场人声音鼎沸,异常热闹, Sun在充分吸收现有的优秀ORM框架设计思想的基础上,制定了新的JPA(Java Persistence API)规范。JPA Java Persistence API,是Java EE 5的标准ORM接口,也是ejb3规范的一部分。

那么什么是JPA呢?JPA是通过JDK5.0注解或XML描述对象-关系表的映射关系,并将运行期实体对象持久化到数据库中去。

Hibernate与JPA的关系及其实现机制

JPA和Hibernate之间的关系,可以简单的理解为JPA是标准接口,Hibernate是实现。那么Hibernate是如何实现与JPA的这种关系的呢。Hibernate主要是通过三个组件来实现的,及hibernate-annotation、hibernate-entitymanager和hibernate-core。

hibernate-annotation是Hibernate支持annotation方式配置的基础,它包括了标准的JPA annotation以及Hibernate自身特殊功能的annotation。

hibernate-core是Hibernate的核心实现,提供了Hibernate所有的核心功能。

hibernate-entitymanager实现了标准的JPA,可以把它看成hibernate-core和JPA之间的适配器,它并不直接提供ORM的功能,而是对hibernate-core进行封装,使得Hibernate符合JPA的规范。

下面重点介绍一下hibernate-entitymanager包的主要类及实现。

HibernatePersistence.java,实现了JPA的PersistenceProvider接口,它提供createEntityManagerFactory和createContainerEntityManagerFactory两个方法来创建EntityManagerFactory对象,这两个方法底层都是调用的EJB3Configuration对象的buildEntityManagerFactory方法,来解析JPA配置文件persistence.xml,,并创建EntityManagerFactory对象。

EntityManagerFactory对象的实现是EntityManagerFactoryImpl类,这个类有一个最重要的*******属性就是Hibernate的核心对象之一SessionFactory。这个类最重要的方法是createEntityManager,来返回EntityMnagaer对象,而sessionFactory属性也传入了该方法。

EntityManager对象的实现是EntityManagerImpl类,这个类继承自AbstractEntityManagerImpl类,在AbstractEntityManager类中有一个抽象方法getSession来获得Hibernate的Session对象,正是在这个Session对象的实际支持下,EntityManagerImpl类实现了JPA的EntityManager接口的所有方法,并完成实际的ORM操作。

此外,hibernate-entitymanager包中还有QueryImpl类利用EntityManagerImpl的支持实现了JPA的Query接口;TransactionImpl利用EntityManagerImpl的支持实现了JPA的EntityTransaction接口。

至此,Hibernate通过hibernate-entitymanager包完成了对于JPA的全部支持工作。

这里我们要先谈一下什么叫实体(Entity),按照JPA规范,具有ORM元数据的领域对象就叫做实体。它应具备一下条件: 
1.必须使用javax.persistence.Entity注解或XML映射文件中有对应的<entity>元素; 
2.必须具有一个不带参数的构造函数,类不能声明为final,方法和需要持久化的属性也不能声明为final; 
3.如果游离态的实体对象需要以值的方式进行传递(如通过Session bean的远程业务接口传递),则必须实现Serializable接口; 
4.需要持久化的属性,起访问修饰符不能是public,它必须通过实体类方法进行访问。

实体的状态

实体共有4种状态:

1、 新建态:新创建的实体对象,尚未拥有持久化主键,没有和一个持久化上下文关联起来

2、 受控态:已经拥有持久化主键和持久化上下文建立了联系

3、 游离态:拥有持久化主键,但尚未和持久化上下文建立联系

4、 删除态:拥有持久化主键,已经和持久化上下文建立了联系,但已经被安排从数据库中删除

下面我们来尝试对一个域对象进行JPA注解,使其成为一个实体类:

@Entity(name=”T_TEST”)
public class Test implements Serializable{
@Id
@GeneratedValue(strategy=GenerationType.TABLE)
@Column(name=” id”)
******* int testId;
@Column(name=”uname”,length=100)
******* String uname;
@Column(name=”password”)
******* String password;
@Column(name=”time”)
@Temporal(TemporalType.Date)
******* Date loginTime;
//省略get/setter方法
}

@下面对以上代码中所涉及的JPA注解进行一下说明

@Entity:将领域对象标注为一个实体类,表示该类需要持久化到数据库中,默认情况下类名即表名,通过name属性显式指定表名,如:name=”T_TEST”表示将Test保存到表T_TEST表中。

@Id:对应的属性是表的主键

@GeneratedValue:主键的产生策略,通过strategy属性进行指定,默认情况下,JPA自动选择一个最适合底层数据库的主键生成策略,如SqlServer对应的identity:

mysql对应的auto increment,在java.persistence.GenerationType中定义了几种可以供选择的策略

1.  :表自动增长字段,Oracle不支持这种方式;Identity

2.  :JPA自动选择合适的策略,是默认选项;AUTO

3.  :通过序列产生主键,通过@SequenceGenerator注解指定序列名,Mysql不支持这种方式。Sequence

4.  :通过表产生主键,框架借由表模拟产生主键,使用该策略可以使用更易于数据库的移植。TABLE

@Colunm(name=”uname”):属性对应的表字段。我们并不需要指定表字段的类型,因为JPA 会根据反射从实体属性中获取类型;如果是字符串类型,我们可以指定字段长度,以便可以自动生成DDL语句。

@Temporal(TemporalType.DATE):如果属性是时间类型,因为数据表对时间类型有更严格的划分,所以必须指定具体时间类型,在java.persistence.TemporalType枚举中定义了三种时间类型:

Date:等于java.sql.Date;

Time:等于java.sql.Time;

TimeStamp:等于java.sql.Timestamp。

JPA对于具有父子关系的类,对于父类必须声明继承实体的映射策略,对于继承实体,java.persistence.InheritanceType定义了3种映射策略:

SINGLE_TABLE:父子类都保存在同一个表中,通过字段值进行区分。

JOINED:父子类相同的部分保存在同一个表中,不同的部门分开存放,通过连接不同的表获取完整数据。

TABLE_PER_CLASS:每一个类对应自己的表,一般不推荐采用这种方式。

下面我们来看看实际的列子是怎么运用的。

父类Test:

@Entity(name=”test”)
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)//指定继承策略
@DiscriminatorColumn(name=”types”,discriminatorType=DiscriminatorType.INTEGER,length=1)//指定区分字段为types,类型为Integer长度为1
@DiscriminatorValue(value=”1”)//对应具体实体的值
public class Test implements Serializable{
…..
}

子类Child:

@Entity
@DiscriminatorValue(value=”2”)
public class Child extends Test{
//如果我们不希望JPA将该属性持久化到数据库,则采用该注解
@Transient
******* String tempStr;
@Lob //lob类型的字段
@Basic(fetch=FetchType.Lazy) //采用延迟加载,FetchType.EAGER不采用
@Column(name=”postattach”,columnDefinition=”LONGTEXT NOT NULL”)对应字段类型
******* String postAttach;
}

可以看到通过字段types来区分父子类数据,也是相当方便的。至于JPA提供的关联关系比如说一对多,多对一,多对多,也有相应的注解进行关联,有兴趣的朋友可以参考相关帮助文档。

以上讲述的都是JPA中以注解形式进行持久化,下面我们来看下采用XML元数据的形式,XML元数据信息以orm.xml命名,放置在类路径的META-INF 目录下。如果你提供了 XML 元数据描述信息,它将覆盖实体类中的注解元数据信息

<?xml version=”1.0” encoding=”UTF-8”?>

<entity-mappings xmlns=”http://java.sun.com/xml/ns/persistence/orm” 

xmlns=”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.test</package>

<entity class=”Test”> 

<table name=”test”/> 

<attributes> 

<id name=”id”> 

<column name=”id”/> 

<generated-value strategy=”TABLE”/> 

</id> 

<basic name=”uname”> 

<column name=”uname” length=”30”/> 

</basic> 

<basic name=”logintime”> 

<column name=” logintime”/> 

<temporal>DATE

</temporal> 

</basic> 

</attributes>

</entity>

<entity-mappings>
 

可以看到JPA元数据采用XML形式也是相当简单易懂的。

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实例

EntityManagerAPI

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);

Hibernate+JPA的更多相关文章

  1. spring data jpa hibernate jpa 三者之间的关系

    JPA规范与ORM框架之间的关系是怎样的呢? JPA规范本质上就是一种ORM规范,注意不是ORM框架——因为JPA并未提供ORM实现,它只是制订了一些规范,提供了一些编程的API接口,但具体实现则由服 ...

  2. spring+hibernate+jpa+Druid的配置文件,spring整合Druid

    spring+hibernate+jpa+Druid的配置文件 spring+hibernate+jpa+Druid的完整配置 spring+hibernate+jpa+Druid的数据源配置 spr ...

  3. hibernate jpa 2.0 报错Hibernate cannot unwrap interface java.sql.Connection

    今天在做报表的时候,利用Hibernate JPA 2.0需要获取数据库连接com.sql.Connection的时候获取不到,网上说用这种方式解决: entityManager.getTransac ...

  4. websphere部署 hibernate jpa & Error 500: javax/persistence/OneToOne.orphanRemoval()Z

    WebSphere 7 & Javax/Persistence/OneToMany.OrphanRemoval() Error 文章出处:http://www.mkyong.com/websp ...

  5. Hibernate JPA 关联关系

    Hibernate JPA 关联关系: 使用cascade做级联操作(只有在满足数据库约束时才会生效): CascadeType.PERSIST: 级联保存,只有调用persist()方法,才会级联保 ...

  6. Spring Hibernate JPA 联表查询 复杂查询(转)

    今天刷网,才发现: 1)如果想用hibernate注解,是不是一定会用到jpa的? 是.如果hibernate认为jpa的注解够用,就直接用.否则会弄一个自己的出来作为补充. 2)jpa和hibern ...

  7. Spring MVC+Hibernate JPA搭建的博客系统项目中所遇到的坑

    标签: springmvc hibernate 2016年12月21日 21:48:035133人阅读 评论(0) 收藏 举报  分类: Spring/Spring MVC(6)  Hibernate ...

  8. Spring Hibernate JPA 联表查询 复杂查询

    今天刷网,才发现: 1)如果想用hibernate注解,是不是一定会用到jpa的? 是.如果hibernate认为jpa的注解够用,就直接用.否则会弄一个自己的出来作为补充. 2)jpa和hibern ...

  9. Hibernate JPA实体继承的映射(二) @MappedSuperclass

    基于代码复用和模型分离的思想,在项目开发中使用JPA的@MappedSuperclass注解将实体类的多个属性分别封装到不同的非实体类中. 1.@MappedSuperclass注解只能标准在类上:@ ...

  10. 【实验一 】Spring Boot 集成 hibernate & JPA

    转眼间,2018年的十二分之一都快过完了,忙于各类事情,博客也都快一个月没更新了.今天我们继续来学习Springboot对象持久化. 首先JPA是Java持久化API,定义了一系列对象持久化的标准,而 ...

随机推荐

  1. [Data Structure] 二叉搜索树(Binary Search Tree) - 笔记

    1. 二叉搜索树,可以用作字典,或者优先队列. 2. 根节点 root 是树结构里面唯一一个其父节点为空的节点. 3. 二叉树搜索树的属性: 假设 x 是二叉搜索树的一个节点.如果 y 是 x 左子树 ...

  2. UVALive 4959 Jumping monkey

    题意就是: 一个猎人在森林里捕猎. 然后有只猴子,喜欢躲树的后边,猎人看不见它 然后给出了一张图,表示有哪些树是相邻的. 数据保证任意图中两个树都可以直接或间接的到达 猎人有一个枪,每次他可以选择一颗 ...

  3. javascript获取对应页面的代码

    window.onload = function () { function getUrls(url) {//核心代码是url2这行代码,通过.replace()方法将对应的字符串替换成其他方式 va ...

  4. Git常用命令清单

    创建 在指定目录创建工作仓库,未指定时在当前目录 git init [dir] 创建不包含工作区的仓库 git init --bare 克隆远程仓库到本地 git clone url 配置 git c ...

  5. android中网络操作使用总结(http)

    Android是作为智能手机的操作系统,我们开发的应用,大多数也都须要连接网络,通过网络发送数据.获取数据,因此作为一个应用开发人员必须熟悉怎么进行网络訪问与连接.通常android中进行网络连接通常 ...

  6. 【翻译】A (very) short introduction to R R的简短介绍

    [前言] 本文翻译自Paul Torfs & Claudia Brauer的文章A (very) short introduction to R.其中比较简单的地方没有翻译,不好用中文描述的地 ...

  7. ViewPage 大圣归来 原生示例

    VP简介 android-support-v4.jar 是谷歌官方给我们提供的一个兼容低版本安卓设备的软件包,里面包囊了只有在安卓3.0以上可以使用的api.而ViewPage就是其中之一,利用它,我 ...

  8. css基础回顾-定位:position

    w3school 对position定义和说明是: 定义和用法: position 属性规定元素的定位类型. 说明: 这个属性定义建立元素布局所用的定位机制.任何元素都可以定位,不过绝对或固定元素会生 ...

  9. ADSL拨号连接

    dotras是一个提供远程访问服务的组件,使用它可以方便的 进行宽带拨号连接 由于不同的系统中dotras调用的底层api可能不同,所以使用时要根据不同的系统使用不同的dotras. dotras目前 ...

  10. Android Design Support Library: 学习CoordinatorLayout

    简述 CoordinatorLayout字面意思是"协调器布局",它是Design Support Library中提供的一个超级帧布局,帮助我们实现Material Design ...