SpringDataJpa使用详解

首先介绍必要配置及规范,再讲解具体使用

 

pom.xml配置:

 

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

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

 

application.properties配置:

 

########################################################
### Spring datasource -- Datasource configuration.
########################################################
spring.datasource.url = jdbc:mysql://localhost:3306/test1?characterEncoding=UTF-8
spring.datasource.username = root
spring.datasource.password = 123456
spring.datasource.driverClassName = com.mysql.cj.jdbc.Driver

########################################################
### Java Persistence Api --  Spring jpa configuration.
########################################################
# Specify the DBMS
spring.jpa.database = MYSQL
# Show or not log for each sql query
spring.jpa.show-sql = true
# Hibernate ddl auto (create, create-drop, update, validate, none)
spring.jpa.hibernate.ddl-auto = update
# Naming strategy
#[org.hibernate.cfg.ImprovedNamingStrategy  #org.hibernate.cfg.DefaultNamingStrategy]
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
# stripped before adding them to the entity manager)
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

 

启动类:

 

@SpringBootApplication
@ComponentScan("com.jpa")//开启spring注解扫描
@EnableJpaRepositories(basePackages = {"com.jpa.repository"})//扫描JPA资源库
@EntityScan(basePackages = {"com.jpa.entity"})//扫描实体类
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

 

实体类:

 

@Data//编译时生成get/set、toString等方法(lombok)
@NoArgsConstructor//编译时生成无参构造方法(lombok)
@AllArgsConstructor//编译时生成全参构造方法(lombok)
@Entity
@Table(name="book")// 指定关联的数据库的表名
public class BookEntity {
    @Id//声明主键ID

@GeneratedValue(strategy = GenerationType.IDENTITY)//自动生成id,使用jpa提供的save()方法必须先为类分配id,没有该注解会报错
    private Long id;
    private String name;
    private String isbn;
    private String author;
}

 

持久层,使用JPA进行数据持久化有两种实现方式

方式一:使用Spring Data JPA 提供的接口默认实现,

方式二:自定义符合Spring Data JPA规则的查询方法,由框架将其自动解析为SQL。

 

方式一:

Spring data JPA提供给用户使用的,主要有以下几个接口:

1.Repository:仅仅是一个标识,表明任何继承它的均为仓库接口类,方便Spring自动扫描识别

2.CrudRepository:继承Repository,实现了一组CRUD相关的方法

3.PagingAndSortingRepository:继承CrudRepository,实现了一组分页排序相关的方法

4.JpaRepository:继承PagingAndSortingRepository,实现一组JPA规范相关的方法

5.JpaSpecificationExecutor:比较特殊,不属于Repository体系,实现一组JPA Criteria查询相关的方法。

 

Crudrepository接口提供了一些简单的增删改查功能:

<S extends T> S save(S entity); // 保存并返回(修改后的)实体

<S extends T> Iterable<S> save(Iterable<S> entities); // 保存并返回(修改后的)实体集合

T findOne(ID id); // 根据ID获取实体

boolean exists(ID id); // 判断指定ID的实体是否存在

Iterable<T> findAll(); // 查询所有实体

Iterable<T> findAll(Iterable<ID> ids); // 根据ID集合查询实体

long count(); // 获取实体的数量

void delete(ID id); // 删除指定ID的实体

void delete(T entity); // 删除实体

void delete(Iterable<? extends T> entities); // 删除实体集合

void deleteAll(); // 删除所有实体

 

PagingAndSortingRepository继承于CrudRepository,除了具有CrudRepository接口的能力外,还新增了分页和排序的功能,接口定义如下:

Iterable<T> findAll(Sort sort); // 查询所有实体并排序

Page<T> findAll(Pageable pageable); // 分页查询实体

 

JpaRepository继承于PagingAndSortingRepository,所以它传递性地拥有了以上接口的所有方法,同时,它还继承了另外一个QueryByExampleExecutor接口,拥有了该接口匹配指定样例的能力,JpaRepository接口定义如下:

List<T> findAll(); // 查询所有实体

List<T> findAll(Sort sort); // 查询所有实体并排序

List<T> findAll(Iterable<ID> ids); // 根据ID集合查询实体

<S extends T> List<S> save(Iterable<S> entities); // 保存并返回(修改后的)实体集合

void flush(); // 提交事务

<S extends T> S saveAndFlush(S entity); // 保存实体并立即提交事务

void deleteInBatch(Iterable<T> entities); // 批量删除实体集合

void deleteAllInBatch();// 批量删除所有实体

T getOne(ID id); // 根据ID查询实体

@Override

<S extends T> List<S> findAll(Example<S> example); // 查询与指定Example匹配的所有实体

@Override

<S extends T> List<S> findAll(Example<S> example, Sort sort);// 查询与指定Example匹配的所有实体并排序

 

QueryByExampleExecutor接口允许开发者根据给定的样例执行查询操作,接口定义如下:

<S extends T> S findOne(Example<S> example); // 查询与指定Example匹配的唯一实体

<S extends T> Iterable<S> findAll(Example<S> example); // 查询与指定Example匹配的所有实体

<S extends T> Iterable<S> findAll(Example<S> example, Sort sort); // 查询与指定Example匹配的所有实体并排序

<S extends T> Page<S> findAll(Example<S> example, Pageable pageable);// 分页查询与指定Example匹配的所有实体

<S extends T> long count(Example<S> example); // 查询与指定Example匹配的实体数量

<S extends T> boolean exists(Example<S> example); // 判断与指定Example匹配的实体是否存在 

 

方式二,自定义查询方法

 

