转 http://www.cnblogs.com/jiangxiaoyaoblog/p/5635152.html
html
1)若是想用hibernate注解,是否是必定会用到jpa的?java
是。若是hibernate认为jpa的注解够用,就直接用。不然会弄一个本身的出来做为补充。程序员
2)jpa和hibernate都提供了Entity,咱们应该用哪一个,仍是说能够两个一块儿用?算法
Hibernate的Entity是继承了jpa的,因此若是以为jpa的不够用,直接使用hibernate的便可spring
正文:数据库
Hibernate对数据库结构提供了较为完整的封装,Hibernate的O/R Mapping实现了POJO 和数据库表之间的映射,以及SQL 的自动生成和执行。程序员每每只需定义好了POJO 到数据库表的映射关系,便可经过Hibernate 提供的方法完成持久层操做。程序员甚至不须要对SQL 的熟练掌握, Hibernate/OJB 会根据制定的存储逻辑,自动生成对应的SQL 并调用JDBC 接口加以执行。express
iBATIS 的着力点,则在于POJO 与SQL之间的映射关系。而后经过映射配置文件,将SQL所需的参数,以及返回的结果字段映射到指定POJO。 相对Hibernate“O/R”而言,iBATIS 是一种“Sql Mapping”的ORM实现编程
Hibernate的真正掌握要比Mybatis来得难些。Mybatis框架相对简单很容易上手,但也相对简陋些。我的以为要用好Mybatis仍是首先要先理解好Hibernate。针对高级查询,Mybatis须要手动编写SQL语句,以及ResultMap。而Hibernate有良好的映射机制,开发者无需关心SQL的生成与结果映射,能够更专一于业务流程api
Hibernate调优方案:缓存
Mybatis调优方案:
MyBatis在Session方面和Hibernate的Session生命周期是一致的,一样须要合理的Session管理机制。MyBatis一样具备二级缓存机制。 MyBatis能够进行详细的SQL优化设计。
Hibernate的查询会将表中的全部字段查询出来,这一点会有性能消耗。Hibernate也能够本身写SQL来指定须要查询的字段,但这样就破坏了Hibernate开发的简洁性。而Mybatis的SQL是手动编写的,因此能够按需求指定查询的字段。
Hibernate HQL语句的调优须要将SQL打印出来,而Hibernate的SQL被不少人嫌弃由于太丑了。MyBatis的SQL是本身手动写的因此调整方便。但Hibernate具备本身的日志统计。Mybatis自己不带日志统计,使用Log4j进行日志记录。
Hibernate缓存:
Hibernate一级缓存是Session缓存,利用好一级缓存就须要对Session的生命周期进行管理好。建议在一个Action操做中使用一个Session。一级缓存须要对Session进行严格管理。Hibernate二级缓存是SessionFactory级的缓存。 SessionFactory的缓存分为内置缓存和外置缓存。内置缓存中存放的是SessionFactory对象的一些集合属性包含的数据(映射元素据及预约SQL语句等),对于应用程序来讲,它是只读的。外置缓存中存放的是数据库数据的副本,其做用和一级缓存相似.二级缓存除了之内存做为存储介质外,还能够选用硬盘等外部存储设备。二级缓存称为进程级缓存或SessionFactory级缓存,它能够被全部session共享,它的生命周期伴随着SessionFactory的生命周期存在和消亡。
Mybatis缓存:
MyBatis 包含一个很是强大的查询缓存特性,它能够很是方便地配置和定制。MyBatis 3 中的缓存实现的不少改进都已经实现了,使得它更增强大并且易于配置。
默认状况下是没有开启缓存的,除了局部的 session 缓存,能够加强变现并且处理循环 依赖也是必须的。要开启二级缓存,你须要在你的 SQL 映射文件中添加一行: <cache/>
字面上看就是这样。这个简单语句的效果以下:
全部的这些属性均可以经过缓存元素的属性来修改。
Mybatis:小巧、方便、高效、简单、直接、半自动
Hibernate:强大、方便、高效、复杂、绕弯子、全自动
全称Java Persistence API,经过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
JPA的出现有两个缘由:
其一,简化现有Java EE和Java SE应用的对象持久化的开发工做;
其二,Sun但愿整合对ORM技术,实现持久化领域的统一。
JPA提供的技术:
1)ORM映射元数据:JPA支持XML和JDK 5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中;
2)JPA 的API:用来操做实体对象,执行CRUD操做,框架在后台替咱们完成全部的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。
3)查询语言:经过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。
JPA是须要Provider来实现其功能的,Hibernate就是JPA Provider中很强的一个。从功能上来讲,JPA如今就是Hibernate功能的一个子集。能够简单的理解为JPA是标准接口,Hibernate是实现。Hibernate主要是经过三个组件来实现的,及hibernate-annotation、hibernate-entitymanager 和hibernate-core。
1)hibernate-annotation是Hibernate支持annotation方式配置的基础,它包括了标准的JPA annotation以及 Hibernate自身特殊功能的annotation。
2)hibernate-core是Hibernate的核心实现,提供了Hibernate全部的核心功能。
3)hibernate-entitymanager实现了标准的JPA,能够把它当作hibernate-core和JPA之间的适配器,它并不直接提供ORM的功能,而是对hibernate-core进行封装,使得Hibernate符合JPA的规范。
总的来讲,JPA是规范,Hibernate是框架,JPA是持久化规范,而Hibernate实现了JPA。
JPA在应用中的位置以下图所示:
JPA维护一个Persistence Context(持久化上下文),在持久化上下文中维护实体的生命周期。主要包含三个方面的内容:
查询语言。约定了面向对象的查询语言JPQL(Java Persistence Query Language。
org.hibernate
|
javax.persistence
|
说明
|
---|---|---|
cfg.Configuration | Persistence | 读取配置信息 |
SessionFactory | EntityManagerFactory | 用于建立会话/实体管理器的工厂类 |
Session | EntityManager | 提供实体操做API,管理事务,建立查询 |
Transaction | EntityTransaction | 管理事务 |
Query | Query | 执行查询 |
实体生命周期是JPA中很是重要的概念,描述了实体对象从建立到受控、从删除到游离的状态变换。对实体的操做主要就是改变实体的状态。
JPA中实体的生命周期以下图:
Removed, 实体对象被删除
1)基本映射
Class | Table | @Entity | @Table(name="tablename") |
property | column | – | @Column(name = "columnname") |
property | primary key | @Id | @GeneratedValue 详见ID生成策略 |
property | NONE | @Transient | |
对象端
|
数据库端
|
annotion
|
可选annotion
|
---|
2)映射关系
JPA定义了one-to-one、one-to-many、many-to-one、many-to-many 4种关系。
对于数据库来讲,一般在一个表中记录对另外一个表的外键关联;对应到实体对象,持有关联数据的一方称为owning-side,另外一方称为inverse-side。
为了编程的方便,咱们常常会但愿在inverse-side也能引用到owning-side的对象,此时就构建了双向关联关系。 在双向关联中,须要在inverse-side定义mappedBy属性,以指明在owning-side是哪个属性持有的关联数据。
对关联关系映射的要点以下:
关系类型
|
Owning-Side
|
Inverse-Side
|
---|---|---|
one-to-one | @OneToOne | @OneToOne(mappedBy="othersideName") |
one-to-many / many-to-one | @ManyToOne | @OneToMany(mappedBy="xxx") |
many-to-many | @ManyToMany | @ManyToMany(mappedBy ="xxx") |
其中 many-to-many关系的owning-side可使用@JoinTable声明自定义关联表,好比Book和Author之间的关联表:
@JoinTable(name = "BOOKAUTHOR", joinColumns = { @JoinColumn(name = "BOOKID", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "AUTHORID", referencedColumnName = "id") })
关联关系还能够定制延迟加载和级联操做的行为(owning-side和inverse-side能够分别设置):
经过设置fetch=FetchType.LAZY 或 fetch=FetchType.EAGER来决定关联对象是延迟加载或当即加载。
经过设置cascade={options}能够设置级联操做的行为,其中options能够是如下组合:
CascadeType.ALL 级联上述4种操做
经过在实体的方法上标注@PrePersist,@PostPersist等声明便可在事件发生时触发这些方法。
主要来看看Spring Data JPA提供的接口,也是Spring Data JPA的核心概念:
public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);
}
public interface JpaSpecificationExecutor<T>{
T findOne(Specification<T> spec);
List<T> findAll(Specification<T> spec);
Page<T> findAll(Specification<T> spec, Pageable pageable);
List<T> findAll(Specification<T> spec, Sort sort);
long count(Specification<T> spec);
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Keyword
|
Sample
|
JPQL snippet
|
---|
Criteria 查询:是一种类型安全和更面向对象的查询
这个接口基本是围绕着Specification接口来定义的, Specification接口中只定义了以下一个方法:
Criteria查询
实例:
ImTeacher.java
@Entity
@Table(name = "im_teacher")
public class ImTeacher implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
@Column(name = "id")
private int id;
@Column(name = "teacher_id")
private int teacherId;
@Column(name = "name")
private String name = "";
@Column(name = "age")
private int age;
@Column(name = "sex")
private String sex = "";
...
}
ImTeacherDao.java
public interface ImTeacherDao extends PagingAndSortingRepository<ImTeacher, Integer>,JpaSpecificationExecutor{
...
}
@Service
public class ImTeacherDaoService {
@Autowired
ImTeacherDao imTeacherDao;
/**
* 复杂查询测试
* @param page
*/
public Page<ImTeacher> findBySepc(int page, int size){
PageRequest pageReq = this.buildPageRequest(page, size);
Page<ImTeacher> imTeachers = this.imTeacherDao.findAll(new MySpec(), pageReq);
return imTeachers;
}
/**
* 创建分页排序请求
*/
private PageRequest buildPageRequest(int page, int size) {
Sort sort = new Sort(Direction.DESC,"age");
return new PageRequest(page,size, sort);
}
private class MySpec implements Specification<ImTeacher>{
@Override
public Predicate toPredicate(Root<ImTeacher> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//1.混合条件查询
Path<String> exp1 = root.get("name");
Path<String> exp2 = root.get("age");
query.where(cb.like(exp1, "%王%"),cb.equal(exp2, "45"));
//2.多表查询
/*Join<ImTeacher,ImStudent> join = root.join("imStudent", JoinType.INNER);
Path<String> exp3 = join.get("name");
return cb.like(exp3, "%jy%");*/
return null;
}
}
}
上个实例的发杂查询已经带有分页,若实例的DAO接口有继承PagingAndSortingRepository接口,则能够直接调用
Page<ImTeacher> impeacher = imTeacherDao.findAll(new PageRequest(1,20));
@Entity
@Table(name = "im_student")
public class ImStudent {
@Id
@GeneratedValue
@Column(name = "id")
private int id;
@Column(name = "student_id")
private int studentId;
@Column(name = "name")
private String name = "";
@Column(name = "age")
private int age;
@Column(name = "sex")
private String sex = "";
@Column(name = "teacher_id")
private int teacherId;
@ManyToOne(cascade={CascadeType.MERGE,CascadeType.REFRESH})
@JoinColumn(name="teacher_id", referencedColumnName="id", insertable=false, updatable=false)
private ImTeacher imTeacher;
...
}
2)在ImTeacher.java中添加
@OneToMany(mappedBy="imTeacher",cascade=CascadeType.ALL,fetch=FetchType.LAZY)
private Set<ImStudent> imStudent = new HashSet<ImStudent>();
...
3)根据学生名字查出其老师信息
@Query("SELECT teacher FROM ImTeacher teacher JOIN teacher.imStudent student WHERE student.name=:name")
ImTeacher findByStuName(@Param("name") String name);
根据老师名字查出其学生列表
@Query("SELECT student FROM ImStudent student JOIN student.imTeacher teacher WHERE teacher.name = :name")
Set<ImStudent> findByStudByTeaName(@Param("name") String name);
4、总结
一、Hibernate的DAO层开发比较简单,对于刚接触ORM的人来讲,可以简化开发工程,提升开发速度。
二、Hibernate对对象的维护和缓存作的很好,对增删改查的对象的维护要方便。
三、Hibernate数据库移植性比较好。
四、Hibernate功能强大,若是对其熟悉,对其进行必定的封装,那么项目的整个持久层代码会比较简单。