近年来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元数据的领域对象就叫做实体。它应具备一下条件: 实体的状态 实体共有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方法 }
@Entity:将领域对象标注为一个实体类,表示该类需要持久化到数据库中,默认情况下类名即表名,通过name属性显式指定表名,如:name=”T_TEST”表示将Test保存到表T_TEST表中。 @Id:对应的属性是表的主键 @GeneratedValue:主键的产生策略,通过strategy属性进行指定,默认情况下,JPA自动选择一个最适合底层数据库的主键生成策略,如SqlServer对应的identity:
@Colunm(name=”uname”):属性对应的表字段。我们并不需要指定表字段的类型,因为JPA 会根据反射从实体属性中获取类型;如果是字符串类型,我们可以指定字段长度,以便可以自动生成DDL语句。 @Temporal(TemporalType.DATE):如果属性是时间类型,因为数据表对时间类型有更严格的划分,所以必须指定具体时间类型,在java.persistence.TemporalType枚举中定义了三种时间类型:
SINGLE_TABLE:父子类都保存在同一个表中,通过字段值进行区分。 JOINED:父子类相同的部分保存在同一个表中,不同的部门分开存放,通过连接不同的表获取完整数据。 TABLE_PER_CLASS:每一个类对应自己的表,一般不推荐采用这种方式。
下面我们来看看实际的列子是怎么运用的。 @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{ ….. }
@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; }
<?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实例 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); |
|
来自: wjw_595 > 《Hibernate》