JPA(Hibernate)

JPA

1,JPA:Java Persistence API.JPA通过JDK 5.0注解-关系表的映射关系,并将运行期的实体对象持久化到数据库中。JPA是JavaEE中的标准。JPA标准只提供了一套规范,需要有JPA的具体实现,Hibernate实现了JPA2.0标准,所以我们在用JPA的时候,其实用的是Hibernate提供了JPA2.0规范的实现;JPA还有其他实现,比如OpenJPA,各个JPA的实现在使用细节上有一些不同,使用时需要注意;
2,JPA和Hibernate对比:
  1),JPA只是Hibernate的一个子集(支持JPA只是Hibernate中的一个功能),
  2),Hibernate在对象状态,对象映射,对象关系,查询语句上和JPA80%以上都雷同;
  3),Hibernate本身更依赖XML配置,而JPA完全使用Annotation实现;
  4),Hibernate的API和JPA的API有一些区别(关键对象,对象方法);

JPA环境搭建:
1,JPA配置:
persistence.xml文件,放于classpath下META-INF/persistence.xml;
<properties>
hibernate.dialect:方言;
hibernate.show_sql:
hibernate.hbm2ddl.auto:
数据连接配置不能使用hibernate的哈;
  javax.persistence.jdbc.driver:JPA规范的数据库驱动;
  javax.persistence.jdbc.url:JPA规范的URL;
  javax.persistence.jdbc.user:JPA规范的用户名;
  javax.persistence.jdbc.password:JPA规范的密码;
  javax.persistence.validation.mode:设置为auto,避免domain的检查;
2,创建Employee对象,并添加注解
  1),@Entity:标在类上,标明当前实体类是需要JPA管理的一个实体对象,类似<class>
  2),@Table:标在类上,标明当前实体类在数据库中对应的表,类似<class>元素的table属性 ;
3,配置属性,(默认情况下,JPA会管理所有的属性;要规范属性,可以在字段上,也可以在getter方法)
  1),@Id:标明当前属性是OID,类似<id>
  2),@GeneratedValue:标明当前OID使用的主键生成方式,类似<generator>
  3),@Column:标明当前属性对应的列,类似<property>的column属性;
  4),@Temporal:标明当前属性的日期类型;

API使用
一,JPA框架的启动:
创建EntityManagerUtil;
  1),使用Persistence.createEntityManagerFactory("com._520it.jpa")创建EntityManagerFactory;
  (按照persistence.xml中的persistence-unit的name属性加载的)
  2),EntityManagerFactory类似SessionFactory,通过createEntityManager方法创建EntityManager;
  3),EntityManager类似Session,实体类的持久化方法由EntityManager提供
2,完成CRUD;
  1,getTransaction:得到事务对象,并调用begin方法开启事务;

  2,persist:持久化对象;

  3,find:得到对象,相当于get方法;

  4,merge:修改对象,相当于update方法;

  5,createQuery:创建一个Query对象;

  6,调用Query对象的getResultList方法执行查询;

  7,remove:删除一个对象,相当于delete方法;(注意,JPA中只能把持久化对象变为删除状态)

1,配置文件:

  1),JPA的配置文件默认从META-INF/persistence.xml加载;
  hibernate(classpath:hibernate.cfg.xml)
  2),JPA配置文件中,可以配置hibernate的相关配置项(只针对HIBERNATE的JPA实现);

  注意,有些配置只能使用javax.xxx
  3),JPA配置文件中,默认查询classpath下所有实体类,如果需要引入外部的类,才需要配置;

hibernate:要让hibernate管理的实体类,必须把映射文件配置在hibernate.cfg.xml的mapping中;
2,实体对象:

  1),JPA也是ORM框架,不同的是使用注解来完成映射;
  2),JPA中,O直接体现在对象中,所以一般情况下,在注解中一般不写配置或者只配置R部分;
  3),JPA中,最大的好处是不需要给所有属性配置,按需配置;
3,API代码:

  1),JPA的启动方式几乎和Hibernate相同,包括类结构基本一致;
  Persistence --- Configuration;
  EntityManagerFactory --- SessionFactory;
  EntityManager ---- Session

  2),EntityManager上的API和Session基本一致;
  使用entityManager.getDelegate()查看EntityManager的真实实现SessionImpl;
  EntityManager的的委托类其实就是SessionImpl,所以,Hibernate其实就是使用Session来实现了JPA的EntityManager;

单对象映射细节:
persistence.xml:
  1,class:引入需要扫描的类,
  2,exclude-unlisted-classes:是否只扫描配置的类;
  3,jar-file:引入需要扫描的jar包;

		<!-- 手动告诉JPA需要管理那些类 -->
<class>com.rk1632._12_second_level_cache.Employee</class>
<!-- exclude-unlisted-classes设置为false,JPA便只会管理class标签引入的实体类 -->
<exclude-unlisted-classes>false</exclude-unlisted-classes>

