十次方学习——spring data(4)

一、spring data jpa 框架

  1. spring data 提供了基于 spring 的使用习惯(方式)来操作各种类型的数据,主要包括各种数据库及 no sql。因此它的适用面比 mybatis 大很多。
  2. 使用数据访问技术、关系和非关系数据库(no sql)、mapreduce 框架和基于云的数据库变得容易。这是一个伞形项目,其中包含许多特定与给定数据库的子项目。
  3. spring data 有很多子项目,其中 commons 和 jdbc 是基础,其他的针对应用的包括 jpa,mongodb,redis,elasticsearch 等。

二、jpa

  • jpa 是 java persistence api 也就是 java 持久化应用接口。javaEE 5.0 中出现的操作数据库的标准,它提供了多个接口,比如 @Table、@Id、@Column 等注解都属于该标准的内容。这些内容所在的包在 javax.persistence 中。在 spring boot 项目中如果引入了 spring data jpa 的启动器,该包就会被引用。
  • jpa 作为一种标准,被很多 orm 的框架所遵循,典型的是 hibernate 框架,另一个就是 spring data jpa, spring 是基于 java 语言的框架,所以它的 orm 框架遵循 jpa 标准是理所当然的。mybatis 并没有实现 jpa 标准。这两个框架各有千秋,mybatis 更优秀的在于书写复杂的查询:spring data jpa 更优秀在于通过方法名来生成不同的 sql。

三、spring data jpa 在 spring boot 中的使用

  1. 启动器 spring-boot-starter-data-jpa,基于启动器 spring,jdbc,spring orm,jpa 等相关的依赖都会被引入使用。

  2. 配置文件中,可以添加 spring.jpa 的相关配置内容:jpa:database:mysql。因为需要根据特定数据库生成 sql。

  3. 创建 pojo 类,需要添加 jpa 的 Entity,Table,Id 等注解。

  4. 建 dao 包,在包下建接口。

  5. 接口需要继承 JpaRepository 接口,该接口可以实现针对单表的几乎所有的 crud 操作,可以分页。还需要继承 JpaSpecificationExecutor 独立接口,它可以实现复杂条件的单表查询,也可以分页。

  6. 实现 service 类。

  7. 创建 controller 类,按照 api 文档书写各个请求处理方法。在控制器类中需要考虑跨域请求的问题,否则报错。解决办法:在控制器类上添加 @CrossOrigin 注解。

  8. 基于组合条件查询。

    • package com.tensquare.base.dao;
      
      import com.tensquare.base.pojo.Label;
      import org.springframework.data.jpa.repository.JpaRepository;
      import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
      
      /**
       * @author 华韵流风
       * @ClassName LabelDao
       * @Date 2021/9/17 17:11
       * @packageName com.tensquare.base.dao
       * @Description TODO
       */
      public interface LabelDao extends JpaRepository<Label,String>, JpaSpecificationExecutor<Label> {
              
              
      }
      
    • /**
       * 标签综合查询
       * 
       * @param label label
       * @return List<Label>
       */
      public List<Label> findByLabel(Label label) {
              
              
          List<Predicate> list = new ArrayList<>();
      
          return labelDao.findAll((Specification<Label>) (root, criteriaQuery, criteriaBuilder) -> {
              
              
              if (!StringUtils.isEmpty(label.getLabelname())) {
              
              
                  Predicate predicate = criteriaBuilder.like(root.get("labelname").as(String.class), "%" + label.getLabelname() + "%");
                  list.add(predicate);
              }
              if (!StringUtils.isEmpty(label.getState())) {
              
              
                  Predicate predicate = criteriaBuilder.like(root.get("state").as(String.class), "%" + label.getState() + "%");
                  list.add(predicate);
              }
              if (!StringUtils.isEmpty(label.getRecommend())) {
              
              
                  Predicate predicate = criteriaBuilder.like(root.get("recommend").as(String.class), "%" + label.getRecommend() + "%");
                  list.add(predicate);
              }
              if (!StringUtils.isEmpty(label.getId())) {
              
              
                  Predicate predicate = criteriaBuilder.like(root.get("id").as(String.class), "%" + label.getId() + "%");
                  list.add(predicate);
              }
              return criteriaBuilder.and(list.toArray(new Predicate[0]));
          });
      
      }
      
    • 基于组合条件的分页查询:

      • 分页查询只需要在方法中添加一个分页参数对象 Pageable,注意 jpa 中的页码是从 0 开始。

      • /**
         * 标签分页
         *
         * @param label label
         * @param page  page
         * @param size  size
         * @return Page<Label>
         */
        public Page<Label> findByLabelPage(Label label, int page, int size) {
                  
                  
            //jpa中的页码是从0开始,所以要减一。
            return labelDao.findAll(getSpecification(label), PageRequest.of(page - 1, size));
        }
        
  9. 自定义 Repository 方法。

    • 条件首字母大写
    • 列名首字母大写
    • 注意顺序
  10. 复杂查询

    • 对于多表的查询,比如多表的连接查询,另一种就是针对多表的子查询。实现方式主要是自己写 sql。

    • spring data jpa 写 sql 有两种方式:

      1. 面向对象的方式,写法称为 JPQL。

      2. 原生的 sql(推荐)。

        • package com.tensquare.qa.dao;
          
          import com.tensquare.qa.pojo.Problem;
          import org.springframework.data.domain.Pageable;
          import org.springframework.data.jpa.repository.JpaRepository;
          import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
          import org.springframework.data.jpa.repository.Query;
          import org.springframework.data.repository.query.Param;
          
          import java.util.List;
          
          /**
           * @author 华韵流风
           */
          public interface ProblemDao extends JpaRepository<Problem, String>, JpaSpecificationExecutor<Problem> {
                      
                      
          
              /**
               * 最新问答
               *
               * @param labelid  labelid
               * @param pageable pageable
               * @return List<Problem>
               */
              @Query(value = "select * from tb_problem p,tb_pl pl where p.id=pl.problemid and pl.labelid=?1 order by createtime desc", nativeQuery = true)
              List<Problem> findNewList(String labelid, Pageable pageable);
          
              /**
               * 热门问答
               *
               * @param labelid  labelid
               * @param pageable pageable
               * @return List<Problem>
               */
              @Query(value = "select * from tb_problem p,tb_pl pl where p.id=pl.problemid and pl.labelid=:labelid order by reply desc", nativeQuery = true)
              List<Problem> findHotList(@Param("labelid") String labelid, Pageable pageable);
          
              /**
               * 等待问答
               *
               * @param labelid  labelid
               * @param pageable pageable
               * @return List<Problem>
               */
              @Query(value = "select * from tb_problem p,tb_pl pl where p.id=pl.problemid and pl.labelid=:labelid and reply=0", nativeQuery = true)
              List<Problem> findWaitList(@Param("labelid") String labelid, Pageable pageable);
          }
          
          

