1、导入jar包。
org.springframework.boot
spring-boot-starter-data-jpa
2、配置文件
#spring data jpa
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
3、实体的定义
4、定义Repository接口,继承Repository接口。
/**
* 1、Repository是一个空接口,即是一个标记接口
* 2、若我们定义的接口继承了Repository,则该接口会被IOC容器识别为一个Repository Bean,纳入到IOC容器中,
* 进而可以在该接口中定义满足一些规范的方法。
*3、实际上,也可以通过@RepositoryDefinition()注解的方式来替代继承Repository接口
*@RepositoryDefinition(domainClass= Person.class,idClass = Integer.class)
*/
public interfacePersonRepositoryextendsRepository {
Person findByLastName(String lastName);
}
说明:Repository接口中,泛型是对应的实体,类型是对应实体的主键。
5、Repository的子接口。
CrudRepository接口:继承Repository接口,实现了增删改查方法。
JpaRepository接口:继承PagingAndStoringRepository,实现了一组JPA规范的相关方法。
PagingAndStoringRepository接口:继承CrudRepository接口,实现了分页排序相关的方法。
SimpleJpaRepository接口:
JpaSpecificationExcutor接口:不属于Repository体系,实现一组Criteria查询相关方法。
6、Repository接口中声明方法的规范
1、查询方法以 find | read | get 开头;
2、涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性以首字母大写
例如:定义一个 Entity 实体类 class User{
private String firstName;
private String lastName; }
使用And条件连接时,应这样写: findByLastNameAndFirstName(String lastName,String firstName); 条件的属性名称与个数要与参数的位置与个数一一对应
3、直接在接口中定义查询方法,如果是符合规范的,可以不用写实现,目前支持的关键字写法如下:
4、支持级联查询
若当前类有符合条件的属性,则优先使用,而不使用级联属性。若要使用级联属性,则属性之间使用下划线进行分割。
使用关键字进行查询例子:
//where lastName like ?%
List findByLastNameStartingWith(String lastName);
//where lastName like ?% and id< ?
List getByLastNameStartingWithAndIdLessThan(String lastName,Integer id);
//where lastName in (?,?) or birth
List findByEmailIOrBirthLessThan(List email, Date birth);
//where a.id>?
List findByAddress_IdGreaterThan(Integer id);
5、@Query注解(查询)
//查询Id最大的那个Person(注意:from后面跟着的实体名Person)
//使用@Query注解可以自定义JPQL,语句实现更灵活的查询
@Query("select p from Person p where p.id=(select max(p2.id) from Person p2)")
Person findMaxIdPerson();;
//为Query注解传递参数方式1:使用占位符(参数有顺序)
@Query("select p from Person p where p.lastName=?1 and p.email=?2")
List testQueryAnnotationParams(String lastName,String email);
//为Query注解传递参数方式2:命名参数的方式(参数无顺序)
@Query("select p from Person p where p.lastName=:lastName and p.email=:email")
List testQueryAnnotationParams2(@Param("email") String email,@Param("lastName") String lastName);
//Like参数的传递(在占位符上使用%)
@Query("select p from Person p where p.lastName like %?1% or p.email like %?2%")
List testQueryAnnotationLikeParam(String lastName,String email);
//Like参数的传递(在占位符上使用%)
@Query("select p from Person p where p.lastName like %?% or p.email like %?%")
List testQueryAnnotationLikeParam2(@Param("lastName") String lastName,@Param("email ") String email);
//使用原生的SQL注解
@Query(value ="select count(id) from person",nativeQuery =true)
intgetPersonCount();
6、Modifying注解
//可以通过自定义的JPQL完成update和delete操作,注意:JPQL不支持插入语句(insert)
//在Query注解中,编写JPQL语句,但必须使用@Modiying进行修饰,以通知spring data,这是一个update或者是delete
//update或者是delete操作需要使用事物,此时需要定义Service层,在Service层上添加事物操作
//默认情况下,springdata的每个方法上都是有事物的,但都是一个只读事物,他们不能完成修改操作
@Modifying
@Query("update Person p set p.email=?1 where id=?2")
intupdatePersonLastName(String email,Integer id);
Service层的事物:
@Service
public classPersonServiceImplimplementsPersonService {
@Autowired
privatePersonRepositorypersonRepository;
@Override
@Transactional
public intupdateLastName(String email, Integer id) {
intcount=personRepository.updatePersonLastName("dd",1);
returncount;
}
}
7、CrudRepository子接口
public interfacePersonRepositoryextendsCrudRepository
Service接口:
public interfacePersonService {
intupdateLastName(String email,Integer id);
voidsavePersons(List list);
}
Service接口实现:
@Service
public classPersonServiceImplimplementsPersonService {
@Autowired
privatePersonRepositorypersonRepository;
@Override
@Transactional
public intupdateLastName(String email, Integer id) {
intcount=personRepository.updatePersonLastName("dd",1);
returncount;
}
@Transactional
@Override
public voidsavePersons(List list) {
personRepository.save(list);
}
}
批量添加测试:
@Test
public voidtestSave() {
List persons =newArrayList<>();
for(inti ='a'; i >='z'; i++) {
Person person =newPerson();
person.setBirth(newDate());
person.setLastName("彩虹"+(char)i);
person.setEmail((char)i+"836908728@qq.com"+(char)i);
person.setId(i +10);
persons.add(person);
}
personService.savePersons(persons);
}
8、PageAndSortingRepository子接口
(是一个只读操作,不需要事物)
//pageNo的记录是从1开始
intpageNo =6-1;
intpageSize =5;
//Pageable接口通常使用的其PageRequest实现类,其中封装了分页的相关信息(page,size,sort)
//排序相关,Sort封装了排序的信息
//Order是针对于某一个属性进行升序还是降序
Order order1=newSort.Order(Direction.DESC,"id");
Order order2=newSort.Order(Direction.ASC,"email");
//sort可以包含多个
Sort sort=newSort(order1,order2);
PageRequest pageable =newPageRequest(pageNo, pageSize,sort);
Page page =personRepository.findAll(pageable);
System.out.println("总记录数:"+ page.getTotalElements());
System.out.println("当前第几页:"+ (page.getNumber()+1));
System.out.println("总页数:"+ page.getTotalPages());
System.out.println("当前页面的list:"+ page.getContent());
System.out.println("当前页面的记录数:"+ page.getNumberOfElements());
9、JpaRepository接口:是PagingAndSortingRepository的子接口
public interfacePersonRepositoryextendsJpaRepository
@Test
public voidtestJpaRepository() {
Person person =newPerson();
person.setBirth(newDate());
person.setLastName("云南");
person.setEmail("836908728@qq.com");
person.setId(27);
Person person1 =personRepository.saveAndFlush(person);
System.out.println(person == person1);
}
9、JpaSpecificationExecutor接口,不属于Repository体系
(实现带查询条件的分页)
public interfacePersonRepositoryextendsJpaRepository,JpaSpecificationExecutor
@Test
/**
* 实现带查询条件的分页:
* 使用JpaSpecificationExecutor的PagefindAll(Specificationspec,Pageable pageable)
* Specification:封装了JPA Criteria查询的查询条件
* Pageable:封装了请求分页的信息,例如:pageNo,pageSize,Sort
*/
public voidtestJpaSpecificationExecutor(){
intpageNo=3-1;
intpageSize=5;
PageRequest pageRequest=newPageRequest(pageNo,pageSize);
Specification specification=newSpecification() {
/**
*
*@paramroot:代表查询的实体类
*@paramcriteriaQuery:可以从中得到root对象,即告知JPA Criteria查询要查询哪一个实体类,还可以添加查询条件
* 还可以结合EntityManager对象得到最终查询的TypeQuery对象
*@paramcriteriaBuilder:CriteriaBuilder 用于创建Criteria相关对象的工厂,当然可以从中获取到Predicate对象
*@returnPredicate类型,代表一个查询条件
*/
@Override
//如:实现id>5
publicPredicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path path=root.get("id");
Predicate predicate=criteriaBuilder.gt(path,5);
returnpredicate;
}
};
Page page=personRepository.findAll(specification,pageRequest);
System.out.println("总记录数:"+ page.getTotalElements());
System.out.println("当前第几页:"+ (page.getNumber() +1));
System.out.println("总页数:"+ page.getTotalPages());
System.out.println("当前页面的list:"+ page.getContent());
System.out.println("当前页面的记录数:"+ page.getNumberOfElements());
}
10、自定义Repository接口
•步骤:
–定义一个接口: 声明要添加的, 并自实现的方法
–提供该接口的实现类: 类名需在要声明的 Repository 后添加 Impl, 并实现方法
–声明 Repository 接口, 并继承 1) 声明的接口
–使用.
–注意: 默认情况下, Spring Data 会在 base-package 中查找 "接口名Impl" 作为实现类. 也可以通过 repository-impl-postfix 声明后缀.
如:定义一个接口:
2、实现接口
3、继承自定义接口
public interfacePersonRepositoryextendsJpaRepository,JpaSpecificationExecutor,TestRepository