JpaRepository
JpaRepository 接口是我们开发时使用的最多的接口。其特点是可以帮助我们将其他接口的方法的返回值做适配处理。可以使得我们在开发时更方便的使用这些方法。
1.创建接口
/**
* SpringDataJPA 实现JpaRepository
* 泛型 第一个参数是对应的Pojo类型
* 第二个参数是注解的包装类型
*/
public interface UserDao extends JpaRepository<Users,Integer> {
}
2.单元测试
/**
* @program: spring-data-jpa
* @description: 单元测试
* @author: 波波烤鸭
* @create: 2019-05-18 09:48
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestDemo {
@Autowired
private UserDao usersDao;
/**
* 添加用户
*/
@Test
@Transactional// 在测试类对于事务提交方式默认的是回滚。
@Rollback(false)//取消自动回滚
public void testInsertUsers(){
Users users = new Users();
users.setUserage(20);
users.setUsername("张三-jpa");
this.usersDao.save(users);
}
}
JpaSpecificationExecutor
完成多条件查询,并且支持分页与排序。
1.创建接口
JpaSpecificationExecutor接口不能够单独使用,需要和其他接口一块使用,如下
/**
* JpaSpecificationExecutor 接口讲解
* @author Administrator
*注意:JpaSpecificationExecutor<Users>:不能单独使用,需要配合着 jpa 中的其他接口一起使用
*/
public interface UserDao extends JpaRepository<Users, Integer>
, JpaSpecificationExecutor<Users> {
}
2.具体功能
2.1 单条件查询
/**
* 单条件查询
* 需求:根据用户姓名查询数据
*/
@Test
public void test1(){
Specification<Users> spec = new Specification<Users>() {
/**
* @return Predicate:定义了查询条件
* @param Root<Users> root:根对象。封装了查询条件的对象
* @param CriteriaQuery<?> query:定义了一个基本的查询.一般不
使用
* @param CriteriaBuilder cb:创建一个查询条件
*/
@Override
public Predicate toPredicate(Root<Users> root,
CriteriaQuery<?> query, CriteriaBuilder cb) {
Predicate pre = cb.equal(root.get("username"), "王五");
return pre;
}
};
List<Users> list = this.usersDao.findAll(spec);
for (Users users : list) {
System.out.println(users);
}
}
2.2 多条件查询
多条件查询有两种方式,具体如下
/**
* 多条件查询 方式一
* 需求:使用用户姓名以及年龄查询数据
*/
@Test
public void test2() {
Specification<Users> spec = new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root,
CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<>();
list.add(cb.equal(root.get("username"), "王五"));
list.add(cb.equal(root.get("userage"), 24));
//此时条件之间是没有任何关系的。
Predicate[] arr = new Predicate[list.size()];
return cb.and(list.toArray(arr));
}
};
List<Users> list = this.usersDao.findAll(spec);
for (Users users : list) {
System.out.println(users);
}
}
/**
* 多条件查询 方式二
* 需求:使用用户姓名或者年龄查询数据
*/
@Test
public void test3(){
Specification<Users> spec = new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root,
CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.or(cb.equal(root.get("username"),"王五 "),cb.equal(root.get("userage"), 25));
}
};
List<Users> list = this.usersDao.findAll(spec);
for (Users users : list) {
System.out.println(users);
}
}
2.3 分页
/**
* 需求:查询王姓用户,并且做分页处理
*/
@Test
public void test4(){
//条件
Specification<Users> spec = new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root,
CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.like(root.get("username").as(String.class), "王%");
}
};
//分页
Pageable pageable = new PageRequest(2, 2);
Page<Users> page = this.usersDao.findAll(spec, pageable);
System.out.println("总条数:"+page.getTotalElements());
System.out.println("总页数:"+page.getTotalPages());
List<Users> list = page.getContent();
for (Users users : list) {
System.out.println(users);
}
}
2.4 排序
/**
* 需求:查询数据库中王姓的用户,并且根据用户 id 做倒序排序
*/
@Test
public void test5(){
//条件
Specification<Users> spec = new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root,
CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.like(root.get("username").as(String.class),
"王%");
}
};
//排序
Sort sort = new Sort(Sort.Direction.DESC,"userid");
List<Users> list = this.usersDao.findAll(spec, sort);
for (Users users : list) {
System.out.println(users);
}
}
2.5 分页排序
/**
* 需求:查询数据库中王姓的用户,做分页处理,并且根据用户 id 做倒序排序
*/
@Test
public void test6(){
//排序等定义
Sort sort = new Sort(Sort.Direction.DESC,"userid");
//分页的定义
Pageable pageable = new PageRequest(0,2, sort);
//查询条件
Specification<Users> spec = new Specification<Users>() {
@Override
public Predicate toPredicate(Root<Users> root,
CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.like(root.get("username").as(String.class),
"王%");
}
};
Page<Users> page = this.usersDao.findAll(spec, pageable);
System.out.println("总条数:"+page.getTotalElements());
System.out.println("总页数:"+page.getTotalPages());
List<Users> list = page.getContent();
for (Users users : list) {
System.out.println(users);
}
}
如此我们对于单表的相关操作通过JpaSpecificationExecutor接口和JpaRepository接口就都可以实现了
自定义 Repository
一 点睛
Spring Data Commons提供了CrudRepository和PagingAndSortingRepository,相关代码如下:
CrudRepository的定义
//Repository的子接口CrudRepository定义了和CRUD操作相关的内容。
package org.springframework.data.repository;
import java.io.Serializable;
@NoRepositoryBean
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
//关于创建或修改的函数
<S extends T> S save(S entity);
<S extends T> Iterable<S> save(Iterable<S> entities);
//关于获取的函数
T findOne(ID id);
boolean exists(ID id);
Iterable<T> findAll();
Iterable<T> findAll(Iterable<ID> ids);
long count();
//关于删除的函数
void delete(ID id);
void delete(T entity);
void delete(Iterable<? extends T> entities);
void deleteAll();
}
PagingAndSortingRepository的定义
//定义了分页和排序操作相关的内容
package org.springframework.data.repository;
import java.io.Serializable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort sort); //排序
Page<T> findAll(Pageable pageable); //分页
}
Spring Data JPA也提供了JpaRepsitory,相关代码如下:
//继承PagingAndSortingRepository,额外提供了一些其他的API
package org.springframework.data.jpa.repository;
import java.io.Serializable;
import java.util.List;
import javax.persistence.EntityManager;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
@NoRepositoryBean
public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
List<T> findAll();
List<T> findAll(Sort sort);
List<T> findAll(Iterable<ID> ids);
<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);
}
我们是否也可以做类似的封装,定义自己常用的数据库操作呢?当然可以,实现方法如下。
二 实现方法
1 自定义Repository接口(定义要操作的方法)
package com.wisely.support;
import java.io.Serializable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;
@NoRepositoryBean //指明当前这个接口不是领域类的接口
//我们自定义的CustomRepository继承了JpaRepository接口,具备JPA的能力
public interface CustomRepository<T, ID extends Serializable>extends JpaRepository<T, ID> ,JpaSpecificationExecutor<T>{
//要定义的数据操作方法在接口中定义
Page<T> findByAuto(T example,Pageable pageable);
}
2 定义接口的实现(定义操作的具体实现)
package com.wisely.support;
import java.io.Serializable;
import javax.persistence.EntityManager;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import static com.wisely.specs.CustomerSpecs.*;
//要实现 CustomRepository接口,继承SimpleJpaRepository类让我们可以使用其提供的方法(如findAll)
public class CustomRepositoryImpl <T, ID extends Serializable>
extends SimpleJpaRepository<T, ID> implements CustomRepository<T,ID> {
private final EntityManager entityManager;//数据操作方法会用到entityManager
//CustomRepositoryImpl的构造函数,需当前处理的领域类和entityManager作为构造参数,在这里也给entityManager赋值了
public CustomRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
super(domainClass, entityManager);
this.entityManager = entityManager;
}
@Override
public Page<T> findByAuto(T example, Pageable pageable) {
//定义数据访问操作,如调用findAll方法并构造一些查询条件
return findAll(byAuto(entityManager, example),pageable);
}
}\
3 自定义CustomRepositoryFactoryBean(自动注册Repository的实现)
package com.wisely.support;
import java.io.Serializable;
import javax.persistence.EntityManager;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
//自定义CustomRepositoryFactoryBean,继承JpaRepositoryFactoryBean
public class CustomRepositoryFactoryBean<T extends JpaRepository<S, ID>, S, ID extends Serializable>
extends JpaRepositoryFactoryBean<T, S, ID> {
@Override
//重写createRepositoryFactory方法,用当前的CustomRepositoryFactory创建实例
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new CustomRepositoryFactory(entityManager); //该类见下面的定义
}
//定义一个私有的静态类,并继承JpaRepositoryFactory
private static class CustomRepositoryFactory extends JpaRepositoryFactory {
//构造函数
public CustomRepositoryFactory(EntityManager entityManager) {
super(entityManager);
}
@Override
@SuppressWarnings({"unchecked"})
protected <T, ID extends Serializable> SimpleJpaRepository<?, ?> getTargetRepository(
RepositoryInformation information, EntityManager entityManager) {// 获得当前自定义类的实现
return new CustomRepositoryImpl<T, ID>((Class<T>) information.getDomainType(), entityManager);
}
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {// 获得当前自定义类的类型
return CustomRepositoryImpl.class;
}
}
}
四、让实体类继承定义的接口,即可实现自定义的功能