四、使用 spring data redis 操作缓存

  1. 创建 redis 容器:docker run -di –-name=tensquare_redis -p 6379:6379 redis –restart=always。

  2. 引用启动器:

    • <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-redis</artifactId>
      </dependency>
      
  3. 在配置文件中配置 redis 服务器:

    • server:
        port: 9005
      spring:
        application:
          name: tensquare-article
        jpa:
          database: mysql
          show-sql: true
      
        datasource:
          username: root
          password: 123456
          url: jdbc:mysql://192.168.46.130:3306/tensquare_article?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false&useUnicode=true&allowMultiQueries=true
          driver-class-name: com.mysql.cj.jdbc.Driver
          hikari:
            maximum-pool-size: 5
            minimum-idle: 2
            idle-timeout: 2000
        redis:
          host: 192.168.46.130
          #port: 6379使用默认的端口可不写
      
  4. 使用:

    • package com.tensquare.article.service;
      
      import com.tensquare.article.dao.ArticleDao;
      import com.tensquare.article.pojo.Article;
      import com.tensquare.utils.IdWorker;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.data.redis.core.RedisTemplate;
      import org.springframework.stereotype.Service;
      import org.springframework.transaction.annotation.Transactional;
      
      import javax.annotation.Resource;
      import java.util.List;
      import java.util.concurrent.TimeUnit;
      
      /**
       * @author 华韵流风
       * @ClassName ArticleService
       * @Date 2021/9/18 14:09
       * @packageName com.tensquare.article.service
       * @Description TODO
       */
      @Service
      @Transactional(rollbackFor = Exception.class)
      public class ArticleService {
              
              
      
          @Autowired
          private ArticleDao articleDao;
      
          @Autowired
          private IdWorker idWorker;
      
          /**
           * 注入redis模板,这里若使用@Autowired注解则需要使用
           * 泛型的RedisTemplate。即不指定类型。
           */
          @Resource
          private RedisTemplate<String, Article>  redisTemplate;
      
          /**
           * 添加article
           *
           * @param article article
           */
          public void add(Article article) {
              
              
              article.setId(String.valueOf(idWorker.nextId()));
              articleDao.save(article);
          }
      
          /**
           * 根据id删除article
           *
           * @param id id
           */
          public void remove(String id) {
              
              
              articleDao.deleteById(id);
              redisTemplate.delete("article_" + id);
          }
      
          /**
           * 根据id修改article
           *
           * @param id      id
           * @param article article
           */
          public void update(String id, Article article) {
              
              
              article.setId(id);
              articleDao.save(article);
              redisTemplate.delete("article_" + id);
              redisTemplate.opsForValue().set("article_" + id, findById(id), 24 * 60 * 60, TimeUnit.SECONDS);
          }
      
          /**
           * 根据id查询article
           *
           * @param id id
           * @return Article
           */
          public Article findById(String id) {
              
              
              //从缓存中查找
              Article article = redisTemplate.opsForValue().get("article_" + id);
              if (article == null) {
              
              
                  article = articleDao.findById(id).get();
                  redisTemplate.opsForValue().set("article_" + id, article, 24 * 60 * 60, TimeUnit.SECONDS);
              }
              return article;
          }
      
          /**
           * 查询所有article
           *
           * @return List<Article>
           */
          public List<Article> findAll() {
              
              
              return articleDao.findAll();
          }
      }
      

猜你喜欢

转载自blog.csdn.net/qq_44628734/article/details/121053556