SpringDataJpa快速上手

编程

Spring Data JPA 是 Spring data 项目下的一个模块。提供了一套基于 JPA标准操作数据库的简化方案。底层默认的是依赖 Hibernate JPA 来实现的。

Spring Data JPA 的技术特点:我们只需要定义接口并继承Spring Data JPA 中所提供的接口就可以了。不需要编写接口实现类。

关于SpringDataJpa项目的搭建过程就不贴代码了,文章中涉及代码的完整版都放在了我的gitee中。

SpringData Jpa中的接口继承层次

在日常的Dao接口开发中,我们只需要继承JpaRepository和JpaSpecificationExecutor这两个接口就可以了。

SpringData Jpa的运行原理

在开发中,我们只需要实现指定的两个接口就可以完成任务了,那么到底是怎么实现的呢,通过一个单元测试,看看xxxDao在运行时到底是个什么:

    /**

* springdata Jpa 的运行原理窥视

*/

@Test

public void testSpringDataJpa() {

/**

* class com.sun.proxy.$Proxy39 代理对象

* 可知其实是基于JDK的动态代理

*/

System.err.println(bookDao.getClass());

/**

* org.springframework.data.jpa.repository.support.SimpleJpaRepository@66273da0

* 其实是通过动态代理生成了一个SimpleJpaRepository实例

*/

System.err.println(bookDao);

/**

* 通过工厂创建的方式得到我们的接口实现类对象

*/

JpaRepositoryFactory factory = new JpaRepositoryFactory(entityManager);

BookDao bookDao = factory.getRepository(BookDao.class);

// factoryclass com.sun.proxy.$Proxy39

System.err.println("factory" + bookDao.getClass());

// factoryorg.springframework.data.jpa.repository.support.SimpleJpaRepository@e5cbff2

System.err.println("factory" + bookDao);

}

  • 其实是基于JDK动态代理,在运行时动态的生成一个SimpleJpaRepository 实现类。

知道了接口的继承层次和运行原理,接下开就逐一查看每个接口的作用

SpringData Jpa中的接口

Repository接口

Repository 接口是 Spring Data JPA 中为我我们提供的所有接口中的顶层接口. Repository 提供了两种查询方式的支持

  1. 基于方法名称命名规则查询
  2. 基于@Query 注解查询

基于方法名称命名规则查询

规则:findBy(关键字)+属性名称(属性名称的首字母大写)+查询条件(首字母大写)

关键字

方法命名

SQL语义

And

findByNameAndPwd

where name = ? and pwd = ?

Or

findByNameOrPwd

where name = ? or pwd = ?

Is, Equal

findById, findByIdEquals

where id = ?

Between

findByIdBetween

where id between ? and ?

LessThan

findByIdLessThan

where id < ?

LessThanEqual

findByIdLessThanEqual

where id <= ?

GreaterThan

findByIdGreaterThan

where id > ?

GreaterThanEqual

findByIdGreaterThanEquals

where id > = ?

After

findByIdAfter

where id > ?

Before

findByIdBefore

where id < ?

IsNull

findByNameIsNull

where name is null

IsNotNull, Not Null

findByNameNotNull

where name is not null

Like

findByNameLike

where name like ?

NotLike

findByNameNotLike

where name not like ?

StartingWith

findByNameStartingWith

where name like "?%"

EndingWith

findByNameEndingWith

where name like "%?"

Containing

findByNameContaining

where name like "?%?"

OrderBy

findByIdOrderByXDesc

where id=? order by x desc

Not

findByNameNot

where name <> ?

In

findByIdIn(Collection<T> c)

where id in (?)

NotIn

findByIdNotIn(Collection<T> c)

where id not in (?)

True | False

findByAaaTrue/False

where aaa = true | fasle

IgnoreCase

findByNameIgnoreCase

where UPPER(name)=UPPER(?)

基于@Query 注解查询

使用JPQL语句查询

JPQL:通过 Hibernate 的 HQL 演变过来的。他和 HQL 语法及其相似。

    /**

* 使用JPQL语句查询,用法和HQL语句十分相似

*

* @param booName

* @return

*/

@Query("from Book where bookName = ?")

List<Book> queryByBookNameUseJPQL(String booName);

@Query("from Book where bookName like ?")

List<Book> queryBookUseJPQL(String bookName);

使用SQL语句查询

    /**

* 使用SQL语句查询

*

* nativeQuery:默认的是 false.表示不开启 sql 查询。设置为true则标示开启sql原生查询

*/

@Query(value = "select * from t_book where book_name = ?", nativeQuery = true)

List<Book> queryBookrByNameUseSQL(String bookName);

使用注解更新数据

    /**

* 更新数据

*

* @Modifying 标示当前语句是一个更新语句

*/

@Query("update t_book set book_price = ? where book_id = ?")

@Modifying

void updateBookPriceById(Double bookPrice, Integer bookId);

CrudRepository接口

