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方法;
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", [email protected](referencedColumnName="id",name="TEA_ID"), [email protected](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",[email protected](name="REG_CITY")), @AttributeOverride(name="provice",[email protected](name="REG_PROVICE")), @AttributeOverride(name="street",[email protected](name="REG_STREET")) }) private Address regAddress; //省略get/set }
继承关系:
1,默认情况下,JPA使用ONE TABLE的方式来自动完成继承的映射
1),只需要在整个继承体系的根对象上面添加@Entity和主键映射;
2),其他所有的子类只需要加上@Entity标签就可以了;
3),会创建一个鉴别器列,DTYPE,使用类名作为鉴别器的值;
4),如果要自定义鉴别器列,在根类型上加上@DiscrimnatorColumn
5),如果自定义了鉴别器列,根类型及所有子类必须添加@DiscriminatorValue
2,使用PER TABLE的方式:
1),在父类(根类)上使用@Inheritance标签,使用TABLE_PER_CLASS的继承策略;
2),id的生成策略不能是AUTO或者IDENTITY;
3),子类只需要添加@Entity,如果要修改子类的表名,@Table;
查询:
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:清除所有二级缓存对象
原文地址:https://www.cnblogs.com/Java0120/p/9906003.html