Spring Boot 入门

Spring Boot 入门

Maven安装

在IDE使用idea的情况下,开发SpringBoot项目是需要使用maven的。具体的使用方法如下:

  1. 下载安装和配置环境:去maven的官网下载,然后安装好在本地,配置好环境。这里有一个教程可以参考:https://juejin.im/post/5b02d829518825426e024215。对于Win 10的用户来说,这个有个坑需要注意:maven安装配置完后在cmd界面输入mvn -v检查,环境是否配置好了。在写配置maven的PATH路径的时候,如果是win10系统,切记切记不要加分号;,直接在路径PATH中新增一条写上%MAVEN_HOME%in即可。配置完后,关掉cmd窗口再打开,输入mvn -v,如果有maven相关信息返回即表示maven安装好,环境配置成功了。

  2. 给idea设置maven环境。通过在idea的settings中输入Maven找到设置项。给其中的Maven home directory设置为下载安装好的maven的地址(比如:C:/Program Files/Java/maven/apache-maven-3.6.3)。然后下面的User settings file建议设置为默认(即:C:UsersNim.m2settings.xml),不要Override,因为idea会默认调用maven地址里conf文件夹中settings.xml文件,所以不需要专门找个地方设置settings文件,需要修改settings.xml文件也只需要去maven文件夹中的conf文件夹里面找到settrings.xml进行修改即可。Local repository建议设置为默认,不要Override,因为idea似乎有时对自定义的repository支持不友好,使用自己新建的repository文件夹会没办法识别,所以为了保险起见建议直接默认,不要修改,让下载的jar都在.m2文件夹中,一般来说问题也不大。

  3. maven镜像加速:中央仓库的镜像拉取速度有时会非常慢,所以可以通过以下两步加速(实际使用的时候阿里云的仓库会有各种各样资源缺失的问题......而中央仓库虽然慢,但是全)(需要注意一下,如果有多个mirror,那么只有第一个mirror会有用):

    1. 中央仓库mirror:

      <mirror>
          <id>mirrorId</id>
          <mirrorOf>central</mirrorOf>
          <name>Human Readable Name for this Mirror.</name>
          <url>http://central.maven.org/maven2/</url>
      </mirror>
      
    2. 阿里云mirror-修改maven根目录下的conf文件夹中的setting.xml文件,内容如下:

      <mirrors>
          <mirror>
            <id>alimaven</id>
            <name>aliyun maven</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
            <mirrorOf>central</mirrorOf>        
          </mirror>
        </mirrors>
      
    3. 阿里云mirror-pom.xml文件里添加

      <repositories>  
              <repository>  
                  <id>alimaven</id>  
                  <name>aliyun maven</name>  
                  <url>http://maven.aliyun.com/nexus/content/groups/public/</url>  
                  <releases>  
                      <enabled>true</enabled>  
                  </releases>  
                  <snapshots>  
                      <enabled>false</enabled>  
                  </snapshots>  
              </repository>  
      </repositories>  
      

这里稍微注意一下,因为2020年1月15日maven的中央仓库从http转换为https,会导致501错误,所以仓库的地址需要变一下。可以在seeting.xml文件中将仓库的mirror改为:

<mirror>
  <id>mirrorId</id>
  <mirrorOf>central</mirrorOf>
  <name>Human Readable Name for this Mirror.</name>
  <url>http://insecure.repo1.maven.org/maven2/</url>
</mirror>

这个问题的具体情况查看请点击我

使用Intellij IDEA创建SpringBoot项目

直接创建一个springboot的demo能够快速加深对springboot使用的熟悉程度,具体见:使用Intellij IDEA创建SpringBoot项目

Hibernate常用注解含义

Hibernate的Annotation注解

  1. 声明实体(Entity)

    1. @Entity:对实体注释。任何Hibernate映射对象都要有这个注释
    2. @Table:声明此对象映射到数据库的数据表,通过它可以为实体指定表(talbe),目录(Catalog)和schema的名字。该注释不是必须的,如果没有则系统使用默认值(实体的短类名)。
    3. @Version:该注释可用于在实体Bean中添加乐观锁支持。
  2. 声明主键

    1. @Id:声明此属性为主键。该属性值可以通过应用自身创建,但是Hibernate推荐通过Hibernate生成
    2. @GeneratedValue:指定的