public interface CrudRepository<T, ID> extends Repository<T, ID> {

// 保存一条数据,如果数据已经存在并且有变化的话,那么就是更新

<S extends T> S save(S var1);

// 批量的添加一个可迭代容器中的所有数据

<S extends T> Iterable<S> saveAll(Iterable<S> var1);

// 根据主键查询数据

Optional<T> findById(ID var1);

boolean existsById(ID var1);

// 查询全部数据

Iterable<T> findAll();

// 根据可迭代的ID查询数据,返回仍然是一个可迭代的集合

Iterable<T> findAllById(Iterable<ID> var1);

// 统计数据的总数

long count();

// 根据ID删除一个数据

void deleteById(ID var1);

// 根据实体删除一个数据

void delete(T var1);

// 删除可迭代集合中所有的数据

void deleteAll(Iterable<? extends T> var1);

// 删除容器中所有的数据

void deleteAll();

}

PagingAndSortingRepository接口

在这个接口中,总共就定义了两个方法,一个是排序,一个是分页

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

Iterable<T> findAll(Sort var1);

Page<T> findAll(Pageable var1);

}

在实际当中使用一下:

        /**

* 分页测试

*/

int pageNum = 1, pageSize = 5;

Page<Book> pageBook = bookDaoPageAndSort.findAll(PageRequest.of(pageNum, pageSize));

/**

* 单列排序

*/

Sort singleSort = new Sort(Sort.Direction.DESC, "book_id");

Iterable<Book> all = bookDaoPageAndSort.findAll(singleSort);

/**

* 多列排序

*/

Sort.Order order1 = new Sort.Order(Sort.Direction.DESC,"book_id");

Sort.Order order2 = new Sort.Order(Sort.Direction.DESC,"book_name");

Sort mutiSort = new Sort(order1, order2);

Iterable<Book> all1 = bookDaoPageAndSort.findAll(mutiSort);

JpaRepository 接口

JpaRepository 接口是我们开发时使用的最多的接口。其特点是可以帮助我们将其他接口的方法的返回值做适配处理。可以使得我们在开发时更方便的使用这些方法。在该接口中并没有新声明方法。

JpaSpecificationExecutor接口

  • 完成多条件查询,并且支持分页与排序

public class JpaSpecTest {

@Autowired

private BookDaoUseSpec bookDaoUseSpec;

/**

* 单条件查询

* 根据书名查询书籍

*/

@Test

public void testJpaSpecSingleRule() {

Specification<Book> spec = new Specification<Book>() {

/**

*

* @param root 根对象。封装了查询条件的对象

* @param criteriaQuery 定义了一个基本的查询,一般不使用

* @param criteriaBuilder 创建的查询条件

* @return Predicate: 查询的条件

*/

@Override

public Predicate toPredicate(Root<Book> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {

Predicate pre = criteriaBuilder.equal(root.get("bookName"), "springdatajpa spec");

return pre;

}

};

/**

* lambda 表达式的写法,更加简单

* select * from t_book where bookName = ?

*/

Specification specification = (root, criteriaQuery, criteriaBuilder) -> {

Predicate pre = criteriaBuilder.equal(root.get("bookName"), "springdatajpa spec");

return pre;

};

bookDaoUseSpec.findAll(spec);

}

/**

* 多条件查询

* 根据书名和价格查询

*/

@Test

public void JpaSpecMutiRule() {

Specification spec = (root, criteriaQuery, criteriaBuilder) -> {

/**

* select * from t_book where bookName = ? or bookPrice = ?

*/

List<Predicate> pres = new ArrayList<>();

pres.add(criteriaBuilder.equal(root.get("bookName"), "java"));

pres.add(criteriaBuilder.equal(root.get("bookPrice"), 100.14));

Predicate[] preArr = new Predicate[pres.size()];

return criteriaBuilder.or(pres.toArray(preArr));

};

bookDaoUseSpec.findAll(spec);

}

/**

* 使用spec 分页和排序查询

*/

@Test

public void testJpaSpecPageAndSort() {

Sort sort = new Sort(Sort.Direction.DESC, "bookId");

int pageNum = 1, pageSize = 5;

Pageable pageable = PageRequest.of(pageNum, pageSize, sort);

Specification spec = (root, criteriaQuery, criteriaBuilder) -> {

return criteriaBuilder.equal(root.get("bookNmae"), "java");

};

bookDaoUseSpec.findAll(spec, pageable);

}

}

自定义接口

除了使用SpringData Jpa提供的接口之外,我们还可以自定义接口,使用自定义接口需要几个规范;

  • 接口定义,命名使用xxxRepository

public interface BookRepository {

Book findBookById(Integer bookId);

}

  • 实现类,命令是xxxDaoImpl,不是xxxRepositoryImpl

public class BookDaoImpl implements BookRepository {

@PersistenceContext(name = "entityManagerFactory")

private EntityManager entityManager;

@Override

public Book findBookById(Integer bookId) {

return entityManager.find(Book.class, bookId);

}

}

  • 使用

    直接在定义的时候使用继承就好了。

public interface BookDao extends JpaRepository<Book, Integer> , BookRepository{

}

以上是 SpringDataJpa快速上手 的全部内容, 来源链接: utcz.com/z/510980.html

回到顶部