zoukankan      html  css  js  c++  java
  • Spring Data

    Spring Data Jpa

    最近博主越来越懒了,深知这样不行。还是决定努力奋斗,如此一来,就有了一下一波复习

    演示代码都基于Spring Boot + Spring Data JPA 

    传送门: 博主的测试代码 

    ------------------------------------------------------------------------------------------------------------------------------

    什么是Spring Data JPA?

    Spring Data 是Spring提供的操作数据的框架在Spring data JPA是Spring data的一个模块,通过Spring data 基于jpa标准操作数据的模块。

    Spring Data的核心能力,就是基于JPA操作数据,并且可以简化操作持久层的代码。

    Spring Data JPA提供的核心接口

    前提数据:

    -- MySQL dump 10.13  Distrib 5.6.16, for debian-linux-gnu (x86_64)
    --
    -- Host: localhost    Database: amber
    -- ------------------------------------------------------
    -- Server version    5.6.16-1~exp1
    
    /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
    /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
    /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
    /*!40101 SET NAMES utf8 */;
    /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
    /*!40103 SET TIME_ZONE='+00:00' */;
    /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
    /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
    /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
    /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
    
    --
    -- Table structure for table `table_user`
    --
    
    DROP TABLE IF EXISTS `table_user`;
    /*!40101 SET @saved_cs_client     = @@character_set_client */;
    /*!40101 SET character_set_client = utf8 */;
    CREATE TABLE `table_user` (
      `id` int(11) NOT NULL DEFAULT '0',
      `name` varchar(255) DEFAULT NULL,
      `password` varchar(255) DEFAULT NULL,
      `address` varchar(255) DEFAULT NULL,
      `age` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
    /*!40101 SET character_set_client = @saved_cs_client */;
    
    --
    -- Dumping data for table `table_user`
    --
    
    LOCK TABLES `table_user` WRITE;
    /*!40000 ALTER TABLE `table_user` DISABLE KEYS */;
    INSERT INTO `table_user` VALUES (4,'tony',NULL,'shanghai',18),(5,'amber',NULL,'shanghai',18),(2,'amber1',NULL,'shanghai',18),(3,'tony',NULL,'shanghai',18),(0,'amber1',NULL,'shanghai',18),(6,'amber',NULL,'shanghai',18);
    /*!40000 ALTER TABLE `table_user` ENABLE KEYS */;
    UNLOCK TABLES;
    /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
    
    /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
    /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
    /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
    /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
    /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
    /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
    /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
    
    -- Dump completed on 2019-01-13 13:43:57
    SQL
    package com.amber.pojo;
    
    import lombok.Data;
    import javax.persistence.*;
    
    @Entity
    @Table(name = "table_user")
    @Data
    public class User {
    
        @Id
        @GeneratedValue
        private Integer id;
        private String name;
        private Integer age;
        private String address;
    
    
    }
    User
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>groupId</groupId>
        <artifactId>SpringBoot-JPA</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <properties>
            <java.version>1.8</java.version>
            <lombok.version>1.16.20</lombok.version>
        </properties>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.5.RELEASE</version>
            <relativePath/>
        </parent>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <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>
    
            <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>6.0.5</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <optional>true</optional>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.8</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
                <scope>provided</scope>
            </dependency>
        </dependencies>
    </project>
    pom.xml

    Repository:

    @org.springframework.stereotype.Repository
    public interface UserRepository  extends Repository<User, Integer> {
    }
    • 提供了方法名成查询方式: 

        方法的名称要遵循 findBy + 属性名(首字母大写) + 查询条件(首字母大写 Is Equals)

         findByNameLike(String name)

        findByName(String name)

        findByNameAndAge(String name, Integer age)

        findByNameOrAddress(String name) 等...

    • 基于@Query注解的查询和更新
     /**
         * SQL nativeQuery的值是true 执行的时候不用再转化
         * @param name
         * @return
         */
        @Query(value = "SELECT * FROM table_user WHERE name = ?1", nativeQuery = true)
        List<User> findByUsernameSQL(String name);

      //基于HQL

        /**
         * 基于HQL
         * @param name
         * @param id
         * @return
         */
        @Query("Update User set name = ?1 WHERE id = ?2")
        @Modifying
        int updateNameAndId(String name, Integer id);

    CrudReposiroty : 继承了Repository

    /*
     * Copyright 2008-2017 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package org.springframework.data.repository;
    
    import java.util.Optional;
    
    /**
     * Interface for generic CRUD operations on a repository for a specific type.
     * 
     * @author Oliver Gierke
     * @author Eberhard Wolff
     */
    @NoRepositoryBean
    public interface CrudRepository<T, ID> extends Repository<T, ID> {
    
        /**
         * Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
         * entity instance completely.
         * 
         * @param entity must not be {@literal null}.
         * @return the saved entity will never be {@literal null}.
         */
        <S extends T> S save(S entity);
    
        /**
         * Saves all given entities.
         * 
         * @param entities must not be {@literal null}.
         * @return the saved entities will never be {@literal null}.
         * @throws IllegalArgumentException in case the given entity is {@literal null}.
         */
        <S extends T> Iterable<S> saveAll(Iterable<S> entities);
    
        /**
         * Retrieves an entity by its id.
         * 
         * @param id must not be {@literal null}.
         * @return the entity with the given id or {@literal Optional#empty()} if none found
         * @throws IllegalArgumentException if {@code id} is {@literal null}.
         */
        Optional<T> findById(ID id);
    
        /**
         * Returns whether an entity with the given id exists.
         * 
         * @param id must not be {@literal null}.
         * @return {@literal true} if an entity with the given id exists, {@literal false} otherwise.
         * @throws IllegalArgumentException if {@code id} is {@literal null}.
         */
        boolean existsById(ID id);
    
        /**
         * Returns all instances of the type.
         * 
         * @return all entities
         */
        Iterable<T> findAll();
    
        /**
         * Returns all instances of the type with the given IDs.
         * 
         * @param ids
         * @return
         */
        Iterable<T> findAllById(Iterable<ID> ids);
    
        /**
         * Returns the number of entities available.
         * 
         * @return the number of entities
         */
        long count();
    
        /**
         * Deletes the entity with the given id.
         * 
         * @param id must not be {@literal null}.
         * @throws IllegalArgumentException in case the given {@code id} is {@literal null}
         */
        void deleteById(ID id);
    
        /**
         * Deletes a given entity.
         * 
         * @param entity
         * @throws IllegalArgumentException in case the given entity is {@literal null}.
         */
        void delete(T entity);
    
        /**
         * Deletes the given entities.
         * 
         * @param entities
         * @throws IllegalArgumentException in case the given {@link Iterable} is {@literal null}.
         */
        void deleteAll(Iterable<? extends T> entities);
    
        /**
         * Deletes all entities managed by the repository.
         */
        void deleteAll();
    }
    CrudRepository

    Crud主要是添加了对数据的增删改查的方法

    PagingAndSortingRepository: 继承了CrudRepository

    /*
     * Copyright 2008-2010 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package org.springframework.data.repository;
    
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.domain.Sort;
    
    /**
     * Extension of {@link CrudRepository} to provide additional methods to retrieve entities using the pagination and
     * sorting abstraction.
     * 
     * @author Oliver Gierke
     * @see Sort
     * @see Pageable
     * @see Page
     */
    @NoRepositoryBean
    public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
    
        /**
         * Returns all entities sorted by the given options.
         * 
         * @param sort
         * @return all entities sorted by the given options
         */
        Iterable<T> findAll(Sort sort);
    
        /**
         * Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object.
         * 
         * @param pageable
         * @return a page of entities
         */
        Page<T> findAll(Pageable pageable);
    }
    PagingAndSortingRepository
    /**
     * 继承了Repository,缺点只能对所有的数据进行排序或者分页
     */
    @Repository
    public interface UserPagingAndSortingReposiroty extends PagingAndSortingRepository<User, Integer> {
    }
    package com.amber;
    
    import com.amber.pojo.User;
    import com.amber.repository.UserPagingAndSortingReposiroty;
    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.data.domain.Page;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.domain.Sort;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import java.util.List;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest(classes = JPAApplication.class)
    public class UserPagingAndSortingReposirotyTest {
    
        @Autowired
        UserPagingAndSortingReposiroty userPagingAndSortingReposiroty;
    
        /**
         * 排序
         */
        @Test
        public void TestSort(){
            //定义排序规则
            Sort.Order order = new Sort.Order(Sort.Direction.DESC, "name");
            Sort.Order order1 = new Sort.Order(Sort.Direction.DESC, "id");
            //Sort
            Sort sort = new Sort(order, order1);
            List<User> users = (List<User>)userPagingAndSortingReposiroty.findAll(sort);
            System.out.println(users);
        }
    
        /**
         * 分页Pageable封装了分页的参数,当前页,每一页显示的条数,注意当前页是从0开始的
         */
        @Test
        public void TestPaging(){
            //Pageable是个接口
            Pageable pageable = new PageRequest(0, 10);
            //返回Page对象
            Page<User> uses = userPagingAndSortingReposiroty.findAll(pageable);
            System.out.println(uses.getTotalElements());
            System.out.println(uses.getTotalPages());
            System.out.println(uses.getNumberOfElements());
        }
    
        /**
         * 分页 + 排序
         */
        @Test
        public void TestPagingAndSort(){
            //定义排序规则
            Sort.Order order = new Sort.Order(Sort.Direction.DESC, "name");
            Sort.Order order1 = new Sort.Order(Sort.Direction.DESC, "id");
            //Sort
            Sort sort = new Sort(order, order1);
            //Pageable是个接口
            Pageable pageable = new PageRequest(0, 10, sort);
            //返回Page对象
            Page<User> uses = userPagingAndSortingReposiroty.findAll(pageable);
            System.out.println(uses.getTotalElements());
            System.out.println(uses.getTotalPages());
            System.out.println(uses.getNumberOfElements());
        }
    
    }
    UserPagingAndSortingReposirotyTest

    JPARepository: 继承了PagingAndSortingRepository接口

    在开发中常用JPARepository

    优点: 对继承父接口中方法的返回值进行了适配,因为在父类接口中通常都返回迭代器,需要我们自己进行强制类型转化。而在JpaRepository中,直接返回了List

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package org.springframework.data.jpa.repository;
    
    import java.util.List;
    import org.springframework.data.domain.Example;
    import org.springframework.data.domain.Sort;
    import org.springframework.data.repository.NoRepositoryBean;
    import org.springframework.data.repository.PagingAndSortingRepository;
    import org.springframework.data.repository.query.QueryByExampleExecutor;
    
    @NoRepositoryBean
    public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
        List<T> findAll();
    
        List<T> findAll(Sort var1);
    
        List<T> findAllById(Iterable<ID> var1);
    
        <S extends T> List<S> saveAll(Iterable<S> var1);
    
        void flush();
    
        <S extends T> S saveAndFlush(S var1);
    
        void deleteInBatch(Iterable<T> var1);
    
        void deleteAllInBatch();
    
        T getOne(ID var1);
    
        <S extends T> List<S> findAll(Example<S> var1);
    
        <S extends T> List<S> findAll(Example<S> var1, Sort var2);
    }
    JpaRepository

    JpaSpecificationExecutor: 这个接口单独存在,没有继承以上说的接口

    主要提供了多条件查询的支持,并且可以在查询中添加分页和排序。

    因为这个接口单独存在,因此需要配合以上说的接口使用,如:

    /**
     * JpaSpecificationExecutor是单独存在的,需要配合这JpaRepository一起使用
     */
    @Repository
    public interface UserJpaSpecificationExecutor extends JpaSpecificationExecutor<User>, JpaRepository<User, Integer> {
    }

    package com.amber;
    
    import com.amber.pojo.User;
    import com.amber.repository.UserJpaSpecificationExecutor;
    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.data.jpa.domain.Specification;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import javax.persistence.criteria.CriteriaBuilder;
    import javax.persistence.criteria.CriteriaQuery;
    import javax.persistence.criteria.Predicate;
    import javax.persistence.criteria.Root;
    import java.util.ArrayList;
    import java.util.List;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest(classes = JPAApplication.class)
    public class UserJpaSecificationExecutorTest {
    
        @Autowired
        UserJpaSpecificationExecutor userJpaSpecificationExecutor;
    
        /**
         * 多条件查询的另外一种写法
         */
        @Test
        public void testUser2(){
            //Specification是个接口,封装了查询信息
            Specification<User> specification = new Specification<User>() {
                /**
                 * Predicate封装了单个查询条件
                 * @param root 对查询对象属性的封装,比如我们这里是查询User,因此root可以看成是User
                 * @param query CriteriaQuery封装了查询中的各部分信息, Select from order
                 * @param cb CB查询条件的构造器
                 * @return
                 */
                @Override
                public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    Predicate p1 = cb.equal(root.get("name"), "amber");
                    Predicate p2 = cb.equal(root.get("age"), "18");
                    return cb.and(p1,p2);
                }
            };
            List<User> users = userJpaSpecificationExecutor.findAll(specification);
            System.out.println(users);
        }
    
        /**
         * 多条件查询
         */
        @Test
        public void testUser1(){
            //Specification是个接口,封装了查询信息
            Specification<User> specification = new Specification<User>() {
                /**
                 * Predicate封装了单个查询条件
                 * @param root 对查询对象属性的封装,比如我们这里是查询User,因此root可以看成是User
                 * @param query CriteriaQuery封装了查询中的各部分信息, Select from order
                 * @param cb CB查询条件的构造器
                 * @return
                 */
                @Override
                public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    List<Predicate> predicates = new ArrayList<>();
                    Predicate p1 = cb.equal(root.get("name"), "amber");
                    Predicate p2 = cb.equal(root.get("age"), "18");
                    predicates.add(p1);
                    predicates.add(p2);
                    Predicate[] predicateArr = new Predicate[predicates.size()];
                    return cb.and(predicates.toArray(predicateArr));
                }
            };
            List<User> users = userJpaSpecificationExecutor.findAll(specification);
            System.out.println(users);
        }
    
        /**
         * 单条件查询
         */
        @Test
        public void testUser(){
            //Specification是个接口,封装了查询信息
            Specification<User> specification = new Specification<User>() {
                /**
                 * Predicate封装了单个查询条件
                 * @param root 对查询对象属性的封装,比如我们这里是查询User,因此root可以看成是User
                 * @param query CriteriaQuery封装了查询中的各部分信息, Select from order
                 * @param cb CB查询条件的构造器
                 * @return
                 */
                @Override
                public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
    
                    Predicate p1 = cb.equal(root.get("name"), "amber");
                    return p1;
                }
            };
            List<User> users = userJpaSpecificationExecutor.findAll(specification);
            System.out.println(users);
        }
    }
    View Code

    总结:

      Spring Data Jpa中一共提供了

    • Repository:
      •   提供了findBy + 属性方法 
      •   @Query 
        •   HQL: nativeQuery 默认false
        •   SQL: nativeQuery 默认true
          • 更新的时候,需要配合@Modifying使用
    • CurdRepository:
      • 继承了Repository 主要提供了对数据的增删改查
    • PagingAndSortRepository:
      • 继承了CrudRepository 提供了对数据的分页和排序,缺点是只能对所有的数据进行分页或者排序,不能做条件判断
      JpaRepository: 继承了PagingAndSortRepository
      • 开发中经常使用的接口,主要继承了PagingAndSortRepository,对返回值类型做了适配
    • JpaSpecificationExecutor
      • 提供多条件查询
  • 相关阅读:
    Tomcat部署项目
    正则表达式
    文件的上传和下载
    实现扫码登陆
    onepill Android端
    部署SpringBoot到阿里云
    Gson
    HTML自动刷新页面
    Spring Data JPA根据属性名查询
    Spring Date JPA实现增删改查
  • 原文地址:https://www.cnblogs.com/amberbar/p/10261599.html
Copyright © 2011-2022 走看看