Swagger 2

这个工具可以帮助前后端分离,分离后的前后端交流的数据格式一般是JSON,后端返给前端的数据应该是有DTO包装为JSON格式才对。Swagger 2工具能够具象化前后端交流的所有端口和数据。

其中Swagger 2的默认访问地址如下:

  1. boot工程格式:http://10.166.10.169:8085/swagger-ui.html
  2. 非boot工程加个自己项目名:http://10.166.10.169:8085/xxx/swagger-ui.html

Lombok使用

这个工具可以简化操作,使用时需要在idea的Plugins里面安装一下lombok的插件。具体的安装教程见:Intellij IDEA 安装lombok及使用详解

安装过程中可能会在idea中找不到任何插件,解决方法为:IDEA Plugins中搜索不到任何插件解决办法

其中的注解介绍见:lombok注解介绍

使用@Scheduled创建定时任务

Spring Boot中使用@Scheduled创建定时任务

将Spring Boot项目打包成jar包部署到Linux服务器持久运行

  1. Linux服务器安装JDK环境在CentOS7.4中安装jdk的几种方法及配置环境变量

    1. 背景

      因为Spring Boot中默认带有Tomcat,所以只需要在Linux服务器端配置好JDK即可直接运行,不需要在服务器再次安装Tomcat。

    2. 步骤

      1. 查看当前系统jdk的版本:java -version
      2. 安装需要的jdk版本的所有java程序:yum -y install java-1.8.0-openjdk*
      3. 查看java版本:java -version
    3. 通过idea将现有的spring boot项目打包成jar包

      1. idea打开项目
      2. 打开maven的管理器,通过maven里面的“Lifecycle”、“install”自动将现有的项目打包成jar包
      3. 在project的项目层级目录下的target文件夹下的jar包即为打包好的本项目jar包
    4. 将本地jar包上传到云端Linux服务器

      1. 下载一个Xftp工具(官网有教育版可免费使用)
      2. 通过Xftp连接服务器端,将打包好的jar包上传到服务器
    5. 持久运行jar包

      1. 背景知识:运行时,如果仅仅使用java -jar xxx.jar运行,那么当控制台关闭后,jar包就会停止运行,所以我们需要后台持久运行jar包,保证任何时候都可以使用jar包提供的功能。

      2. 一些简单的Linux操作命令

        1. 执行jar包的命令和在windows操作系统上是一样的,都是java -jar xxxx.jar。

        2. 将jar程序设置成后台运行,并且将标准输出的日志重定向至文件consoleMsg.log。

          nohup java -jar xxx.jar >temp.txt 2>&1 &

        3. 如果想杀掉运行中的jar程序,查看进程命令为:

          ps aux|grep xxx.jar

          将会看到此jar的进程信息

          root 1082 0.1 12.6 2555644 237984 ? Sl Sep25 2:42 java -jar /project/k12-qhelp-error-book-back-end-0.0.1-SNAPSHOT.jar

          其中1082则为此jar的pid,杀掉命令为

          kill -9 1082

      3. 遇到Unable to access jar file xxx.jar问题的处理办法

        1. 运行JAR文件时需要指定路径,否则会出现如标题所示的提示。所以想要运行F:/myexamples/Hello.jar,如果当前不在F:/myexamples目录下,那么需要这样调用:java -jar F:/myexamples/Hello.jar。
    6. 上传用到的一些命令解释

      1. 上传jar到服务器

        java -jar shareniu.jar

        特点:当前ssh窗口被锁定,可按CTRL + C打断程序运行,或直接关闭窗口,程序退出

        java -jar shareniu.jar &

        &代表在后台运行。

        特点:当前ssh窗口不被锁定,但是当窗口关闭时,程序中止运行。

        nohup java -jar shareniu.jar &

        nohup 意思是不挂断运行命令,当账户退出或终端关闭时,程序仍然运行

        当用 nohup 命令执行作业时,缺省情况下该作业的所有输出被重定向到nohup.out的文件中,除非另外指定了输出文件。

        nohup java -jar shareniu.jar >temp.txt &

        将command的输出重定向到temp.file文件,即输出内容不打印到屏幕上,而是输出到temp.file文件中。

    7. 开放服务器的安全组端口

      1. 假设当前jar包的端口为9010,则需要在安全组中开放9010的端口
    8. 访问swagger

      1. 访问格式:服务器ip:启动端口/swagger-ui.html
      2. 使用http://xxx.xxx.xxx.xxx:9010/swagger-ui.html访问服务

