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 提供了两种查询方式的支持
- 基于方法名称命名规则查询
- 基于@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