Spring Boot 整合Spring Data JPA
ORM思想
主要目的:操作实体类相当于操作数据库表
建立两个关系:
1.建立实体类和表的映射关系
2.建立实体类中的属性和表中字段的映射关系
不再重点关注sql语句(这是ORM思想我感觉最好的一个地方)
实现了ORM思想的框架:mybatis,hibernate
JPA底层实现数据库语言的还是hibernate
Spring Boot 整合Spring Data JPA 的时候Dao层的repository接口类继承的四个接口的详解
Spring Boot 整合Spring Data JPA 的时候需要定义Dao 层,就是repository类,这个类是一个接口,来继承一个接口,一共有四个接口
1.Repository接口
提供了方法名称命名查询方式
提供了基于@Query注解查询与更新
下面是repository类的代码
publicinterfacePersonRepositoryByNameextendsRepository<Person,Integer>{//一定注意下方法名:findBy(关键字)+属性名(首字母大写)
List<Person>findByName(String name);//按照姓名查找
List<Person>findByAddress(String address);//按照地址查找
List<Person>findByNameOrAge(String name,Integer age);//按照姓名或者年龄查找
List<Person>findByNameLike(String name);//按照姓名模糊查找
List<Person>findByAddressLike(String address);//按照地址模糊查找}
下面是一个测试代码
@SpringBootTestclassSpringbootSpringdatajpaApplicationTests{@Autowired
PersonRepository personRepository;@Autowired
PersonRepositoryByName personRepositoryByName;@TestpublicvoidtestSave(){
Person person=newPerson();
person.setAge(24);
person.setName("张三");
person.setAddress("济南市槐荫区");this.personRepository.save(person);}@TestpublicvoidtestFindByName(){
List<Person> list=this.personRepositoryByName.findByName("张三");for(Person persons: list){
System.out.println(persons);}}@TestpublicvoidtestFindByAddress(){
List<Person> list=this.personRepositoryByName.findByAddress("济南市历下区");for(Person persons: list){
System.out.println(persons);}}@TestpublicvoidtestFindByNameOrAge(){
List<Person> list=this.personRepositoryByName.findByNameOrAge("李四",21);for(Person persons: list){
System.out.println(persons);}}@TestpublicvoidtestFindByNameLink(){
List<Person> list=this.personRepositoryByName.findByNameLike("李%");for(Person persons: list){
System.out.println(persons);}}@TestpublicvoidtestFindByAddressLink(){
List<Person> list=this.personRepositoryByName.findByAddressLike("济南市%");for(Person persons: list){
System.out.println(persons);}}}
基于@Query注解查询与更新
首先还是需要建立一个repository接口来继承Repository接口,然后写方法
代码
publicinterfacePersonRepositoryQueryAnnotationextendsRepository<Person,Integer>{//使用@Query注解结合sql语句来实现查找,**注意**:?的顺序和形参的顺序是一一对应的
nativeQuery=true的意思是告诉hibernate这是一个标准的sql语句@Query(value="select * from tb_person where name=?",nativeQuery=true)
List<Person>queryByName(String name);@Query(value="update tb_person set name=? where id=?",nativeQuery=true)@Modifying//这是更新的注解与@Query注解配合使用来更新voidupdateNameById(String name,Integer id);}
测试代码:
@TestpublicvoidtestQueryByName(){
List<Person> list=this.personRepositoryQueryAnnotation.queryByName("张三");for(Person persons: list){
System.out.println(persons);}}@Test@Transactional//手动设置一个事务,更新操作必须在事务中@Rollback(value=false)//取消自动回滚publicvoidtestUpdateNameById(){this.personRepositoryQueryAnnotation.updateNameById("张三三",3);}}
2.CrudRepository接口
注意:CrudRepository接口是继承的Repository接口的,主要功能就是增删改查,而且CrudRepository接口的使用和JpaRepository接口的使用非常类似
CrudRepository接口中的方法都有[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YIAb4NvH-1618480041802)(C:\Users\86130\AppData\Roaming\Typora\typora-user-images\image-20210413213804466.png)]
接口类的实现代码
publicinterfaceCrudRepositoryextendsorg.springframework.data.repository.CrudRepository<Person,Integer>{}
测试增删改查的代码
//插入数据@TestpublicvoidtestInsert(){
Person person=newPerson();
person.setName("张三丰");
person.setAddress("青岛市");
person.setAge(333);
crudRepository.save(person);}//注意CrudRepository的save方法既可以插入又可以更新@TestpublicvoidtestInsert(){
Person person=newPerson();、//**注意**:如果你想要更新的话必须指定id,使用setId()方法
person.setId(4);
person.setName("张三丰");
person.setAddress("青岛市黄岛区");
person.setAge(333);
crudRepository.save(person);}//按照Id进行指定删除@TestpublicvoidtestDeleteById(){
crudRepository.deleteById(5);}//按照指定Id进行查找@TestpublicvoidtestFindById(){
Optional<Person> persons= crudRepository.findById(4);
System.out.println(persons);}//查找全部@TestpublicvoidtestFindAll(){
Iterable<Person> all= crudRepository.findAll();
System.out.println(all);}
3.PagingAndSortingRepository接口
这个类继承了CrudRepository接口,主要功能是排序查询和分页查询
首先我们看一下接口类的实现
publicinterfaceRepositoryPagingAndSortingextendsPagingAndSortingRepository<Person,Integer>{}
PagingAndSortingRepository接口中的方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-geuBbPid-1618480041806)(C:\Users\86130\AppData\Roaming\Typora\typora-user-images\image-20210414165917747.png)]
测试代码
//排序查询@TestpublicvoidtestSort(){//Order来定义排序规则DESC是降序,ASC是升序
Order order=newOrder(Sort.Direction.DESC,"id");//spring boot2.0以上版本的Sort重写了,不能new Sort了,要用Sort.by
Sort sort=Sort.by(order);
List<Person> persons=(List<Person>) repositoryPagingAndSorting.findAll(sort);for(Person list: persons){
System.out.println(list);}}//分页查询@TestpublicvoidtestPaging(){//spring boot2.0以上版本不能用Pageable了要使用PageRequest.of,返回PageRequest
PageRequest pageable=PageRequest.of(1,2);
Page<Person> page= repositoryPagingAndSorting.findAll(pageable);
System.out.println("总条数"+page.getTotalElements());
System.out.println("总页数"+page.getTotalPages());
List<Person> list= page.getContent();for(Person persons:list){
System.out.println(persons);}}//分页排序查询(将上面两个方法结合)@TestpublicvoidtestPagingAndSort(){
Order order=newOrder(Sort.Direction.DESC,"id");
Sort sort=Sort.by(order);
PageRequest pageable= PageRequest.of(0,2,sort);
Page<Person> page= repositoryPagingAndSorting.findAll(pageable);
System.out.println("总条数"+page.getTotalElements());
System.out.println("总页数"+page.getTotalPages());
List<Person> list= page.getContent();for(Person persons:list){
System.out.println(persons);}}
4.JpaRepository接口
该类继承了PagingAndSortingRepository接口,可以对父接口中的方法返回值进行适配
接口类的定义
publicinterfacePersonRepositoryextendsJpaRepository<Person,Integer>{}
JpaRepository接口中的方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TZiSoi0D-1618480041807)(C:\Users\86130\AppData\Roaming\Typora\typora-user-images\image-20210414171553284.png)]
测试代码
//分页查询@TestpublicvoidtestJpaRepository(){
Sort sort=Sort.by(Sort.Direction.DESC,"id");
PageRequest pageable=PageRequest.of(0,2,sort);
Page<Person> page= personRepository.findAll(pageable);
List<Person> list= page.getContent();for(Person persons:list){
System.out.println(persons);}}//按照顺序查询@TestpublicvoidtestJpaRepositoryFind(){
Sort sort= Sort.by(Sort.Direction.DESC,"id");//注意这里的personRepository.findAll(sort)不需要进行强制类型转换,因为JpaRepository实现了对父接口的返回值类型的适配
List<Person> list= personRepository.findAll(sort);for(Person persons: list){
System.out.println(persons);}}
=5.JpaSpecificationExecutor接口==
JpaSpecificationExecutor没有继承前面的四个接口的任意一个,它是独立的一个,所以它有时候需要配合其他的接口使用。JpaSpecificationExecutor接口主要用于对一些复杂条件的查询
JpaSpecificationExecutor接口经常配合JpaSpecificationExecutor接口使用
下面是JpaSpecificationExecutor接口中的方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xKYO59kz-1618480041809)(C:\Users\86130\AppData\Roaming\Typora\typora-user-images\image-20210414191340758.png)]
接口类的代码
publicinterfaceRepositoryJpaSeextendsJpaSpecificationExecutor<Person>/*只需要写实体类*/,JpaRepository<Person,Integer>{}
测试代码
//单条件查询@TestpublicvoidtestJpaSe(){
Specification spe=newSpecification(){@Override/**root是我们实体类的一个封装类
* criteriaQuery:封装了我们要执行的查询中的各个部分的信息
* criteriaBuilder:定义不同的查询条件
*/public PredicatetoPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder){
Predicate predicate= criteriaBuilder.equal(root.get("name"),"张三三");return predicate;}};
Optional list= repositoryJpaSe.findOne(spe);
System.out.println(list);}//多条件查询@TestpublicvoidtestJpaSpe(){
Specification spe=newSpecification(){@Overridepublic PredicatetoPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder){//多条件查询的时候我们就将我们的多个查询条件放进Predicate类型的List中
Predicate name= criteriaBuilder.equal(root.get("name"),"李四");
Predicate age= criteriaBuilder.equal(root.get("age"),24);
List<Predicate> list=newArrayList<>();
list.add(name);
list.add(age);
Predicate[] pre=newPredicate[list.size()];//将list中的数据注入到一个Predicate类型的数组中,其中or是或者的关系,and是并列的关系return criteriaBuilder.or(list.toArray(pre));}};
List list= repositoryJpaSe.findAll(spe);
System.out.println(list);}//多条件查询并且排序@TestpublicvoidtestJpaSpe1(){
Specification spe=newSpecification(){@Overridepublic PredicatetoPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder){//注意可以这样来写我们的多个条件,这样写比较方便简洁return criteriaBuilder.or(criteriaBuilder.equal(root.get("name"),"张三丰"),criteriaBuilder.equal(root.get("age"),333),criteriaBuilder.equal(root.get("id"),2));}};
Sort sort=Sort.by(Sort.Direction.DESC,"id");
List list= repositoryJpaSe.findAll(spe, sort);
System.out.println(list);}//多条件查询并且分页查询@TestpublicvoidtestJpaSpe2(){
Specification spe=newSpecification(){@Overridepublic PredicatetoPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder){//注意可以将and和or条件组合使用return criteriaBuilder.or(criteriaBuilder.equal(root.get("name"),"张三丰"),criteriaBuilder.equal(root.get("age"),333),criteriaBuilder.equal(root.get("id"),2));}};
Sort sort=Sort.by(Sort.Direction.DESC,"id");
PageRequest pageable=PageRequest.of(0,1,sort);
Page<Person> people= repositoryJpaSe.findAll(spe,pageable);
List<Person> list= people.getContent();
System.out.println(list);}
关联映射操作
一对多的关联映射
要在一对多和多对一的实体类中分别加注解
实体类代码
//roles 角色的实体类@Entity@Table(name="tb_roles")publicclassRoles{@Id@GeneratedValue(strategy= GenerationType.IDENTITY)@Column(name="roles_id")private Integer roles_id;@Column(name="role_name")