Windows上遇到端口占用问题的解决办法

  1. 进入cmd界面
  2. 通过如下命令查询所有端口的占用情况:netstat -ano
  3. 通过如下命令,以PID(例如1234)来杀掉进程:taskkill /pid 1234 /f
  4. (可选)通过如下命令,以PID(例如1234)查看占用端口的程序的名称:tasklist | findstr "1234"

springboot的类没有启动按钮

解决方法:右键项目,选择“Mark Directiory as”,选择“Generated Sources Root”。

理由:idea需要自己构建项目结构

HTTP

在和Spring Boot中用restTemplate访问https的时候,可能会遇到被阻挡访问的问题。(问题解决方法:springboot restTemplate 访问某些网站的时候碰到 unable to find valid certification path to requested target,解决方法原始来源:How to disable SSL certificate checking with Spring RestTemplate?)

这个时候创建一个工具类:

/**
 * @author Nim
 * @DateTime 2020/2/6 17:32
 * @using 关闭SSL关于HTTPS的阻挡,让HTTPS能够通过testTemplate的验证
 */
public final class SSLUtil{

    private static final TrustManager[] UNQUESTIONING_TRUST_MANAGER = new TrustManager[]{
            new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers(){
                    return null;
                }
                public void checkClientTrusted(X509Certificate[] certs, String authType ){}
                public void checkServerTrusted( X509Certificate[] certs, String authType ){}
            }
    };

    public  static void turnOffSslChecking() throws NoSuchAlgorithmException, KeyManagementException {
        // Install the all-trusting trust manager
        final SSLContext sc = SSLContext.getInstance("SSL");
        sc.init( null, UNQUESTIONING_TRUST_MANAGER, null );
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }

    public static void turnOnSslChecking() throws KeyManagementException, NoSuchAlgorithmException {
        // Return it to the initial state (discovered by reflection, now hardcoded)
        SSLContext.getInstance("SSL").init( null, null, null );
    }

    private SSLUtil(){
        throw new UnsupportedOperationException( "Do not instantiate libraries.");
    }
}

在需要放开https访问阻拦的时候调用一下就能使https可用:

SSLUtil.turnOffSslChecking();

错误代码

JPA

概念简介

Java持久性API(JPA)是Java的一个规范。 它用于在Java对象和关系数据库之间保存数据。 JPA充当面向对象的领域模型和关系数据库系统之间的桥梁。
由于JPA只是一个规范,它本身不执行任何操作。 它需要一个实现。 因此,像Hibernate,TopLink和iBatis这样的ORM工具实现了JPA数据持久性规范。

查询

JPA级联查询

使用repository里面的@query注释,自己写hql语句(推荐),亦可使用原生sql语句。

update

spring使用jpa进行update操作主要有两种方式

注意一定要写@Transactional和@Modifying(clearAutomatically = true)这两个标签,没它们会报错

@MappedSuperclass

通过继承父类Entity减少子类Entity间的冗余代码

在使用lombok的情况在,在父类entity的class上标注@MappedSuperclass和@Data,同时子类通过extends继承父类,即可使用父类的属性。

@MappedSuperclass注解只能标准在类上:

  1. 标注为@MappedSuperclass的类将不是一个完整的实体类,他将不会映射到数据库表,但是他的属性都将映射到其子类的数据库字段中。
  2. 标注为@MappedSuperclass的类不能再标注@Entity或@Table注解,也无需实现序列化接口。但是如果一个标注为@MappedSuperclass的类继承了另外一个实体类或者另外一个同样标注了@MappedSuperclass的类的话,他将可以使用@AttributeOverride或@AttributeOverrides注解重定义其父类(无论是否是实体类)的属性映射到数据库表中的字段。比如可以重定义字段名或长度等属性,使用@AttributeOverride中的子属性@Column进行具体的定义。

注意:对于其父类中标注@Lob注解的属性将不能重载,并且@AttributeOverride里的@Column设置都将不起作用。

