美文网首页
Spring Boot整合Spring Data JPA

Spring Boot整合Spring Data JPA

作者: Yanl__ | 来源:发表于2019-12-25 15:08 被阅读0次

    1.简介
    2.整合Spring Data JPA
    3.JPA提供的核心接口
    4.关联映射

    1.简介

    Spring Data:

    Spring提供了一个操作数据的框架,而Spring Data JPA只是Spring Data框架下一个基于JPA标准操作数据的模块

    Spring Data JPA:

    基于JPA标准对数据进行操作。简化操作持久层代码,只需要编写接口。

    2.整合Spring Data JPA

    1. 搭建整合环境
      修改pom文件,添加坐标
    <!-- springBoot整合jpa的启动器-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>
    
            <!-- 测试工具的启动器-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
            </dependency>
    <!-- mysql -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
    
    1. 配置application.properties
    spring.datasource.driverClassName=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/ssm
    spring.datasource.username=root
    spring.datasource.password=951105
    
    #spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    
    spring.jpa.hibernate.ddl-auto=update
    # 显示sql语句
    spring.jpa.show-sql=true
    
    1. 添加实体类
      3.1 添加注解@Entity,表示当前类是实体类。
      3.2 添加注解@Table(name = "t_users"),指定数据库中的表名
      3.3 添加注解@Id, 表明当前属性为主键
            设置主键生成策略 @GeneratedValue(strategy = GenerationType.IDENTITY)
      3.4 @Column(name = "id") 表示属性与数据库表中的哪一列的映射关系
    @Entity
    // 设置数据库中的表名
    @Table(name = "t_users")
    public class Users {
        // 设置主键
        @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;
    
    1. 编写Dao接口
    public interface UsersRepository extends JpaRepository<Users, Integer> {
    }
    
    1. 编写启动类
    2. 编写测试代码
      通过JPA生成表,并添加数据
    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest(classes = App.class)
    public class UsersRepositoryTest {
    
        @Autowired
        private UsersRepository usersRepository;
    
        @Test
        public void testSave(){
            Users users = new Users();
            users.setName("张三");
            users.setAge(18);
            users.setAddress("china");
            this.usersRepository.save(users);
        }
    }
    

    3.Spring Data JPA提供的核心接口

    1. Repository接口
      1.1 方法名称命名查询方式
      1.2 基于@Query注解查询与更新
    2. CrudRepository接口
    3. PagingAndSortingRepository接口
    4. JpaRepository接口
    5. JPASpecificationExecutor接口

    1. Repository接口

    1.1 方法名称命名查询方式
    方法的名称必须要遵循驼峰式命名规则。findBy(关键字)+属性名称(首字母要大写)
    +查询条件(首字母大写)

    编写Dao接口

    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);
    }
    

    编写测试类

        @Test
        public void testFindByName(){
            List<Users> list = this.usersRepositoryByName.findByName("张三");
            for(Users users :list){
                System.out.println(users);
            }
        }
    

    1.2 基于@Query注解查询与更新

    • 查询直接加@Query注解
    • 需要更新数据库中信息还需要添加@Modifying注解
        @Query("from Users where name = ?")
        List<Users> queryByNameUseHQL(String name);
        
        @Query(value="select * from t_users where name = ?",nativeQuery=true)
        List<Users> queryByNameUseSQL(String name);
        
        @Query("update Users set name  = ? where id  = ?")
        @Modifying //需要执行一个更新操作
        void updateUsersNameById(String name,Integer id);
    

    2. CrudRepository接口

    主要完成一些增删改查的操作。继承了Repository接口,能使用其所有操作

    • save
      save方法,已经加了事务的注解。由源码可以看出,save方法即是插入,也是更新。(当数据库中有该对象时,就是更新,没有时,就是插入)


      save

    3. PagingAndSortingRepository接口

    实现排序和分页的功能,只能对全部数据进行分页与排序。

    1. 分页
            //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);
            }
    
    1. 排序
      2.1 定义排序规则order
      Order(Direction.DESC,"id"); 第一个参数为: 设置降序,第二个参数为:选择那个字段进行排序操作
      2.2 使用sort对象封装排序规则
            //Order 定义排序规则
            Order order = new Order(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);
            }
    
    1. 排序加分页
      将封装了排序规则的sort对象放在PageRequest方法中
            Sort sort = new Sort(new Order(Direction.DESC, "id"));
            
            Pageable pageable = new PageRequest(1, 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);
            }
    

    4. JpaRepository接口

    该接口继承了PagingAndSortingRepository接口。对父接口中的方法的返回值进行了适配。

    List<Users> list = (List<Users>)this.usersRepositoryPagingAndSorting.findAll(sort);

    PagingAndSortingRepository
    这里的findAll方法返回的是一个可迭代类型,需要强转成List。

    List<Users> list = this.usersJpaRepository.findAll();
    JpaRepository
    在JpaRepository中,会对方法的返回值进行适配,直接返回List类型的,不需要强转。

    5. JPASpecificationExecutor接口

    该接口主要是提供了多条件查询的支持,并且可以在查询中添加分页与排序

    1. 单条件
            /**
             * Specification<Users>:用于封装查询条件
             */
            Specification<Users> spec = new Specification<Users>() {
                
                //Predicate:封装了 单个的查询条件
                /**
                 * Root<Users> root:查询对象的属性的封装。
                 * CriteriaQuery<?> query:封装了我们要执行的查询中的各个部分的信息,select  from order by
                 * CriteriaBuilder cb:查询条件的构造器。定义不同的查询条件
                 */
                @Override
                public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    // where name = '张三三'
                    /**
                     * 参数一:查询的条件属性
                     * 参数二:条件的值
                     */
                    Predicate pre = cb.equal(root.get("name"), "张三三");
                    return pre;
                }
            };
            List<Users> list = this.usersRepositorySpecification.findAll(spec);
            for (Users users : list) {
                System.out.println(users);
            }
    

    Specification<Users>:用于封装查询条件

    1. 多条件
      2.1 多条件写法一
      2.2 多条件写法二
    多条件写法一:
            /**
             * Specification<Users>:用于封装查询条件
             */
            Specification<Users> spec = new Specification<Users>() {
                
                //Predicate:封装了 单个的查询条件
                /**
                 * Root<Users> root:查询对象的属性的封装。
                 * CriteriaQuery<?> query:封装了我们要执行的查询中的各个部分的信息,select  from order by
                 * CriteriaBuilder cb:查询条件的构造器。定义不同的查询条件
                 */
                @Override
                public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    // where name = '张三三' and age = 20
                    List<Predicate> list = new ArrayList<>();
                    list.add(cb.equal(root.get("name"),"张三三"));
                    list.add(cb.equal(root.get("age"),20));
                    Predicate[] arr = new Predicate[list.size()];
                    return cb.and(list.toArray(arr));
                }
            };
            List<Users> list = this.usersRepositorySpecification.findAll(spec);
            for (Users users : list) {
                System.out.println(users);
            }
    
    多条件写法二:
    Specification<Users> spec = new Specification<Users>() {
                
                //Predicate:封装了 单个的查询条件
                /**
                 * Root<Users> root:查询对象的属性的封装。
                 * CriteriaQuery<?> query:封装了我们要执行的查询中的各个部分的信息,select  from order by
                 * CriteriaBuilder cb:查询条件的构造器。定义不同的查询条件
                 */
                @Override
                public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    // where name = '张三三' and age = 20
                    /*List<Predicate> list = new ArrayList<>();
                    list.add(cb.equal(root.get("name"),"张三三"));
                    list.add(cb.equal(root.get("age"),20));
                    Predicate[] arr = new Predicate[list.size()];*/
                    //(name = '张三' and age = 20) or id = 2
                    return cb.or(cb.and(cb.equal(root.get("name"),"张三三"),cb.equal(root.get("age"),20)),cb.equal(root.get("id"), 2));
                }
            };
            
            Sort sort = new Sort(new Order(Direction.DESC,"id"));
            List<Users> list = this.usersRepositorySpecification.findAll(spec,sort);
            for (Users users : list) {
                System.out.println(users);
            }
    
    1. 多条件加分页
      在findAll方法中,加上sort参数,spec参数照旧
            Specification<Users> spec = new Specification<Users>() {
                
                
                @Override
                public Predicate toPredicate(Root<Users> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    
                    
                    return cb.or(cb.and(cb.equal(root.get("name"),"张三三"),cb.equal(root.get("age"),20)),cb.equal(root.get("id"), 2));
                }
            };
            
            Sort sort = new Sort(new Order(Direction.DESC,"id"));
            List<Users> list = this.usersRepositorySpecification.findAll(spec,sort);
            for (Users users : list) {
                System.out.println(users);
            }
    


    4.关联映射

    1. 一对多关联映射

    多的一方:Users

    • 添加外键
    • 级联操作(新建用户时,可能会新建一个角色,需要添加级联操作,通过添加新角色信息到数据库中)

    单的一方:Roles

    • @OneToMany(mappedBy = "roles") 根据roles相同的属性,来添加users到Set集合中
        // 添加级联操作。 保存新用户,新用户中可能有新角色,级联保存新角色信息
        @ManyToOne(cascade = CascadeType.PERSIST)
        // 维护外键
        @JoinColumn(name = "roles_id")
        private Roles roles;
    
        @OneToMany(mappedBy = "roles")
        private Set<Users> users = new HashSet<>();
    

    保存操作与查询操作

        @Test
        public void testSave(){
            // 创建一个用户
            Users users = new Users();
            users.setAddress("天津");
            users.setAge(32);
            users.setName("小刚");
            // 创建一个角色
            Roles roles = new Roles();
            roles.setRolename("管理员");
            // 关联
            roles.getUsers().add(users);
            users.setRoles(roles);
            // 保存
            this.usersRepository.save(users);
        }
    
        @Test
        public void testFind(){
            Users findOne = this.usersRepository.findById(5).orElse(null);
            System.out.println(findOne);
            Roles roles = findOne.getRoles();
            System.out.println(roles.getRolename());
        }
    

    2. 多对多关联映射

        @ManyToMany(cascade=CascadeType.PERSIST,fetch=FetchType.EAGER)
        //@JoinTable:映射中间表
        //joinColumns:当前表中的主键所关联的中间表中的外键字段
        @JoinTable(name="t_roles_menus",joinColumns=@JoinColumn(name="role_id"),inverseJoinColumns=@JoinColumn(name="menu_id"))
        private Set<Menus> menus = new HashSet<>();
    
        @ManyToMany(mappedBy="menus")
        private Set<Roles> roles = new HashSet<>();
    

    相关文章

      网友评论

          本文标题:Spring Boot整合Spring Data JPA

          本文链接:https://www.haomeiwen.com/subject/jifvnctx.html