对象:
  4,@Entity和@Table;entity的name属性可以为对象起别名;table的name为对象指定表名;
  5,默认情况下,根据@Id标签的位置确定access的方式;可以通过@Access来改变access方式(field);
  6,@Column标签;name属性;
  7,@Temporal标签;设置日期格式;
  8,@Transient标签;设置一个字段不需要持久化;
  9,@Lob标签:设置text类型;相当于hibernate <property type="text">

主键映射细节:

使用JPA内置的主键生成策略:

  1,@GeneratedValue(strategy=GenerationType.AUTO);---- native
  2,@GeneratedValue(strategy=GenerationType.IDENTITY); ------identity
  3,@GeneratedValue(strategy=GenerationType.SEQUENCE); ------sequence
  4,@GeneratedValue(strategy=GenerationType.TABLE);---- TableGenerator
  5,   @Id --- assigned

JPA--HIBERNATE

核心对象对比
  1,EntityManagerFactory: 类似SessionFactory,线程安全,主要用于产生EntityManager,对于一个应用+数据库,一个实例就够了
  2,EntityManager:类似Session,在Hibernate中就是Session的包装类,使用方式和Session相同;线程不安全;
  3,Query/TypedQuery:类似Query对象,部分API有区别;
  4,EntityTransaction:类似Tansaction对象,API相同;

EntityManager方法对比:

session ---> jpa

save; ---> persist:persist方法必须运行在事务中;

update; ---> merge:merge方法必须运行在事务中;

saveOrUpdate ---> erge方法可以把临时对象或者游离对象都变成持久化对象;

delete ---> remove:remove方法必须运行在事务中;

get ---> find:find返回对象类型不是Object;

load ---> getReference:使用延迟加载;

getTransaction; ---> getTranscation:得到的对象是EntityTransaction;

createQuery; ---> createQuery:javax.xxx.Query;TypedQuery

clear ---> clear;

evict ---> detach:把一个指定的持久化对象变成游离对象;

close ---> close;

单向的many2one:

	//<many2one name="dept" column="dept_id">
//EAGER:迫切的 LAZY:懒,此处fetch设置延迟加载或者不延迟加载
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="DEPT_ID")
private Department dept;

1,Employee
2,@JoinColumn相当于在many-to-one元素中的column;
3,默认情况下,得many方,JPA会直接使用LEFT JOIN 把one方查询出来;相当于没有延迟加载;
4,@ManyToOne(fetch=FetchType.LAZY)
   @Fetch(FetchMode.SELECT)
  1),manytoone标签上的fetch属性代表是否延迟加载,默认是FetchType.EAGER;如果使用延迟加载,FetchType.LAZY;
  2),fetch标签代表怎么去拿关联的对象,默认情况使用left join直接把many方对应的one方拿到,也可以设置为select,使用两条SQL分别加载many和one;

单向的one2many:
1,JPA中,one2many是使用三张表完成的;
2,从one方拿many,使用延迟加载,仍然使用的PersistenceSet,所以,还是只能使用接口;
3,只能使用集合的size方法来判断是否有many方和one方关联;
4,在关闭EntityManager之前实例化集合;

集合:
1,JPA能够自动根据集合的类型来完成集合的映射;
2,如果集合是Set相当于默认使用<set>来映射;
3,如果集合是List相当于默认使用<bag>来映射;
4,可以使用@OrderBy标签来排序(让JPA按照集合中的类型的某个属性排序)

双向的many2one和one2many;

	//1,one方放弃去维护和many方的关系;---->inverse=true
//2,one方查询many方的表结构按照many方对应的属性配置查询(one方放弃中间表结构)
@OneToMany(mappedBy="dept")
private Set<Employee> es = new HashSet<>();

1,在many方直接使用@ManyToOne标签;
2,在one方,使用@OneToMany(mappedBy="")
  1),mappedBy代表one方放弃对many方关系的维护;
  2),one方放弃自己的中间表结构,使用many方对应的属性的表结构;
3,双向的many2one,one2many就和hibernate中的是一样的了;

JPA级联:

MERGE:
REMOVE:
all:额外的包含了DETACH和PERSIST
在hibernate中的delete-orphan变成了@OneToMany的一个属性:orphanRemoval=true;

DETACH:代表,在主对象上面调用detach方法(把持久化对象变成游离对象,相当于evict),级联的对所有子对象调用detach方法;
PERSIST:代表,在主对象上面调用persist方法,级联的对所有子对象调用persist方法;

JPA(Hibernate)

many2many:

@Entity
public class Teacher { @Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name; @ManyToMany
private Set<Student> students = new HashSet<>();
//省略get/set ...
} @Entity
public class Student { @Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name; @ManyToMany(mappedBy="students")
private Set<Teacher> teachers = new HashSet<>();
//省略get/set ...
}

自定义中间表

	@ManyToMany
