spring-data-jpa hibernate basic tutorial

Hibernate & JPA

1、JPA

    The full name is Java Persistence API, which describes the object-relational table mapping relationship through JDK 5.0 annotations or XML, and persists the entity objects at runtime to the database.

     There are two reasons for the emergence of JPA:
 First, to simplify the development of object persistence for existing Java EE and Java SE applications;
 second, Sun hopes to integrate ORM technology to achieve the unification of the persistence field.

     Technologies provided by JPA:

 1) ORM mapping metadata: JPA supports XML and JDK 5.0 annotations in two forms of metadata. The metadata describes the mapping relationship between objects and tables, and the framework persists entity objects to database tables accordingly;

 2) JPA API: used to manipulate entity objects, perform CRUD operations, the framework does everything for us in the background, and developers are freed from cumbersome JDBC and SQL codes.

 3) Query language: query data through an object-oriented rather than database-oriented query language to avoid tight coupling of program SQL statements.

 2. JPA & Hibernate relationship

    JPA needs Provider to realize its functions, and Hibernate is a strong one in JPA Provider. Functionally, JPA is now a subset of Hibernate functionality. It can be simply understood that JPA is the standard interface and Hibernate is the implementation. Hibernate is mainly implemented through three components, hibernate-annotation, hibernate-entitymanager and hibernate-core.

1) Hibernate-annotation is the basis for Hibernate to support annotation mode configuration, which includes standard JPA annotation and annotation of Hibernate's own special functions.

2) hibernate-core is the core implementation of Hibernate, providing all the core functions of Hibernate.

3) hibernate-entitymanager implements standard JPA, which can be regarded as an adapter between hibernate-core and JPA. It does not directly provide ORM functions, but encapsulates hibernate-core so that Hibernate conforms to the JPA specification .

    In general, JPA is the specification, Hibernate is the framework, JPA is the persistence specification, and Hibernate implements JPA.

3. Overview of JPA

1 Overview

The location of JPA in the application is shown in the following figure:

 

JPA maintains a Persistence Context (persistence context) in which the entity's life cycle is maintained. It mainly includes three aspects:

  1. ORM metadata. JPA supports two forms of annotation or xml to describe object-relational mapping.
  2. Entity manipulation API. Implement CRUD operations on entity objects.
  3. query language. The object-oriented query language JPQL (Java Persistence Query Language) is agreed.

 

The main APIs of JPA are defined in the javax.persistence package. If you're familiar with Hibernate, it's easy to map:

 

org.hibernate
javax.persistence
illustrate
cfg.Configuration Persistence Read configuration information
SessionFactory EntityManagerFactory Factory class for creating session/entity managers
Session EntityManager Provides entity manipulation API, manages transactions, and creates queries
Transaction EntityTransaction management affairs
Query Query execute query

2. Entity life cycle

Entity life cycle is a very important concept in JPA, which describes the state transition of entity objects from creation to control, from deletion to free. The operation of the entity is mainly to change the state of the entity.

The life cycle of an entity in JPA is as follows:

 

  1. New, a newly created entity object without a primary key (identity) value
  2. Managed, the object is in the Persistence Context (persistence context), managed by the EntityManager
  3. Detached,对象已经游离到Persistence Context之外,进入Application Domain
  4. Removed, 实体对象被删除

3、实体关系映射(ORM)

1)基本映射

 

对象端
数据库端
annotion
可选annotion
Class
Table
@Entity
@Table(name="table name")
property column @Column(name = "columnname")
property primary key @Id @GeneratedValue 详见ID生成策略
property NONE @Transient  

 

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.MERGE 级联更新
  • CascadeType.PERSIST 级联保存
  • CascadeType.REFRESH 级联刷新
  • CascadeType.REMOVE 级联删除
  • CascadeType.ALL 级联上述4种操作

4、事件及监听

 

通过在实体的方法上标注@PrePersist,@PostPersist等声明即可在事件发生时触发这些方法。

四、JPA应用

1、Dependencies

<dependencies>
  <dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-jpa</artifactId>
  </dependency>
<dependencies>

2、JPA提供的接口

主要来看看Spring Data JPA提供的接口,也是Spring Data JPA的核心概念:

1):Repository:最顶层的接口,是一个空的接口,目的是为了统一所有Repository的类型,且能让组件扫描的时候自动识别。
2):CrudRepository :是Repository的子接口,提供CRUD的功能
public interface CrudRepository<T, ID extends Serializable>extends Repository<T, ID> {
<S extends T> S save(S entity);
T findOne(ID primaryKey);      
Iterable<T> findAll();          
Long count();                   
void delete(T entity);          
 boolean exists(ID primaryKey);   
// … more functionality omitted
}
3):PagingAndSortingRepository:是CrudRepository的子接口,添加分页和排序的功能

public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {

 Iterable<T> findAll(Sort sort);

Page<T> findAll(Pageable pageable);

}

4):JpaRepository:是PagingAndSortingRepository的子接口,增加了一些实用的功能,比如:批量操作等。
5):JpaSpecificationExecutor:用来做负责查询的接口

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

}

