一、SpringBootData JPA介绍
SpringData:其实SpringData就是Spring提供了一个操作数据的框架。而SpringData JPA只是SpringData框架下的一个基于JPA标准操作数据的模块
SpringData JPA:基于JPA的标准数据进行操作。简化操作持久层的代码。只需要编写接口就可以
二、SpringBoot整合SpringData JPA
1、导入maven依赖
在原有的SprigBoot的maven依赖的基础上加上JPA的依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
2、application.properties文件中添加配置
spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true
3、实体类
@Entity @Table(name = "t_users") @Data @ToString public class Users { @Id //主键id @GeneratedValue(strategy = GenerationType.IDENTITY)//主键生成策略 @Column(name = "id")//数据库字段名 private Integer id; @Column(name = "name") private String name; @Column(name = "age") private Integer age; @Column(name = "address") private String address; @ManyToOne(cascade = CascadeType.PERSIST) //表示多方 @JoinColumn(name = "role_id") //维护一个外键,外键在Users一侧 private Roles roles; }
4、编写Dao接口
import org.springframework.data.jpa.repository.JpaRepository; import com.bjsxt.pojo.Users; /** * 参数一 T :当前需要映射的实体 * 参数二 ID :当前映射的实体中的OID的类型 * */ public interface UsersRepository extends JpaRepository<Users,Integer> { }
三、SpringBoot JPA提供的核心接口
Repository接口
CrudRepository接口
PagingAndSortingRepository接口
JpaRepository接口
JPASpecificationExecutor接口
四、Repository接口的使用
提供了方 法 名 称 命 名 \color{#FF0000}{方法名称命名}方法名称命名查询方式
提供了基于@ Q u e r y 注 解 \color{#FF0000}{@Query注解}@Query注解查询与更新
1、dao层接口(方法名称命名查询方式)
/** * Repository接口方法名称命名查询 */ public interface UsersRepositoryByName extends Repository<Users,Integer> { //方法名称必须要遵循驼峰式命名规则,findBy(关键字)+属性名称(首字母大写)+查询条件(首字母大写) List<Users> findByName(String name); List<Users> findByNameAndAge(String name,Integer age); List<Users> findByNameLike(String name); }
2、测试
/** * Repository */ @Test public void UsersRepositoryByName(){ List<Users> list=this.usersRepositoryByName.findByName("张三"); for (Users users:list){ System.out.println(users); } } @Test public void findByNameAndAge(){ List<Users> list=this.usersRepositoryByName.findByNameAndAge("张三",20); for (Users users:list){ System.out.println(users); } } @Test public void findByNameLike() { List<Users> list = this.usersRepositoryByName.findByNameLike("张%"); for (Users users : list) { System.out.println(users); } }
3、dao层接口编写(基于@Query注解查询与更新)
public interface UsersRepositoryQueryAnnotation extends JpaRepository<Users,Integer> { @Query("from Users where name = ?") List<Users> queryByNameUseHQL(String name); @Query(value = "select * from t_user where name=?",nativeQuery = true) List<Users> queryByNameUseSQL(String name); @Query("update Users set name=? where id=?") @Modifying //需要执行一个更新操作 void updateUsersNameById(String name,Integer id); }
4、测试
/** * Repository--@Query测试 */ @Test public void testQueryByNameUseSQL() { List<Users> list = this.usersRepositoryQueryAnnotation.queryByNameUseSQL("张三"); for (Users users : list) { System.out.println(users); } } /** * Repository--@Query测试 */ @Test @Transactional //@Transactional与@Test 一起使用时 事务是自动回滚的。 @Rollback(false) //取消自动回滚 public void testUpdateUsersNameById() { this.usersRepositoryQueryAnnotation.updateUsersNameById("张三三", 1); }
五、CrudRepository接口的使用
CrudRepository接口,主要是完成一些增删改查的操作。注意:CrudRepository接口继承了Repository接口
1、编写dao层接口
import org.springframework.data.repository.CrudRepository; public interface UsersRepositoryCrudRepository extends CrudRepository<Users,Integer> { }
2、测试
@Test public void testCrudRepositoryUpdate() { Users users=new Users(); users.setId(4); users.setName("青"); users.setAge(18); users.setAddress("怀化"); this.usersRepositoryCrudRepository.save(users); } @Test public void testCrudRepositoryFindOne() { Users users=this.usersRepositoryCrudRepository.findOne(4); System.out.println(users); } @Test public void testCrudRepositoryFindAll() { List<Users> list= (List<Users>) this.usersRepositoryCrudRepository.findAll(); for (Users user:list){ System.out.println(user); } } @Test public void testCrudRepositoryDeleteById() { this.usersRepositoryCrudRepository.delete(4); }
六、PagingAndSortingRepository接口的使用
该接口提供了分页与排序的操作,注意:该接口继承了CrudRepository接口
1、编写dao层
import org.springframework.data.repository.PagingAndSortingRepository; public interface UsersRepositoryPagingAndSorting extends PagingAndSortingRepository<Users,Integer> { }
2、测试
@Test public void testPagingAndSortingRepositorySort() { //Order 定义了排序规则 Sort.Order order=new Sort.Order(Sort.Direction.DESC,"id"); //Sort对象封装了排序规则 Sort sort=new Sort(order); List<Users> list= (List<Users>) this.usersRepositoryPagingAndSorting.findAll(sort); for (Users users:list){ System.out.println(users); } } @Test public void testPagingAndSortingRepositoryPaging() { //Pageable:封装了分页的参数,当前页,煤业显示的条数。注意:它的当前页是从0开始 //PageRequest(page,size):page表示当前页,size表示每页显示多少条 Pageable pageable=new PageRequest(1,2); Page<Users> page=this.usersRepositoryPagingAndSorting.findAll(pageable); System.out.println("数据的总条数:"+page.getTotalElements()); System.out.println("总页数:"+page.getTotalPages()); List<Users> list=page.getContent(); for (Users users:list){ System.out.println(users); } } @Test public void testPagingAndSortingRepositorySortAndPaging() { Sort sort=new Sort(new Sort.Order(Sort.Direction.DESC,"id")); Pageable pageable=new PageRequest(0,2,sort); Page<Users> page=this.usersRepositoryPagingAndSorting.findAll(pageable); System.out.println("数据的总条数:"+page.getTotalElements()); System.out.println("总页数:"+page.getTotalPages()); List<Users> list=page.getContent(); for (Users users:list){ System.out.println(users); } }
七、JpaRepository接口
该接口继承了PagingAndSortingRepository。对继承的父接口中方法的返回值进行适配
1、dao层接口编写
/** * 参数一 T :当前需要映射的实体 * 参数二 ID :当前映射的实体中的OID的类型 * */ public interface UsersRepository extends JpaRepository<Users,Integer> { }
2、测试
/** * JpaRepository 排序测试 */ @Test public void testJpaRepositorySort() { //Order 定义了排序规则 Sort.Order order=new Sort.Order(Sort.Direction.DESC,"id"); //Sort对象封装了排序规则 Sort sort=new Sort(order); List<Users> list= this.usersRepository.findAll(sort); for (Users users:list){ System.out.println(users); } }
八、JPASpecificationExecutor接口
该接口主要是提供了多条件查询的支持,并且可以在查询中添加排序与分页。注意JPASpecificationExecutor是单独存在的。完全独立
1、dao层接口编写
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; /** * 〈一句话功能简述〉<br> * JpaSpecificationExecutor * * @author admin * @create 2019/5/23 * @since 1.0.0 */ public interface UserRepositorySpecification extends JpaRepository<Users,Integer>,JpaSpecificationExecutor<Users> { }
2、测试
/** * JpaSpecificationExecutor 单条件查询 */ @Test public void testJpaSpecificationExecutor1() { /** * Specification:用于封装查查询条件 */ Specification<Users> spec=new Specification<Users>() { //Predicate:封装了单个查询条件 /** * @param root 对查询对象属性的封装 * @param criteriaQuery 封装了我们要执行的查询中的各个部分的信息,select from order * @param criteriaBuilder 查询条件的构造器 * @return */ @Override public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { //where name="张三" /** * 参数一:查询的属性 * 参数二:条件的值 */ Predicate predicate=criteriaBuilder.equal(root.get("name"),"张三"); return predicate; } }; List<Users> list=this.userRepositorySpecification.findAll(spec); for (Users users:list){ System.out.println(users); } } /** * JpaSpecificationExecutor 多条件查询方式一 */ @Test public void testJpaSpecificationExecutor2() { /** * Specification:用于封装查查询条件 */ Specification<Users> spec=new Specification<Users>() { //Predicate:封装了单个查询条件 /** * @param root 对查询对象属性的封装 * @param criteriaQuery 封装了我们要执行的查询中的各个部分的信息,select from order * @param criteriaBuilder 查询条件的构造器 * @return */ @Override public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { //where name="张三" and age=20 /** * 参数一:查询的属性 * 参数二:条件的值 */ List<Predicate> list=new ArrayList<>(); list.add(criteriaBuilder.equal(root.get("name"),"张三")); list.add(criteriaBuilder.equal(root.get("age"),20)); Predicate[] arr=new Predicate[list.size()]; return criteriaBuilder.and(list.toArray(arr)); } }; List<Users> list=this.userRepositorySpecification.findAll(spec); for (Users users:list){ System.out.println(users); } } /** * JpaSpecificationExecutor 多条件查询方式二 */ @Test public void testJpaSpecificationExecutor3() { /** * Specification:用于封装查查询条件 */ Specification<Users> spec=new Specification<Users>() { //Predicate:封装了单个查询条件 /** * @param root 对查询对象属性的封装 * @param criteriaQuery 封装了我们要执行的查询中的各个部分的信息,select from order * @param criteriaBuilder 查询条件的构造器 * @return */ @Override public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { //where name="张三" and age=20 /** * 参数一:查询的属性 * 参数二:条件的值 */ /*List<Predicate> list=new ArrayList<>(); list.add(criteriaBuilder.equal(root.get("name"),"张三")); list.add(criteriaBuilder.equal(root.get("age"),20)); Predicate[] arr=new Predicate[list.size()];*/ //(name='张三' and age=20) or id=2 return criteriaBuilder.or(criteriaBuilder.and(criteriaBuilder.equal(root.get("name"),"张三"),criteriaBuilder.equal(root.get("age"),20)),criteriaBuilder.equal(root.get("id"),1)); } }; Sort sort=new Sort(new Sort.Order(Sort.Direction.DESC,"id")); List<Users> list=this.userRepositorySpecification.findAll(spec,sort); for (Users users:list){ System.out.println(users); } }
九、关联映射操作
1、一对多的关联关系
需求:角色与用户的一对多的关联关系
角色:一方
用户:多方
2、实体类
/** * @author xhy * @version 1.0 * @date 2021/6/28 17:14 * @description */ @Entity @Table(name = "t_roles") @Data @ToString public class Roles { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "role_id") private Integer roleId; @Column(name = "role_name") private String roleName; @OneToMany(mappedBy = "roles") private Set<Users> users=new HashSet<>(); }
@Entity @Table(name = "t_roles") @Data @ToString public class Menus { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "menus_id") private Integer menusId; @Column(name = "menus_name") private String menusName; @Column(name = "menus_url") private String menusUrl; @Column(name = "father_id") private Integer fatherId; @ManyToMany(mappedBy = "menus") private Set<Roles> roles = new HashSet<>(); }
3、dao层接口编写
/** * 参数一 T :当前需要映射的实体 * 参数二 ID :当前映射的实体中的OID的类型 * */ public interface UsersRepository extends JpaRepository<Users,Integer> { }
4、测试
package com.bjsxt.test; import com.bjsxt.dao.RolesRepository; import com.bjsxt.pojo.Menus; import com.bjsxt.pojo.Roles; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.Set; /** * 〈一句话功能简述〉<br> * 多对多的关联关系的测试 * * @author admin * @create 2019/5/23 * @since 1.0.0 */ @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = App.class) public class ManyToManyTest { @Autowired private RolesRepository rolesRepository; /** * 添加测试 */ @Test public void testSave(){ //创建角色对象 Roles roles=new Roles(); roles.setRoleName("项目经理"); //创建菜单对象 Menus menus=new Menus(); menus.setMenusName("xxxx管理系统"); menus.setFatherId(0); Menus menus2=new Menus(); menus2.setFatherId(1); menus2.setMenusName("项目管理"); //关联 roles.getMenus().add(menus); roles.getMenus().add(menus2); menus.getRoles().add(roles); menus2.getRoles().add(roles); //保存 this.rolesRepository.save(roles); } /** * 查询操作 */ @Test public void testFind(){ Roles roles=this.rolesRepository.findOne(2); System.out.println(roles.getRoleName()); Set<Menus> menus=roles.getMenus(); for (Menus menu:menus){ System.out.println(menu); } } }
5、多对多的关联关系
角色与菜单多对多关联关系
菜单:多方
角色:多方
6、在Roles中添加以下内容
@ManyToMany(cascade = CascadeType.PERSIST,fetch = FetchType.EAGER) //映射中间表 joinColumns:当前表中的主键关联中间表的外键 @JoinTable(name = "t_roles_menus",joinColumns =@JoinColumn(name = "role_id"),inverseJoinColumns = @JoinColumn(name = "menu_id")) private Set<Menus> menus=new HashSet<>();
7、dao层接口
import org.springframework.data.jpa.repository.JpaRepository; public interface RolesRepository extends JpaRepository<Roles,Integer> { }
8、测试
/** * Copyright (C), 2015-2019, XXX有限公司 * FileName: ManyToManyTest * Author: admin * Date: 2019/5/23 14:19 * Description: * History: * <author> <time> <version> <desc> * 作者姓名 修改时间 版本号 描述 */ package com.bjsxt.test; import com.bjsxt.dao.RolesRepository; import com.bjsxt.pojo.Menus; import com.bjsxt.pojo.Roles; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.Set; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = App.class) public class ManyToManyTest { @Autowired private RolesRepository rolesRepository; /** * 添加测试 */ @Test public void testSave(){ //创建角色对象 Roles roles=new Roles(); roles.setRoleName("项目经理"); //创建菜单对象 Menus menus=new Menus(); menus.setMenusName("xxxx管理系统"); menus.setFatherId(0); Menus menus2=new Menus(); menus2.setFatherId(1); menus2.setMenusName("项目管理"); //关联 roles.getMenus().add(menus); roles.getMenus().add(menus2); menus.getRoles().add(roles); menus2.getRoles().add(roles); //保存 this.rolesRepository.save(roles); } /** * 查询操作 */ @Test public void testFind(){ Roles roles=this.rolesRepository.findOne(2); System.out.println(roles.getRoleName()); Set<Menus> menus=roles.getMenus(); for (Menus menu:menus){ System.out.println(menu); } } }