zoukankan      html  css  js  c++  java
  • springBoot整合JPA

    springBoot整合JPA

    JPA官网: https://docs.spring.io/spring-data/jpa/docs/2.3.1.RELEASE/reference/html/#jpa.repositories

    maven 依赖:

          <!--spring-data-jpa-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>

    yml:

    spring:
      application:
        name: jpa-study
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        druid:
          # mysql 8.0 以下
          # url: jdbc:mysql://localhost:3306/test?useSSL=false&characterEncoding=utf8&autoReconnect=true
          # driver-class-name: com.mysql.jdbc.Driver
          # mysql 8.0 以上使用
          url: jdbc:mysql://localhost:3306/my-study?useSSL=false&serverTimezone=GMT%2B8&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: root
          password: 123456
      jpa:
        hibernate:
    #      自动更新ddl-auto是hibernate的配置属性,其主要作用是:自动创建、更新、验证数据库表结构。该参数的几种配置如下:
          #    ·create:每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。
          #    ·create-drop:每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。
          #    ·update:最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据model类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等应用第一次运行起来后才会。
          #    ·validate:每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。
          ddl-auto: update
    #      开启驼峰_转换
          naming:
            physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
    #        日志中显示sql语
        show-sql: true

    新建实体Person类:

    @Entity
    @Data
    public class Person {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column(name = "name", length = 20)
        private String name;
    
        @Column(name = "age", length = 4)
        private int age;
    }

    @Entity 注解代表它是数据库持久化类

    @GeneratedValue作用:

     @GeneratedValue注解存在的意义主要就是为一个实体生成一个唯一标识的主键、@GeneratedValue提供了主键的生成策略。

    strategy属性:提供四种值:

    AUTO  主键由程序控制, 是默认选项 ,不设置就是这个
    IDENTITY 主键由数据库生成, 采用数据库自增长, Oracle不支持这种方式
    SEQUENCE 通过数据库的序列产生主键, MYSQL  不支持
    Table 提供特定的数据库产生主键, 该方式更有利于数据库的移植

    Dao:

    @Repository
    public interface PersonRepository extends JpaRepository<Person, Long> {
        
    }

    controller:

    @RestController
    public class PersonController {
    
        @Autowired
        private PersonRepository personRepository;
    
        /**
         * 新增
         * @param person
         */
        @PostMapping(path = "addPerson")
        public void addPerson(Person person) {
            personRepository.save(person);
        }
    
        /**
         * 删除
         * @param userId
         */
        @DeleteMapping(path = "deletePerson")
        public void deletePerson(Long userId) {
            //删除名字是张三的记录
            Person person = new Person();
            person.setName("张三");
            personRepository.delete(person);
    
            //删除主键是userId的记录(李四)
            personRepository.deleteById(userId);
        }
    
        /**
         * 查询
         * @return
         */
        @GetMapping("getPerson/{userId}")
        public Object getPerson(@PathVariable("userId") Long userId){
            Optional<Person> byId = personRepository.findById(userId);
    //        Person person = byId.get();
            return byId;
        }
    
        /**
         * 修改 save(String var1)
         * 添加和更新(修改)操作都是save(T t)方法,逻辑是根据主键判断的,如果数据库中有数据能匹配到参数中的主键,就更新匹配到的数据,否则就新添加。
         * @return
         */
        @PutMapping("update")
        public Object updatePerson(){
            Person person = new Person();
            person.setId(2L);
            person.setName("张三丰");
            return personRepository.save(person);
        }
    }

    自定义查询--根据方法名创建查询

    方法名称中受支持的关键字

    关键词示例JPQL片段

    And

    findByLastnameAndFirstname

    … where x.lastname = ?1 and x.firstname = ?2

    Or

    findByLastnameOrFirstname

    … where x.lastname = ?1 or x.firstname = ?2

    Is, Equals

    findByFirstnamefindByFirstnameIsfindByFirstnameEquals

    … where x.firstname = ?1

    Between

    findByStartDateBetween

    … where x.startDate between ?1 and ?2

    LessThan

    findByAgeLessThan

    … where x.age < ?1

    LessThanEqual

    findByAgeLessThanEqual

    … where x.age <= ?1

    GreaterThan

    findByAgeGreaterThan

    … where x.age > ?1

    GreaterThanEqual

    findByAgeGreaterThanEqual

    … where x.age >= ?1

    After

    findByStartDateAfter

    … where x.startDate > ?1

    Before

    findByStartDateBefore

    … where x.startDate < ?1

    IsNull, Null

    findByAge(Is)Null

    … where x.age is null

    IsNotNull, NotNull

    findByAge(Is)NotNull

    … where x.age not null

    Like

    findByFirstnameLike

    … where x.firstname like ?1

    NotLike

    findByFirstnameNotLike

    … where x.firstname not like ?1

    StartingWith

    findByFirstnameStartingWith

    … where x.firstname like ?1(参数附后%

    EndingWith

    findByFirstnameEndingWith

    … where x.firstname like ?1(带前缀的参数%

    Containing

    findByFirstnameContaining

    … where x.firstname like ?1(参数绑定在中%

    OrderBy

    findByAgeOrderByLastnameDesc

    … where x.age = ?1 order by x.lastname desc

    Not

    findByLastnameNot

    … where x.lastname <> ?1

    In

    findByAgeIn(Collection<Age> ages)

    … where x.age in ?1

    NotIn

    findByAgeNotIn(Collection<Age> ages)

    … where x.age not in ?1

    True

    findByActiveTrue()

    … where x.active = true

    False

    findByActiveFalse()

    … where x.active = false

    IgnoreCase

    findByFirstnameIgnoreCase

    … where UPPER(x.firstame) = UPPER(?1)

     

    使用  @Query

    使用@Query注解在接口方法之上自定义执行SQL。

    eg:

    public interface UserRepository extends JpaRepository<User, Long> {
    
      @Query("select u from User u where u.emailAddress = ?1 AND u.userName=?2")
      User findByEmailAddress(String emailAddress, String userName);
    }

    like @Query中的高级表达式

    public interface UserRepository extends JpaRepository<User, Long> {
    
      @Query("select u from User u where u.firstname like %?1")
      List<User> findByFirstnameEndsWith(String firstname);
    }

    本地查询

    该 @Query注释允许通过设定运行的原生查询 nativeQuery 标志设置为true,如图以下示例:

    nativeQuery 属性如果设置为 true 时,表示的意思是:可以执行原生sql语句,所谓原生sql,也就是说这段sql拷贝到数据库中,然后把参数值给一下就能运行了,原生的 sql 都是真实的字段,真实的表名。如果设置为 false 时,就不是原生的 sql ,而不是数据库对应的真正的表名,而是对应的实体名,并且 sql 中的字段名也不是数据库中真正的字段名,而是实体的字段名;

    public interface UserRepository extends JpaRepository<User, Long> {
    
      @Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
      User findByEmailAddress(String emailAddress);
    }

    通过使用以下方法在查询方法中声明本机计数查询以进行分页 @Query

    public interface UserRepository extends JpaRepository<User, Long> {
    
      @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
        countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
        nativeQuery = true)
      Page<User> findByLastname(String lastname, Pageable pageable);
    }

    使用排序

    排序可以通过提供PageRequestSort直接使用来完成

    修改查询

    @Modifying,如以下示例所示:

    删除查询

    复杂的条件查询以及分页、排序

    * 分页、排序、复杂条件查询
    * 在涉及到复杂的查询的时候,尤其是多条件查询的时候,如果通过命名方式实现,长长的方法名将是代码显得十分的不优雅。
    * 这个时候,大多数人会选择使用NativeQuery,通过编写SQL语句来实现,这种方式导致的结果就是项目代码中遍地是SQL,
    * 随着时间的推移,项目已经失去了使用JPA的初衷。能否有一种方式,在保障JPQL的风格里完成这种复杂的查询呢?
    * 这里介绍一种简单的方式:JpaSpecificationExecutor

    Dao层继承 JpaSpecificationExecutor<T>该接口允许基于JPA标准的API规范的运行。

    @Repository
    public interface PersonRepository extends JpaRepository<Person, Long>, JpaSpecificationExecutor<Person> {
        @Query("select p from Person AS p where  p.age < ?1")
        List<Person> findByAgeLessThan(Integer age, Pageable pageable);
    
    }

    Service:

    1: 简单的查询条件连接:

     @Override
        public Page<Person> findByPageAndParams(Person personParams, Integer startPage, Integer pageSize) {
            // 排序信息
            ///Sort.Direction是个枚举有ASC(升序)和DESC(降序),eg:按年龄age字段升序排序
            Sort ageSort = Sort.by(Sort.Direction.ASC, "age");
            //分页信息 注意JPA的page是从0开始算的,page传0,查询的是第1页的数据
            Pageable pageable = PageRequest.of(0, 10, ageSort);
            //查询条件构造
            Specification<Person> specification = new Specification<Person>() {
                @Override
                public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                    /**
                     * @param *root: 代表查询的实体类.
                     * @param query: 可以从中得到 Root 对象, 即告知 JPA Criteria 查询要查询哪一个实体类. 还可以
                     * 来添加查询条件, 还可以结合 EntityManager 对象得到最终查询的 TypedQuery 对象.
                     * @param *cb: CriteriaBuilder 对象. 用于创建 Criteria 相关对象的工厂. 当然可以从中获取到 Predicate 对象
                     * @return: *Predicate 类型, 代表一个查询条件.
                     */
                    Path<String> name = root.get("name");
                    Path<Integer> age = root.get("age");
                    Predicate like = criteriaBuilder.like(name, "%" + personParams.getName() + "%");
                    Predicate lt = criteriaBuilder.lt(age, personParams.getAge());
                    // 多个条件拼接起来
                    Predicate predicate = criteriaBuilder.and(like, lt);
                    return predicate;
                }
            };
            Page<Person> personPageList = personRepository.findAll(specification, pageable);
            return personPageList;
        }

    这里需要用到CriteriaBuilder提供的几个方法: 将多个条件(predicate)连接

     Predicate and(Predicate... restrictions);
     Predicate or(Predicate... restrictions);

    CriteriaQuery实现多条件组合

      public Page<Person> findByPageAndParams(Person personParams, Integer startPage, Integer pageSize) {
            // 排序信息
            ///Sort.Direction是个枚举有ASC(升序)和DESC(降序),eg:按年龄age字段升序排序
            Sort ageSort = Sort.by(Sort.Direction.ASC, "age");
            //分页信息 注意JPA的page是从0开始算的,page传0,查询的是第1页的数据
            Pageable pageable = PageRequest.of(0, 10, ageSort);
            //查询条件构造
            Specification<Person> specification = new Specification<Person>() {
                @Override
                public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                    /**
                     * @param *root: 代表查询的实体类.
                     * @param query: 可以从中得到 Root 对象, 即告知 JPA Criteria 查询要查询哪一个实体类. 还可以
                     * 来添加查询条件, 还可以结合 EntityManager 对象得到最终查询的 TypedQuery 对象.
                     * @param *cb: CriteriaBuilder 对象. 用于创建 Criteria 相关对象的工厂. 当然可以从中获取到 Predicate 对象
                     * @return: *Predicate 类型, 代表一个查询条件.
                     */
                    Path<Integer> id = root.get("id");
                    Path<String> name = root.get("name");
                    Path<Integer> age = root.get("age");
                    Predicate like = criteriaBuilder.like(name, "%" + personParams.getName() + "%");
                    Predicate lt = criteriaBuilder.lt(age, personParams.getAge());
                    // 多个条件拼接起来
                    Predicate predicate = criteriaBuilder.and(like, lt);
                    //添加where条件
                    criteriaQuery.where(predicate);
                    // //指定查询项,select后面的东西
                    criteriaQuery.multiselect(name,age,criteriaBuilder.count(id));
                    //分组
                    criteriaQuery.groupBy(id);
                    //排序
                    criteriaQuery.orderBy(criteriaBuilder.asc(id));
                    //筛选
                    criteriaQuery.having(criteriaBuilder.greaterThan(id,0));
                    //获取最终的Predicate
                    Predicate restriction = criteriaQuery.getRestriction();
                    return restriction;
                }
            };
            Page<Person> personPageList = personRepository.findAll(specification, pageable);
            return personPageList;
        }

    CriteriaQuery与entityManager整合

    @PersistenceContext
        private EntityManager entityManager;
    
        public List<Person> test(){
            CriteriaBuilder cb = entityManager.getCriteriaBuilder();
            //User指定了查询结果返回至自定义对象
            CriteriaQuery<Person> query = cb.createQuery(Person.class);
            Root<Person> root = query.from(Person.class);
            Path id = root.get("id");
            List<Predicate> predicates=new ArrayList<Predicate>();
            Predicate predicateId = cb.equal(id,1);
            predicates.add(predicateId);
            Path<Person> email = root.get("email");
            Predicate predicateEmail = cb.equal(email, "aa@qq.com");
            predicates.add(predicateEmail);
            Predicate endPredicate = cb.and(predicates.toArray(new Predicate[predicates.size()]));
            //添加where条件
            query.where(endPredicate);
            //指定查询项,select后面的东西
    //        query.multiselect(id,email);
            //分组
            query.groupBy(id);
            //排序
            query.orderBy(cb.asc(id));
            //筛选
            query.having(cb.greaterThan(id,0));
            TypedQuery<Person> q = entityManager.createQuery(query);
            List<Person> result = q.getResultList();
            for (Person person : result) {
                //打印查询结果
                System.out.println(person.toString());
            }
            return result;
        }

    动态sql构建

    public Page<Person> test2(Person personParams, Integer startPage, Integer pageSize) {
            // 排序信息
            ///Sort.Direction是个枚举有ASC(升序)和DESC(降序),eg:按年龄age字段升序排序
            Sort ageSort = Sort.by(Sort.Direction.ASC, "age");
            //分页信息 注意JPA的page是从0开始算的,page传0,查询的是第1页的数据
            Pageable pageable = PageRequest.of(0, 10, ageSort);
            //查询条件构造
            Specification<Person> specification = new Specification<Person>() {
                @Override
                public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                    /**
                     * @param *root: 代表查询的实体类.
                     * @param query: 可以从中得到 Root 对象, 即告知 JPA Criteria 查询要查询哪一个实体类. 还可以
                     * 来添加查询条件, 还可以结合 EntityManager 对象得到最终查询的 TypedQuery 对象.
                     * @param *cb: CriteriaBuilder 对象. 用于创建 Criteria 相关对象的工厂. 当然可以从中获取到 Predicate 对象
                     * @return: *Predicate 类型, 代表一个查询条件.
                     */
                    Path<String> name = root.get("name");
                    Path<Integer> age = root.get("age");
                    Predicate conjunction = criteriaBuilder.conjunction();
                    List<Expression<Boolean>> expressions = conjunction.getExpressions();
                    if(!StringUtils.isEmpty(name)){
                        expressions.add(
                                criteriaBuilder.and(criteriaBuilder.like(name, "%" + personParams.getName() + "%"))
                        );   
                    }
                    if (age != null) {
                        expressions.add(
                                criteriaBuilder.and(criteriaBuilder.lt(age, personParams.getAge()))
                        );
                    }
    
                    return conjunction;
                }
            };
            Page<Person> personPageList = personRepository.findAll(specification, pageable);
            return personPageList;
        }
  • 相关阅读:
    11月12号实验课
    10月29日实验
    10.15实验课作业
    Idea的使用和设置
    常用的Linux命令
    KAFKA总结
    SpringBoot+Maven+MyBaties+Mysql快速搭建一个项目
    Spring 常见面试
    Windows下安装ZK kafka Mysql dubbo redis
    MySQL常见的面试题
  • 原文地址:https://www.cnblogs.com/dw3306/p/13162537.html
Copyright © 2011-2022 走看看