JPA规范中对@Lob注解并没有说明不能同时标注@Column注解,但是在实际使用中Hibernate JPA不支持这中标注方式。

  1. 此外,这样的类还可以直接标注@EntityListeners实体监听器,他的作用范围仅在其所有继承类中,并且实体监听器同样可以保被其子类继承或重载。
  2. 标注为@MappedSuperclass的类其属性最好设置为protected或default类型的,以保证其同一个包下的子类可以直接调用它的属性。便于实体监听器或带参数构造函数的操作。

JPA手工对ArrayList进行分页的算法

概述

系统与系统之间的交互,通常是使用接口的形式。假设B系统提供了一个批量的查询接口,限制每次只能查询50条数据,而我们实际需要查询500条数据,这个时候可以对这500条数据做分批操作,分10次调用B系统的批量接口。

如果B系统的查询接口是使用List作为入参,那么要实现分批调用的话,可以利用ArrayList的subList方法来处理。

代码

sublist方法的定义:

List<E> subList(int fromIndex, int toIndex);

只要准确算出fromIndex和toIndex即可。

数据准备

public class TestArrayList {
    public static void main(String[] args) {
        List<Long> datas = Arrays.asList(new Long [] {1L,2L,3L,4L,5L,6L,7L});
    }
}

分页算法

import java.util.Arrays;
import java.util.List;

public class TestArrayList {
    private static final Integer PAGE_SIZE = 3;
    public static void main(String[] args) {
        List<Long> datas = Arrays.asList(new Long [] {1L,2L,3L,4L,5L,6L,7L,8L});

        //总记录数
        Integer totalCount = datas.size();

        //分多少次处理
        Integer requestCount = totalCount / PAGE_SIZE;

        for (int i = 0; i <= requestCount; i++) {
            Integer fromIndex = i * PAGE_SIZE;
            //如果总数少于PAGE_SIZE,为了防止数组越界,toIndex直接使用totalCount即可
            int toIndex = Math.min(totalCount, (i + 1) * PAGE_SIZE);
            List<Long> subList = datas.subList(fromIndex, toIndex);
            System.out.println(subList);
            //总数不到一页或者刚好等于一页的时候,只需要处理一次就可以退出for循环了
            if (toIndex == totalCount) {
                break;
            }
        }

    }
}

测试场景

  1. 总数不足一页
  2. 总数刚好等于一页
  3. 总数多余一页

上面三个case都可以正常通过。

Spring中常用的注解

当项目变得比较大的时候,如果还使用hbm.xml文件来配置Hibernate实体就会变得比较复杂。这里Hibernate提供了Annotation注解方式,使得Hibernate的映射文件变得很方便管理。

  1. 声明实体
    1. @Enttity:对实体进行注解。任何Hibernate映射对象都要有这个注解。
    2. @Table:声明此对象映射到数据库的数据表,通过它可以为实体指定表(table),目录(ctalog)和schema的名字。该注解不是必须的,如果没有则系统使用默认值(实体类的短类名)。
    3. @Version:该注解可用于在实体Bean中添加乐观锁支持。
  2. 声明主键
    1. @Id:声明此属性为主键。
    2. @GeneratedValue:指定主键的生成策略。(包含:TABLE, IDENTITY, SEQUENCR, AUTO)
  3. 声明普通属性
    1. @Column:声明该属性与数据库字段的映射关系
  4. 声明关联关系
    1. @Repositoty:
    2. @Service、@Controller和@Component将类标识为Bean(Spring 2.5在@Repositoty的基础上增加了功能类似的额外三个注解:@Service、@Controller和@Component,他们分别用于软件系统的不同层次)(Spring Boot中的层次关系为:controller->services->repository)
      1. @Component:一个泛化的概念,仅仅表示一个组件(Bean),可以作用在任何层次。
      2. @Service:通常作用在业务层,但是目前该功能与@Component相同
      3. @Controller:通常作用在控制层,但是目前该功能与@Component相同

