spring Data JPA

ⅰ亾dé卋堺 提交于 2019-11-27 06:39:18

什么是JPA?

    全称Java Persistence API,可以通过注解或者XML描述【对象-关系表】之间的映射关系,并将实体对象持久化到数据库中。

为我们提供了:

    1)ORM映射元数据:JPA支持XML和注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中;

        如:@Entity、@Table、@Column、@Transient等注解。

    2)JPA 的API:用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。

        如:entityManager.merge(T t);

    3)JPQL查询语言:通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。

        如:from Student s where s.name = ?

    JPA仅仅是一种规范,也就是说JPA仅仅定义了一些接口,而接口是需要实现才能工作的。所以底层需要某种实现,而Hibernate就是实现了JPA接口的ORM框架。

    也就是说:

        JPA是一套ORM规范,Hibernate实现了JPA规范:

什么是spring data jpa?

    spirng data jpa是spring提供的一套简化JPA开发的框架,按照约定好的【方法命名规则】写dao层接口,就可以在不写接口实现的情况下,实现对数据库的访问和操作。同时提供了很多除了CRUD之外的功能,如分页、排序、复杂查询等等。

    Spring Data JPA 可以理解为 JPA 规范的再次封装抽象,底层还是使用了 Hibernate 的 JPA 技术实现。如图:

接口约定命名规则:

CrudRepository接口:提供了最基本的对实体类的添删改查操作 

T save(T entity);//存放单个实体 
Iterable<T> save(Iterable<? extends T> entities);//保存集合        
T findOne(ID id);//根据id查找实体         
boolean exists(ID id);//根据id判断实体是否存在         
Iterable<T> findAll();//查询所有实体,不用或慎用!         
long count();//查询实体数量         
void delete(ID id);//根据Id删除实体         
void delete(T entity);//删除一个实体 
void delete(Iterable<? extends T> entities);//删除一个实体的集合         
void deleteAll();//删除所有实体

PagingAndSortingRepository接口:提供了分页与排序的功能:

Iterable<T> findAll(Sort sort); //排序 
Page<T> findAll(Pageable pageable); //分页查询(含排序功能) 

JpaRepository接口:提供了JPA的相关功能: 

List<T> findAll(); //查找所有实体 
List<T> findAll(Sort sort); //排序、查找所有实体 
List<T> save(Iterable<? extends T> entities);//保存集合 
void flush();//执行缓存与数据库同步 
T saveAndFlush(T entity);//强制执行持久化 
void deleteInBatch(Iterable<T> entities);//删除一个实体集合 

 

springBoot使用实例

1.pom添加依赖:

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

 2.实体类User添加注解:

package com.example.domain;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQuery;

@Entity
//@NamedQuery:在Repository接口定义的findByName方法不使用默认的查询实现,而是使用自定义查询语句去查询
//不标注,则使用默认实现
@NamedQuery(name = "User.findByName", query = "select name,address from User u where u.name=?1")
public class User implements Serializable{
    private static final long serialVersionUID = 1L;
    //主键
    @Id
    long id;
    //对应数据库字段的列名
    @Column(name = "name")
    String name;

    @Column(name = "address")
    String address;

    public long getId(){
        return id;
    }

    public void setId(long id){
        this.id = id;
    }

    public String getName(){
        return name;
    }

    public void setName(String name){
        this.name = name;
    }

    public String getAddress(){
        return address;
    }

    public void setAddress(String address){
        this.address = address;
    }

}

3.编写Repository接口(dao层)

package com.example.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import com.example.domain.User;

public interface UserJpaRepository extends JpaRepository<User,Long> {
}

    这里的UserJpaRepository接口实现了JpaRepository接口。JpaRepository实现了PagingAndSortingRepository接口,PagingAndSortingRepository接口实现了CrudRepository接口,CrudRepository接口实现了Repository接口。

        Repository接口是一个标识接口,里面是空的;

        CrudRepository接口定义了增删改查方法;

        PagingAndSortingRepository接口用于分页和排序;

    由于JpaRepository接口继承了以上所有接口,所以拥有它们声明的所有方法;

    但是使用过程中还是需要注意:以findAll方法为例,JpaRepository接口返回的是List,而PagingAndSortingRepository和CrudRepository返回的是迭代器;

    UserRepository:

package com.example.repository;

import java.util.List;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.query.Param;

import com.example.domain.User;

public interface UserRepository extends Repository<User, Long>{

    List<User> findByNameAndAddress(String name, String address);

    @Query(value = "from User u where u.name=:name")
    List<User> findByName1(@Param("name") String name);

    @Query(value = "select * from #{#entityName} u where u.name=?1", nativeQuery = true)
    List<User> findByName2(String name);

    List<User> findByName(String name);
}

    UserRepository接口主要定义了一些查询方法;

    findByNameAndAddress方法:无需额外定义其查询语句就能直接执行。因为Spring Data Jpa会根据实体类的属性名字以及方法名自动实现该方法;

    findByName方法:由于实体类中声明了@NamedQuery注解,则使用@NamedQuery注解标注的查询语句去查询;

    @Query用来配置自定义SQL的注解。参数nativeQuery = true表明使用原生sql,如果不配置,默认是false,则使用HQL查询。

    findByName1方法:使用了HQL语句查询;

    findByName2方法:使用了原始的sql语句查询。

4.配置数据库配置:

    application.properties:

spring.jpa.show-sql = true
logging.level.org.springframework.data=DEBUG
spring.jpa.hibernate.ddl-auto=

spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

5.controller、service编写和普通项目一样

 

@Query配合@Modifying使用:

    @Query注解单独使用:只能用来查询的;配合@Modifying注解一起使用,则可以完成数据的删除、添加、更新操作。

    需要注意,此处还需要使用事务注解进行事务管理,否则会抛出TranscationRequiredException异常

    即加上@Transactional注解即可。

分页查询

    UserRepository:

Page<Person> findByNameAndPassword(String name ,String password,Pageable pageable);

    service层:

Page<Person> p1 = personRepository.findByNameAndPassword("张三","123", new PageRequest(1,10,new Sort("id")));

List<Person> list=p1.getContent();

数据排序

    UserRepository:

List<Person> findByNameAndPassword(String name ,String password,Sort sort);

    service层:

List<Person> p1 = personRepository.findByNameAndPassword("张三","123",new Sort(Sort.Direction.ASC,"id"));//根据Id升序排序

总结:

    SpringDataJPASpring Data的一个子项目,通过提供基于JPARepository极大的减少了JPA作为数据访问方案的代码量,仅需要编写一个接口集成下SpringDataJPA内部定义的接口,即可完成简单的CRUD操作。

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!