除了可以直接使用Spring Data JPA接口提供的基础功能外,Spring Data JPA还允许开发者自定义查询方法,对于符合以下命名规则的方法,Spring Data JPA能够根据其方法名为其自动生成SQL,除了使用示例中的 find 关键字,还支持的关键字有:query、get、read、count、delete等。

find+全局修饰+By+实体属性名+限定词+连接词+.(其它实体属性)+OrderBy+ 排序属性+排序方向

例如:

findDistinctByFirstNameIgnoreCaseAndLastNameOrderByAgeDesc(String firstName,String lastName);

其中:Distinct是全局修饰(非必须),FirstName和LastName是实体的属性名, And是连接词,IgnoreCase是限定词,Age是排序属性,Desc是排序方向,限定词 和连接词统称为“关键词” 

常用词如下:

全局修饰:Distinct,Top,First

关键词:IsNull,IsNotNull,Like,NotLike,Containing,In,NotIn, IgnoreCase,

Between,Equals,LesThan,GreaterThan,After,Before

排序方向:Asc,Desc

连接词:And,Or

示例:

// 泛型参数1 : 实体类

// 泛型参数2 : 实体类中主键的类型

@Repository

public interface Demo extends JpaRepository<User,Integer>{

    // =============标准命名方式===============

    // 根据名字进行精准查询,Standard类中有name字段

    User findByName(String name);

    // 根据名字进行模糊查询

    User findByNameLike(String name);

    // 查询名字为空的数据

    List<User> findByNameIsNull();

    // 多条件查询

    User findByNameAndPassword(String name,String password);

    // ==============非标准命名方式=============

    // 使用JPQL进行非标准命名查询

    @Query("from User u where u.name like ?")

    User findByNamexxxxxLikeJPQL(String name);

    // 使用JPQL进行非标准多条件查询

    // 默认情况下,问号的顺序和传入的参数顺序是一致的

    // 可以在问号后面追加数字,改变和参数的匹配顺序

    // 下面的示例中,传入的第一个参数匹配到第二个问号,传入的第二个参数匹配到第一个问号

    @Query("from User u where u.name like ?2 and password = ?1")

    User findByNameAndOperatorJPQL(String password,String name);

    // 使用标准SQL进行非标准命名查询

    @Query(value = "select * from user u where u.name like ?", nativeQuery = true)

User findByNamexxxxxLikeSQL(String name);

// 自定义增删改操作

    @Transactional // 使用事务

    @Modifying // 执行修改操作

    @Query("delete from User u where u.name = ?")

    void deleteByName(String name);

 

    @Transactional

    @Modifying // 执行修改操作

    @Query("update User u set u.password = ?2 where u.name = ?1")

    void updatePasswordByName(String name, String password);

}

 

分页查询

 

普通分页

首先分页查询的dao层需要集成两个接口:

@Repository
public interface BookRepository extends JpaRepository<BookEntity,Long>, JpaSpecificationExecutor<BookEntity> {

}

Service层:

@Autowired

BookRepository bookRepository; //dao层接口


@Override
public Page<BookEntity> findBookNoCriteria(Integer page,Integer size) {
    Pageable pageable = new PageRequest(page, size, Sort.Direction.ASC, "id");
    return bookRepository.findAll(pageable);
}

Sort.Direction.ASC,”id”是指根据id排序

Page<T>接口是jpa自带的,getContent()方法返回查询的数据集合,getNumber()返回当前页码(从0开始,不是从1开始),getSize()返回每页显示的数量。

 

多条件(含模糊查询)查询分页

Service层:

@Override
public Page<BookEntity> findBookCriteria(Integer page, Integer size, final BookQuery bookQuery) {
    Pageable pageable = new PageRequest(page, size, Sort.Direction.ASC, "id");

 //构造查询条件
    Page<BookEntity> bookPage = bookRepository.findAll(new Specification<BookEntity>(){
        @Override
        public Predicate toPredicate(Root<BookEntity> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {

/**

*创建一个查询的where语句

*@param root :根对象,可以简单的认为就是泛型对象

*@param criteriaBuilder:构建查询条件

*/
          List<Predicate> list = new ArrayList<Predicate>();//存储条件的集合
          if(null!=bookQuery.getName()&&!"".equals(bookQuery.getName())){
            //构建模糊查询条件criteriaBuilder.like

list.add(criteriaBuilder.like(root.get("name").as(String.class),“%”+bookQuery.getName()+”%”));
          }
          if(null!=bookQuery.getIsbn()&&!"".equals(bookQuery.getIsbn())){

//构建精确查询条件criteriaBuilder.equal

list.add(criteriaBuilder.equal(root.get("isbn").as(String.class), bookQuery.getIsbn()));
          }
          if(null!=bookQuery.getAuthor()&&!"".equals(bookQuery.getAuthor())){
            list.add(criteriaBuilder.equal(root.get("author").as(String.class),

bookQuery.getAuthor()));
          }

//in条件

Set<Long> ids = new HashSet<>();

if (!CollectionUtils.isEmpty(ids)) {
     In<Long> in = criteriaBuilder.in(root.get("id"));
     ids.forEach((c) -> in.value(c));
     list.add(in);
}


          Predicate[] p = new Predicate[list.size()];
          return criteriaBuilder.and(list.toArray(p));
        }
    },pageable);
    return bookPage;
}

 

测试类:

@Test
public void testFindBookNoCriteria() throws Exception {
    Page<BookEntity> page = bookQueryService.findBookNoCriteria(0, 5);
    System.out.println(page.getContent());
}

@Test
public void testFindBookCriteria() throws Exception {
    BookQuery bookQuery = new BookQuery("%1%",null,null);
    Page<BookEntity> bookPage = bookQueryService.findBookCriteria(0, 5, bookQuery);
    System.out.println(bookPage.getContent());
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值