理解JPA注解@GeneratedValue

  1. JPA通用策略生成器

    通过annotation来映射hibernate实体的,基于annotation的hibernate主键标识为@Id,其生成规则由@GeneratedValue设定的.这里的@id和@GeneratedValue都是JPA的标准用法,JPA提供四种标准用法,分别为TABLE,SEQUENCE,IDENTITY,AUTO。

  2. Hibernate主键策略生成器

    hibernate提供多种主键生成策略,有点是类似于JPA,有的是hibernate特有,下面列出几个Hibernate比较常用的生成策略:

    • native: 对于 oracle 采用 Sequence 方式,对于MySQL 和 SQL Server 采用identity(自增主键生成机制),native就是将主键的生成工作交由数据库完成,hibernate不管
    • uuid: 采用128位的uuid算法生成主键,uuid被编码为一个32位16进制数字的字符串。占用空间大(字符串类型)。
    • assigned: 在插入数据的时候主键由程序处理(即程序员手动指定),这是 <generator>元素没有指定时的默认生成策略。等同于JPA中的AUTO。
    • identity: 使用SQL Server 和 MySQL 的自增字段,这个方法不能放到 Oracle 中,Oracle 不支持自增字段,要设定sequence(MySQL 和 SQL Server 中很常用)。 等同于JPA中的INDENTITY。
    • increment: 插入数据的时候hibernate会给主键添加一个自增的主键,但是一个hibernate实例就维护一个计数器,所以在多个实例运行的时候不能使用这个方法。

    hibernate提供了多种生成器供选择,基于Annotation的方式通过@GenericGenerator实现。hibernate每种主键生成策略提供接口org.hibernate.id.IdentifierGenerator的实现类,如果要实现自定义的主键生成策略(比如SnowFlake ID)也必须实现此接口。

ID设置

@GeneratorValue与@GenericGenerator注解使用心得

排序

Redis

Redis概念

Redis和MongoDB这两个是内存数据库,而MySQL是存储在磁盘的持久层数据库。随着MySQL的磁盘IO速度成为数据库的瓶颈,这个时候可以开一个Redis数据库,在内存做直接的IO操作,进行IO操作时直接在内存进行,当系统处于空闲时,再将数据写入MySQL中,增加整体的数据IO效率。

NoSQL技术

Redis一种基于内存的数据库,并且提供一定的持久化功能。Redis和MongoDB是当前使用最广泛的NoSQL,而就Redis技术而言,它的性能十分优越,可以支持每秒十几万次的读/写操作,其性能远超数据库,并且还支持集群、分布式、主从同步等配置,原则上可以无限扩展,让更多的数据存储在内存中,更让人欣慰的是它还支持一定的事务能力,这保证了高并发的场景下数据的安全和一致性。

Redis 在 Java Web 中的应用

Redis在Java Web主要有两个应用场景

  • 存储缓存用的数据
  • 需要高速读/写的场合使用它进行快速读/写

缓存场景

在日常对数据库的访问中,读操作的次数远超写操作,需要读的可能性是比写的可能大得多的。当我们使用SQL语句去数据库进行读写操作时,数据库就会去磁盘把对应的数据索引取回来,这是一个相对较慢的过程。如果我们把数据放在 Redis 中,也就是直接放在内存之中,让服务端直接去读取内存中的数据,那么这样速度明显就会快上不少,并且会极大减小数据库的压力,但是使用内存进行数据存储开销也是比较大的,限于成本的原因,一般我们只是使用 Redis 存储一些常用和主要的数据,比如用户登录的信息等。

高速读/写场景

在如今的互联网中,越来越多的存在高并发的情况,比如天猫双11、抢红包、抢演唱会门票等,这些场合都是在某一个瞬间或者是某一个短暂的时刻有成千上万的请求到达服务器,如果单纯的使用数据库来进行处理,就算不崩,也会很慢的,轻则造成用户体验极差用户量流失,重则数据库瘫痪,服务宕机,而这样的场合都是不允许的!

Redis持久化

持久化的功能:Redis的是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将Redis的中的数据以某种形式(数据或命令)从内存保存到硬盘;当下次Redis的重启时,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置。

Redis的持久化分为RDB持久化和AOF持久化:前者将当前数据保存到硬盘,后者则是将每次执行的写命令保存到硬盘(类似于MySQL的二进制日志的);由于AOF持久化的实时性更好,即当进程意外退出时丢失的数据更少,因此AOF是目前主流的持久化方式,不过RDB持久化仍然有其用武之地。

实际使用时的环境配置和具体操作demo