6):Specification:是Spring Data JPA提供的一个查询规范,要做复杂的查询,只需围绕这个规范来设置查询条件即可

 3、查询语言

3.1 根据名称判别
Keyword
Sample
JPQL snippet

And

findByLastnameAndFirstname

… where x.lastname = ?1 and x.firstname = ?2

Or

findByLastnameOrFirstname

… where x.lastname = ?1 or x.firstname = ?2

Is,Equals

findByFirstname,findByFirstnameIs,findByFirstnameEquals

… where x.firstname = ?1

Between

findByStartDateBetween

… where x.startDate between ?1 and ?2

LessThan

findByAgeLessThan

… where x.age < ?1

LessThanEqual

findByAgeLessThanEqual

… where x.age ⇐ ?1

GreaterThan

findByAgeGreaterThan

… where x.age > ?1

GreaterThanEqual

findByAgeGreaterThanEqual

… where x.age >= ?1

After

findByStartDateAfter

… where x.startDate > ?1

Before

findByStartDateBefore

… where x.startDate < ?1

IsNull

findByAgeIsNull

… where x.age is null

IsNotNull,NotNull

findByAge(Is)NotNull

… where x.age not null

Like

findByFirstnameLike

… where x.firstname like ?1

NotLike

findByFirstnameNotLike

… where x.firstname not like ?1

StartingWith

findByFirstnameStartingWith

… where x.firstname like ?1(parameter bound with appended %)

EndingWith

findByFirstnameEndingWith

… where x.firstname like ?1(parameter bound with prepended %)

Containing

findByFirstnameContaining

… where x.firstname like ?1(parameter bound wrapped in%)

OrderBy

findByAgeOrderByLastnameDesc

… where x.age = ?1 order by x.lastname desc

Not

findByLastnameNot

… where x.lastname <> ?1

In

findByAgeIn(Collection<Age> ages)

… where x.age in ?1

NotIn

findByAgeNotIn(Collection<Age> age)

… where x.age not in ?1

True

findByActiveTrue()

… where x.active = true

False

findByActiveFalse()

… where x.active = false

IgnoreCase

findByFirstnameIgnoreCase

… where UPPER(x.firstame) = UPPER(?1)

 

3.2 @Query
public interface UserRepository extends JpaRepository<User, Long> {
 //Declare query at the query method using @Query
  @Query("select u from User u where u.emailAddress = ?1")
  User findByEmailAddress(String emailAddress);

 

//Advanced like-expressions in @Query
@Query("select u from User u where u.firstname like %?1")
  List<User> findByFirstnameEndsWith(String firstname);

 

//Declare a native query at the query method using @Query
@Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
  User findByEmailAddress(String emailAddress);

 

//Declare native count queries for pagination at the query method using @Query
@Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
//Declaring manipulating queries
@Modifying
@Query("update User u set u.firstname = ?1 where u.lastname = ?2")
int setFixedFirstnameFor(String firstname, String lastname);
}
3.3 复杂查询 JpaSpecificationExecutor

Criteria 查询:是一种类型安全和更面向对象的查询

这个接口基本是围绕着Specification接口来定义的, Specification接口中只定义了如下一个方法:

Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);

Criteria查询

基本对象的构建
1:通过EntityManager的getCriteriaBuilder或EntityManagerFactory的getCriteriaBuilder方法可以得到CriteriaBuilder对象
2:通过调用CriteriaBuilder的createQuery或createTupleQuery方法可以获得CriteriaQuery的实例
3:通过调用CriteriaQuery的from方法可以获得Root实例
过滤条件
1:过滤条件会被应用到SQL语句的FROM子句中。在criteria 查询中,查询条件通过Predicate或Expression实例应用到CriteriaQuery对象上。
2:这些条件使用 CriteriaQuery .where 方法应用到CriteriaQuery 对象上
3:CriteriaBuilder也作为Predicate实例的工厂,通过调用CriteriaBuilder 的条件方法( equal,notEqual, gt, ge,lt, le,between,like等)创建Predicate对象。
4:复合的Predicate 语句可以使用CriteriaBuilder的and, or andnot 方法构建

实例:

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;

    }

 }

}

 3.4 分页

上个实例的发杂查询已经带有分页,若实例的DAO接口有继承PagingAndSortingRepository接口,则可以直接调用

Page<ImTeacher> impeacher = imTeacherDao.findAll(new PageRequest(1,20));

3.5 联表查询
方法:
法一:直接用Query语句或者上节复杂的连接查询,查出两张或多张表的数据。
法二:映射,接下来将详细介绍。
1)ImStudent.java

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

 

四、总结

1、Hibernate的DAO层开发比较简单,对于刚接触ORM的人来说,能够简化开发工程,提高开发速度。

2、Hibernate对对象的维护和缓存做的很好,对增删改查的对象的维护要方便。

3、Hibernate数据库移植性比较好。

4、Hibernate功能强大,如果对其熟悉,对其进行一定的封装,那么项目的整个持久层代码会比较简单。

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326267571&siteId=291194637