//类似于<set table="">
//name表示中间表的名称
//joinColumns代表在中间表里面对应自己主键的外键列
// name:中间列的外键列的名称
// referencedColumnName:参照自己的哪个列(主键列),可以不写
//inverseJoinColumns代表在中间表里面对应对方主键的外键列
// name:中间列的外键列的名称
// referencedColumnName:参照对方的哪个列(主键列),可以不写
@JoinTable(name="TEA_STU",
joinColumns=@JoinColumn(referencedColumnName="id",name="TEA_ID"),
inverseJoinColumns=@JoinColumn(referencedColumnName="id",name="STU_ID"))
private Set<Student> students = new HashSet<>();

  

组件关系:

//组合对象
//可嵌入对象,代表这个对象不是一个实体对象,是一个需要嵌入到宿主对象中才有意义的对象
@Embeddable
public class Address { private String provice;
private String city;
private String street;
//省略get/set
} //宿主对象
@Entity
public class Company { @Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name; private Address address; //多个相同类型的嵌入对象,需要重写属性列名
@AttributeOverrides({
@AttributeOverride(name="city",column=@Column(name="REG_CITY")),
@AttributeOverride(name="provice",column=@Column(name="REG_PROVICE")),
@AttributeOverride(name="street",column=@Column(name="REG_STREET"))
})
private Address regAddress;
//省略get/set
}

  

继承关系:
1,默认情况下,JPA使用ONE TABLE的方式来自动完成继承的映射
  1),只需要在整个继承体系的根对象上面添加@Entity和主键映射;
  2),其他所有的子类只需要加上@Entity标签就可以了;
  3),会创建一个鉴别器列,DTYPE,使用类名作为鉴别器的值;
  4),如果要自定义鉴别器列,在根类型上加上@DiscrimnatorColumn
  5),如果自定义了鉴别器列,根类型及所有子类必须添加@DiscriminatorValue

JPA(Hibernate)

2,使用PER TABLE的方式:
  1),在父类(根类)上使用@Inheritance标签,使用TABLE_PER_CLASS的继承策略;
  2),id的生成策略不能是AUTO或者IDENTITY;
  3),子类只需要添加@Entity,如果要修改子类的表名,@Table;

JPA(Hibernate)

查询:
1,TypedQuery和Query的区别;TypedQuery主要用于查询一个实体对象,不能使用投影查询;
2,分页:同样使用setFristResult和setMaxResult两个方法;
3,注意,如果使用JPA的查询,使用位置参数,参数的索引是从[1]开始的 (hibernate从[0]开始的)
4,查询总条数之类的只有一条结果的,可以使用getSingleResult方法;
5,如果要使用原生的SQL,直接使用createNativeQuery()

		//如果只查询一种实体对象,建议使用TyedQuery
TypedQuery query = em.createQuery("select e from Employee e where name like ?", Employee.class);
//分页的两个方法和Hibernate的query相同
//List<Employee> list = query.setFirstResult(5).setMaxResults(5).getResultList();
//System.out.println(list); //如果确定结果集只有一行,使用getSingleResult==Hibernate中的uniqueResult
//query.getSingleResult(); //JPA中,查询参数的顺序从1开始
//List<Employee> list = query.setParameter(1, "%松鼠%").getResultList(); List<Object[]> objs = em.createNativeQuery("select * from Employee", Employee.class).getResultList();
System.out.println(objs);

  

JPA中的锁;

1,悲观锁;
select for update可以阻止:除了SELECT之外的其他SQL(FOR UPDATE,DML,LOCK IN SHARE MODE);
select lock in share mode可以阻止:DML和FOR UPDATE,LOCK IN SHARE MODE;

在JPA中使用悲观锁,
em.find(Class,id,LockModeType),
LockModeType一般有两种方式:
  1,PESSIMISTIC_READ:LOCK IN SHARE MODE:会通过造成死锁来阻止并发事务执行;
  2,PESSIMISTIC_WRITE:SELECT FOR UPDATE:会延迟另一个事务的执行;(一般使用这种)

在JPA中使用乐观锁.
在对象中添加一个version属性,在上面添加@Version标签就可以了

二级缓存的配置:
1,拷贝二级缓存的jar包;
2,拷贝二级缓存的hibernate的配置文件,

			<!-- 告诉hibernate使用哪个缓存框架作为二级缓存框架 -->
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>
<!-- 设置二级缓存前缀 -->
<property name="hibernate.cache.region_prefix" value="hibernate"/>

3,拷贝ehcache的配置文件(classpath);
4,在需要二级缓存的对象上面加上标签;
  1),Cacheable标签是JPA提供的;
  2),Cache标签,是hibernate提供的,提供了更多的二级缓存控制相关的配置;

@Entity
//Cacheable标签表示需要二级缓存的实体类
@Cacheable
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE,region="hibernate.EMPLOYEE")
public class Employee {
//省略
}

  

二级缓存的操作:
1,在JPA中,二级缓存是放在EntityManagerFactory上的;
2,entityManagerFactory.getCache()方法得到二级缓存对象;
3,evict(Class):清除指定类型所有数据;
   evict(Class,Object id):清除指定对象;
   evictALL:清除所有二级缓存对象

上一篇:C# 异步委托(AP、APM)


下一篇:sencha touch 入门系列 扩展篇之sencha touch 项目打包压缩