见参考资料中的“Redis【入门】就这一篇!”,有较为详细的教程。

SpringBoot整合Redis进行缓存数据库查询

见参考资料中的“SpringBoot整合Redis进行缓存数据库查询”,有较为详细的教程。

配制好Redis环境后,整合Spring Boot和Redis的步骤如下:

先在pom.xml文件中导入依赖:

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

然后在application.yml中加入自己的redis信息(需要先在服务器或者本地配制好redis):

spring:
  redis:
    database: 0      # Redis数据库索引(默认为0)
    host: localhost  # Redis服务器地址
    port: 6379       # Redis服务器连接端口
    password:        # Redis服务器连接密码(默认为空)
    timeout: 5000       # 连接超时时间(毫秒)
    jedis:
      pool:
        max-active: 1000  # 连接池最大连接数(使用负值表示没有限制)
        max-idle: 50    # 连接池中的最大空闲连接
        max-wait: -1   # 连接池最大阻塞等待时间(使用负值表示没有限制)
        min-idle: 10    # 连接池中的最小空闲连接

在Service层加入class:

@Service
public class RedisService {

	@Autowired
	private RedisTemplate redisTemplate;

	public Result<String> put(String key, Object value, long seconds) {
		Result<String> result = new Result<>();
		result.setCode(HttpStatus.OK);
		try {
			redisTemplate.opsForValue().set(key, value, seconds, TimeUnit.SECONDS);
			result.setMessage("success");
		} catch (Exception e) {
			result.setMessage("false");
			e.printStackTrace();
		}
		return result;
	}

	public Result<Object> get(String key) {
		Result<Object> result = new Result<>();
		result.setCode(HttpStatus.OK);
		try {
			result.setData(redisTemplate.opsForValue().get(key));
			result.setMessage("success");
		} catch (Exception e) {
			result.setMessage("false");
			e.printStackTrace();
		}
		return result;

	}
}

在Controller层加入class:

@RestController
public class RedisController {

    @Autowired
    private RedisService redisService;

    @RequestMapping(value = "put", method = RequestMethod.PUT)
    public Result<String> put(String key, String value, long seconds) {
        System.out.println("Redis put");
        Result<String> result = new Result<>();
        result = redisService.put(key, value, seconds);
        return result;
    }

    @RequestMapping(value = "get", method = RequestMethod.GET)
    public Result<Object> get(String key) {
        System.out.println("Redis get");
        Result<Object> restult = new Result<>();
        restult = redisService.get(key);
        return restult;
    }

}

即可完成Spring Boot和Redis的整合。

Redis可视化管理工具

Redis Desktop Manager是一款能够可视化Redis管理的工具,收费软件,自己去网上下载。

其它

  • Spring Boot和Spring MVC的区别:

参考资料

  1. SPRING中常用的注解(@ENTITY,@TABLE,@COLUMN,@REPOSITORY,@SERVICE)
  2. Spring Boot中使用@Scheduled创建定时任务
  3. Spring Boot教程
  4. 在CentOS7.4中安装jdk的几种方法及配置环境变量
  5. spring boot 项目部署到服务器 两种方式
  6. linux jar 包运行与关闭
  7. 解决linux环境下nohup: redirecting stderr to stdout问题
  8. Unable to access jar file xxx.jar
  9. springboot主类没有启动按钮
  10. 在linux下发布jar包
  11. 查看端口被占用的情况以及如何解除端口占用
  12. 最快的 maven repository--阿里镜像仓库
  13. JPA基础(一):全面阐释和精彩总结JPA
  14. JPA学习笔记(1)——什么是JPA
  15. JPA是什么?为什么使用JPA? JPA和Hibernate关系
  16. Spring Data JPA 和MyBatis比较
  17. JPA教程(易百教程)
  18. JPA教程网
  19. Java中使用到的注解
  20. 对ArrayList进行分页
  21. SPRING中常用的注解(@ENTITY,@TABLE,@COLUMN,@REPOSITORY,@SERVICE)
  22. MySQL、MongoDB、Redis 数据库之间的区别
  23. Redis【入门】就这一篇!
  24. SpringBoot整合Redis进行缓存数据库查询
  25. 精讲Redis持久化
原文地址:https://www.cnblogs.com/keep250/p/12275845.html