关于面试遇到的问题

一.微服务远程服务调用

使用了OpenFeign做服务调用

1、OpenFeign

1)OpenFeign介绍

声明式的API定义:通过使用注解,开发者可以定义和描述服务间的API接口,包括请求方法、路径、参数、请求头等信息。这样可以使得服务间的调用代码更加简洁和易于维护。

自动化的服务发现和负载均衡:OpenFeign集成了服务注册中心,可以自动发现和调用其他微服务。它还支持负载均衡,可以根据配置的负载均衡策略选择合适的服务实例进行调用。

内置的请求和响应拦截器:OpenFeign提供了一些内置的拦截器,可以在请求和响应的不同阶段进行拦截和处理。开发者可以自定义拦截器来实现日志记录、错误处理等功能。

支持多种编码器和解码器:OpenFeign支持多种编码器和解码器,可以处理不同的数据格式,如JSON、XML等。开发者可以根据需要选择合适的编码器和解码器。

整合了Hystrix和Ribbon:OpenFeign与Hystrix和Ribbon等其他Spring Cloud组件集成,可以实现服务的容错和熔断机制,提高系统的可靠性和稳定性。

总之,OpenFeign简化了微服务架构中的服务间调用,提供了一种简洁、声明式的方式来定义和调用服务API。它与Spring Cloud的其他组件集成良好,是构建和管理微服务架构的重要工具之一。

2)OpenFeign使用


① 添加 OpenFeign依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.0.0.RELEASE</version>
</dependency>


② 创建Feign客户端接口

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
 
@FeignClient(name = "producer")   //标记的接口用于定义远程服务的调用
public interface RemoteClient {
 
    @GetMapping("/getMember")
    String helloNacos();
}


③ 使用Feign客户端

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
 
@SpringBootApplication
@RestController
@EnableFeignClients
@EnableDiscoveryClient
public class NacosFeignApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(NacosFeignApplication.class, args);
    }
 
    @Autowired
    private RemoteClient remoteClient;
 
    @GetMapping("/feign")
    public String test() {
        return remoteClient.helloNacos();
    }
}


④ 注册配置及controller

spring:
  application:
    name: producer
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
server:
  port: 8083
 
=========================================================================
@RestController
@Slf4j
public class ProducerController {
    @Value("${server.port}")
    private String port;
 
    @RequestMapping("/getMember")
    public String getMember() {
        return "The port of producer is "+port;
    }
}


2、Feign


1)Feign介绍

1.定义:
        - Feign是一个声明式的Web服务客户端,它使得编写Web服务客户端变得更加容易。
        - Feign的设计目标是让Web服务调用变得更加简单,无论是在本地还是在远程。
2.特点:
        - 声明式API定义:通过简单的注解,开发者可以定义需要调用的远程服务的API接口。
        - 集成了负载均衡:Feign默认集成了Ribbon负载均衡器,使得服务调用更加健壮和可靠。
        - 自动化的服务发现:Feign通过服务名自动进行服务发现,无需手动指定远程服务的IP地址和端口。
3.与其他技术的关系:
        - Feign在RestTemplate和Ribbon的基础上进一步封装,使用RestTemplate实现HTTP调用,使用Ribbon实现负载均衡

2)Feign调用步骤
程序启动时,扫描所有的@FeignClient注解

当接口方法被调用时,通过JDK代理来生成RequestTemplate模板

根据RequestTemplate模板生成Http请求的Request对象

Request对象交给Client去处理,其中Client的网络请求框架可以是HttpURLConnection、HttpClient、OKHttp

最后client封装成LoadBaLanceClient,结合ribbon负载均衡地发起调用

2)Feign和OpenFeign的比较


1. 定义与背景

Feign:Feign是Netflix开发的一个声明式HTTP客户端,它使得编写Web服务客户端变得更加容易。Feign通过注解和动态代理简化了HTTP API的调用。
OpenFeign:OpenFeign是Feign的一个开源实现,并且完全兼容Feign的API。OpenFeign提供了更多的功能和扩展性,是Spring Cloud生态系统中用于服务间通信的重要组件。
2. 核心特性

Feign:
支持多种HTTP请求类型,包括GET、POST、PUT、DELETE等。
支持多种数据格式,如JSON、XML、文本等。
支持负载均衡和故障转移。
OpenFeign:
除了Feign的所有特性外,OpenFeign还支持以下功能:
更多的注解支持,包括@FeignClient、@RequestMapping、@GetMapping、@PostMapping等。
更多的配置选项,如超时、重试、熔断器等。
更多的扩展,如日志记录、监控、安全等。
3. 实现方式

Feign:使用Java动态代理来创建HTTP客户端,根据注解自动生成HTTP请求。
OpenFeign:使用Java SPI(Service Provider Interface)来创建HTTP客户端,允许用户自定义HTTP客户端的实现。
4. 适用场景

Feign:适用于需要简单、强大的声明式HTTP请求库的场景。
OpenFeign:适用于需要更强大、更灵活的声明式HTTP请求库的场景,需要自定义HTTP客户端、使用更多注解、配置更多选项或扩展更多功能。
5. 集成与扩展

Feign:虽然功能强大,但扩展性相对有限。
OpenFeign:作为Spring Cloud的一部分,与Spring Cloud的其他组件(如Eureka、Ribbon等)集成得更好,并且提供了丰富的扩展机制。
6. 性能优化

Feign:性能优化主要依赖于底层HTTP客户端的选择和配置。
OpenFeign:除了底层HTTP客户端的选择和配置外,OpenFeign还提供了更多的配置选项和扩展机制来优化性能,如连接池、超时设置等。
总结:

Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务

OpenFeign是Spring Cloud在Feign的基础上支持了SpringMVC的注解,如@RequesMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

3.远程调用的原理


                        
原文链接:https://blog.csdn.net/weixin_47480200/article/details/139567745

二.关于多线程

1.什么是多线程

进程中的最小执行单位就是线程

一个进程中多个线程同时进行即为多线程

这里出现一个问题,多线程往往无法避免的问题,就是线程安全

2.多线程实现的三种方式

1.1继承Thread类的方式进行实现

java.lang.Thread是Java提供的线程类,继承了该类的就是一个线程类,所有的线程对象都必须是 Thread 类或其⼦类的实例。每个线程的作⽤是完成⼀定的任务,实际上就是执⾏⼀段程序流即⼀段顺序执⾏的代码,Java 使⽤线程执⾏体来代表这段程序流。主线程和分支线程是并发执行的,谁在前谁在后是随机的抢占式分配。Java中通过继承Thread类来创建并启动多线程的步骤如下:

        1. 定义 Thread 类的⼦类,并重写该类的 run() ⽅法,该 run() ⽅法的⽅法体就代表了线程需要完成的任务,因此把 run() ⽅法称为线程执⾏体。

        2. 创建 Thread ⼦类的实例,即创建了线程对象

        3. 调⽤线程对象的 start() ⽅法来启动该线程

/**
 * 关于多线程的测试类 继承Thread
 */
public class TestThread extends Thread{
    //重写run方法
    @Override
    public void run() {
        for (int i=0;i<15;i++){
            //getName()方法是在线程启动时获取线程名
            System.out.println(getName()+"hello");
            System.out.println("第"+i+"个");
        }
    }

    public static void main(String[] args) {
        TestThread t1=new TestThread();
        TestThread t2=new TestThread();

        t1.setName("线程1");
        t2.setName("线程2");

        t1.start();
        t2.start();
    }
}
2.1实现Runnable接口的方式进行实现

  采⽤ java.lang.Runnable 实现也是⾮常常⻅的⼀种,只需要重写 run ⽅法即可。

        步骤如下:

        1. 定义 Runnable 接⼝的实现类,并重写该接⼝的 run() ⽅法,该 run() ⽅法的⽅法体同样是该线程的线程执⾏体。

        2. 创建 Runnable 实现类的实例,并以此实例作为 Thread 的 target 来创建 Thread 对象,该 Thread 对象才是 真正的线程对象。

        3. 调⽤线程对象的 start() ⽅法来启动线程。                    

创建任务的对象,创建线程对象,并且把任务传递给线程对象,然后开启线程 

/**
 * 关于多线程的测试类 调用Runnable接口
 */
public class TestThread implements Runnable{
    //重写run方法
    @Override
    public void run() {
        for (int i=0;i<15;i++){
            //getName()方法是在线程启动时获取线程名
            System.out.println(Thread.currentThread().getName()+"hello"+"第"+i+"个");
        }
    }

    public static void main(String[] args) {
        /*多线程的第二种启动方式:1.自己定义一个类实现Runnable接口
        2.重写里面的run方法
        3.创建自己的类的对象
        4.创建一个Thread类的对象,并开启线程
         */
        //创建MyRun的对象
        // 表示多线程要执行的任务
        TestThread mr = new TestThread();

        //创建线程对象,并且把任务传递给线程对象
        Thread t1 = new Thread(mr);
        Thread t2 = new Thread(mr);

        //给线程设置名字
        t1.setName("线程1");
        t2.setName("线程2");
        //开启线程
        t1.start();
        t2.start();

    }
}
3.1利用Callable接口和Future接口方式实现

  Callable接口是Runable接口的增强版。同样用call()方法作为线程的执行体,增强了之前的run()方法。因为call方法可以有返回值,也可以声明抛出异常。

        Future接口用来代表Callable接口里的call()方法的返回值,FutureTask类是Future接口的一个实现类,FutureTask类实现了RunnableFuture接口,而RunnnableFuture接口继承了Runnable和Future接口,所以说FutureTask是一个提供异步计算的结果的任务。

        

        步骤如下:

                1.创建一个类MyCallable实现Callable接口
                2.重写call (是有返回值的,表示多线程运行的结果)
                3.创建MyCallable的对象(表示多线程要执行的任务)
                4.创建FutureTask的对象(作用管理多线程运行的结果)
                5.创建Thread类的对象,并启动(表示线程)

原文链接:https://blog.csdn.net/m0_65277261/article/details/136961604

三.String相关

1.String的底层如何实现

        String的底层是由字符char类型的数组或者byte类型的数组组成

2.关于String

        String是一个不可变字符串类型,每次修改都会创建一个新的字符串。

四.关于数据库优化

1.

五.为什么使用Redis,和Mysql数据库相比有什么优势

        

六.关于SpringBoot

1.什么是SpringBoot

SpringBoot是一种框架,用于简化Spring的应用搭建和开发

2.SpringBoot的常用注解以及作用

(1)SpringBootAplication

作用:这是一个组合注解,用于标识SpringBoot应用程序的入口,该注解包含了@Configuration、@EnableAutoConfiguration和@ComponentScan三个注解

(2)@RestController

作用:与@Controller类似,会把返回值自动转换为JSON格式,并以HTTP的格式响应给客户端

(3)@Service

作用:用于标识一个类是Spring容器的一个服务类(Service)

(4)@Component

作用:用于标识一个类是Spring容器里的组件

(5)@Repository

作用:用于标注一个类作为数据访问对象(DAO)

(6)@Configuration

作用:标识一个类是String的配置类

(7)@RequestMapping

作用:通过该注解可以通过配置的url进行访问,get和post都可以

(8)@GetMapping

作用:和@RequestMapping的作用相似,但是只能是Get请求

(9)@PostMapping

作用:和@RequestMapping的作用相似,但是只能是Post请求

(10)@ResponseBody

作用:可以用在方法或者类上,表示该方法的返回结果直接写入HTTP response body中,而不会解析为跳转路径,即不会经过视图解析器,返回什么数据即在页面上输入什么数据,即将java对象转为json格式的数据

(11)@AutoWired

作用:基于注解方式自动装配,在容器里面将查找到的Bean返回,默认基于类型装配,如果发现找到多个Bean则根据名字装配,如果还发现多个则直接报错

(12)@Qualifier

作用:于注解方式自动装配,在容器里面将查找到的Bean返回,根据名字装配,一般是配合@AutoWired使用,当发现多个相同的名字Bean时使用

(13)@Resource

默认按名称注入例如@Resource(name = “zhaozhao”)则根据name属性注入找不到则报错,如果没有name属性则根据属性名称注入,如果匹配不成功则按照类型匹配不成功报错

(14)@ComponentScan

作用:批量的方式注册Bean

(15)Value

作用:用于获取Bean的属性,一般用于读取配置文件的数据,作用在变量上

(16)RequestParam

作用:获取查询参数。即url?name=这种形式

(17)RequestBody

作用:该注解用于获取请求数据的body,get请求没有请求体,所以一般用于post请求

七.关于SpringCloud

八.如何使用SpringCloud zuul网关实现页面访问拦截

1.添加依赖

2.启动类加注解开启zuul功能

3.写配置文件

4.写一个方法继承ZuulFilter重写里面的四个方法

public String filterType(); 定义Filter的类型(pre 前置,post 后置, route 路由, error 错误)

public int filterOrder();定义filter执行顺序 数字越小越先执行

public boolean shouldFilter(); 是否执行run方法

public Object run() ; // 做过滤逻辑方法
                        
原文链接:https://blog.csdn.net/qq_33878489/article/details/131870744

九.Liux的基本命令

pwd                查看当前所在目录

ls                    列出文件和目录

cd                   切换目录

mkdir              创建新的目录

cp                    复制文件或目录

mv                  移动或重命名文件或目录

cat,less,more  查看文件内容

find                 搜索文件或目录

grep                查找特定的文本内容

cmod               修改文件或目录的权限

top,ps              查看当前正在运行的进程

kill                   杀死一个进程

free,top           查看系统内存使用情况

netstat             查看网络连接信息

who,w             查看当前登录用户

reboot,shutdown -r now      重启系统

shutdown -h now                 关闭系统

cat,tail             查看系统日志信息

apt-get,yum     安装软件包

apt-get  update && apt-get upgrade,yum update     更新已安装的软件包

which,whereis        查找文件路径

gzip,tar,zip              压缩和解压文件

.关于基本数据类型byte

Java中的字节(byte)是基本的数据类型之一,它是8位(即一个字节)的数据类型。

1. 范围:Java中的字节可以表示的范围是从 -128 到 127。因为 Java 中的字节是有符号的,所以最高位用来表示符号位,0 表示正数,1 表示负数。

2. 用途:字节在 Java 中有多种用途,比如在网络通信中传输数据、读写文件、数据压缩等。此外,在某些情况下,字节也可以用于节省内存空间,因为它只占用一个字节的内存。

3. 操作:Java提供了丰富的字节操作方法,比如字节的读写操作、位操作等。你可以使用 InputStream 和 OutputStream 类来进行字节流的读写操作,也可以使用 ByteBuffer 类来进行字节缓冲区的操作。

4. 字节与字符:在 Java 中,字节和字符是两种不同的概念。字节是最小的数据存储单位,而字符是人类可读的文本表示。在处理文本数据时,通常会涉及到字节和字符之间的相互转换,比如使用字符集将字节流转换为字符流。

5. 字节码:除了基本数据类型的字节外,Java 还有一种特殊的字节码(bytecode),它是 Java 编译器编译 Java 源代码后生成的中间代码。字节码可以被 Java 虚拟机(JVM)解释执行,这使得 Java 具有跨平台性。

十一.从数据库里查询十条数据

  这代表从都一个数据开始查询十条数据 0可以省略

select * from table limit 0,10 

   这表示从第五条数据开始查询十条数据

select * from table limit 5,10

十二.有关数据库的事务

定义:在java中事务管理代表一组操作要么全部成功要么全部失败的一种机制,以确保数据的一致性和完整性,在mysql中要让多条语句当成一个整体则需要放在同一个事务中

事务的管理方式:编程式事务管理,声明式事务管理

编程式事务:所谓编程式事务指的是通过编码方式实现事务,即类似于JDBC编程实现事务管理。管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。

声明式事务:管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。

显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。

声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

事务的特性:原子性,一致性,隔离性和持久性

原子性:事务是数据库的逻辑工作单位,事务中包含的各操作要么都完成,要么都不完成

一致性:事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。

隔离性:一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。

持久性:指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。
                        
原文链接:https://blog.csdn.net/yjp1240201821/article/details/140614475

十三.有关事务隔离问题

1.引言

数据库事务的隔离级别有4种,由低到高分别为Read uncommitted(读未提交) 、Read committed (读已提交)、Repeatable read (重复读)、Serializable (序列化)。读现象是在多个事务并发执行时,在读取数据方面可能碰到的问题。包括脏读、不可重复读、幻读。

脏读:读到了脏数据,即无效数据。

不可重复读:是指在数据库访问中,一个事务内的多次相同查询却返回了不同数据。

幻读:指同一个事务内多次查询返回的结果集不一样,比如增加了行记录。

备注:不可重复读对应的是修改,即update操作。幻读对应的是插入操作。幻读是不可重复读的一种特殊场景。不可重复读针对的是更新和删除,幻读针对的是插入。

要想解决脏读、不可重复读、幻读等读现象,那么就需要提高事务的隔离级别。但是随之带来的,隔离级别越高,并发能力越低。所以,需要根据业务去进行衡量,具体场景应该使用哪种隔离级别。

下面通过事例一一阐述它们的概念与联系。

2.事务隔离级别


2.1 Read uncommitted(读未提交)


提供了事务建最小限度的隔离。顾名思义,就是一个事务可以读取另一个未提交事务的数据。

示例:小明去商店买衣服,付款的时候,小明正常付款,钱已经打到商店老板账户,但是小明发起的事务还没有提交。就在这时,商店老板查看自己账户,发现钱已到账,于是小明正常离开。小明在走出商店后,马上回滚差点提交的事务,撤销了本次交易曹邹。

结果:小明未付钱买到了衣服,商店老板实际未收到小明的付款。

分析:商店老板查看自己的资金账户,这个时候看到的是小明还没有提交事务的付款。这就是脏读。

注意:处于该隔离级别的事务A与B,如果事务A使用事务B不提交的变化作为计算的基础,然后哪些未提交的变化被事务A撤销,这就导致了大量的数据错误变化。

2.2 Read committed (读已提交)

处于Read committed (读已提交)级别的事务可以看到其他事务对数据的修改。也就是说,在事务处理期间,如果其他事务修改了相应的表,那么同一个事务的同一sql在其他事务执行前后返回的是不同的结果。一个事务要等另一个事务提交后才能读取数据。

示例:小明卡里有1000元,准备与几个朋友聚餐消费,消费1000元,当他买单时(事务开启),收费系统检测到他卡里有1000元。就在检测完毕的时候,小明女朋友发现小明有私房钱,全部转走并提交。当收费系统准备扣款时,再检查小明卡里的金额,发现已经没钱了,付款不成功。小明此时就会很纳闷,明明有钱的呀,钱呢?

分析:该示例中同一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。该隔离级别可以解决脏读问题。

2.3 Repeatable read (重复读)


在开始读取数据(事务开启)时,不再允许修改操作

示例:还是小明有1000元,准备跟朋友聚餐消费这个场景,当他买单(事务开启)时,收费系统检测到他卡里有1000元,这个时候,他的女朋友不能转出金额。接下来,收费系统就可以扣款成功了,小明醉醺醺的回家,准备跪脱衣板。

分析:重复读可以解决不可重复读的问题,这句话有些别扭,大家可以仔细品一下。

写到这里,大家可能会产生疑问,什么情况下产生幻读呢?

那么, 什么是幻读呢?
幻读是指在同一个事务中,前后两次查询相同的范围时,得到的结果不一致 (我们来看这个图)
 第一个事务里面我们执行了一个范围查询,这个时候满足条件的数据只有一条
 第二个事务里面,它插入了一行数据,并且提交了
 接着第一个事务再去查询的时候,得到的结果比第一查询的结果多出来了一条数据。
所以,幻读会带来数据一致性问题。
                        
原文链接:https://blog.csdn.net/sinat_53467514/article/details/135273385

示例来了:

小明在公司上班,女朋友告诉他,拿着他的卡去逛街消费。花了一千元,然后小明去查看他银行卡的消费记录(事务开启),看到确实是花了一千元。就在这个时候,小明女朋友又花三千元买了一些化妆品和衣服,即新增了一些消费记录。当小明打印自己银行卡消费记录单的时候(女朋友事务提交),发现花了四千元,似乎出现了幻觉,小明很心疼。这就是幻读

扩展:当我们开启一个事务以后,有如下的程序操作

第一步:更新A表id=1的记录

第二步:查询A表id=1的记录

第三步:使用第二步的查询结果作为依据继续业务逻辑

第四步:提交事务

问题来了:同一个事务中,事务未提交前,第二步的查询结果是第一步执行前的结果还是第一步执行后的结果呢?

答案:事务隔离级别是针对不通事务的,同一事务中的未提交的更新,在后续是可以查询到的。     

解决幻读

MVCC加上间隙锁的方式
(1)在快照读读情况下,mysql通过mvcc来避免幻读。
(2)在当前读读情况下,mysql通过next-key来避免幻读。锁住某个条件下的数据不能更改

2.4 Serializable (序列化)

数据库事务的最高隔离级别。在此级别下,事务串行执行。可以避免脏读、不可重复读、幻读等读现象。但是效率低下,耗费数据库性能,不推荐使用。

原文链接:https://blog.csdn.net/airingyuan/article/details/127112563

十四.有关事务回滚问题

定义:当事务中多条操作中,有一个反生错误则会发生事务回滚,即将前面已经发生的回滚

事务回滚是指将该事务已经完成对数据库的更新操作撤销,在事务中,每个正确的原子都会被顺序执行,直到遇到错误的原子操作。

什么是回滚?

回滚是删除由一个或多个部分完成的事务执行的更新,为保证应用程序、数据库或系统错误后还原数据库的完整性,需要使用回滚。

回滚包括程序回滚和数据回滚等类型(泛指程序更新失败,返回上一次正确状态行为)

十五.有关数据库调优

十六.docker的基本命令

docker的定义:Docker 将应用程序与该程序的依赖,打包在一个文件里面,改文件包括了所有打包得应用程序的所有依赖,像数据库等;直接运行改文件,就可以让程序跑起来,从而不用再去考虑环境问题。

docker的作用:

(1)提供一次性的环境。比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。

(2)提供弹性的云服务。因为 Docker 容器可以随开随关,很适合动态扩容和缩容。

(3)组建微服务架构。通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。

docker的常用命令:

(1)启动docker
systemctl start docker
(2)停止docker
systemctl stop docker
(3)重启docker
systemctl restart docker
(4)查看docker
systemctl status docker
(5)设置开机自启
systemctl enable docker
(6)查看docker概要信息
docker info
(7)查看docker总体帮助文档
docker --help
(8)查看docker命令帮助文档
docker 命令 --help
 
例如:
docker run --help
二、镜像命令
(1)docker images
列出本地主机上有的镜像

(2)docker search
去配置的镜像网站库找寻找某个镜像,比如:Docker

docker search [OPTIONS] 镜像名字
常用参数:
--limit nu   #只输出查到的前nu条记录
 
example:
docker search redis
docker search --limit 3 redis
docker search redis --limit 3    # 放在镜像名称前面后面均可
 

字段解析:

NAME:镜像名称
DISCRIPTION:镜像说明
STARTS:点赞数
OFFICAL:是否是官方认可的
AUTOMATED:是否自动构建 
(3)docker pull
从远程库拉取镜像

docker pull 镜像名字[:TAG]
 
example:
docker pull redis:6.0.8
docker pull ubuntu  # 没有指定版本即拉取最新版 即默认为 ubuntu:latest
(4)docker system df
查看镜像/容器/数据卷所占的空间

docker system df


(5)docker rmi
删除本地有的镜像

#删除单个
docker rmi 镜像ID  #删除镜像,如果此时镜像上面有容器正在运行,会报错无法删除
docker rmi  -f 镜像ID   #强制(forced)删除镜像
 
 
#删除多个
docker rmi -f 镜像名1:TAG 镜像名2:TAG 
 
 
#删除全部(慎用)
docker rmi -f $(docker images -qa)  
#首先docker images -qa会列举本地所有的镜像的ID,然后作为一个集合送入rmi一个个删除
(6)docker commit
 Docker中的镜像分层,支持通过扩展现有镜像,创建新的镜像。我们进行扩展后提交到本地成为一个新的镜像

docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
 
example:
docker pull ubuntu  # 从镜像仓库拉取基础ubuntu镜像(支持扩展),原始的默认Ubuntu镜像是不带着vim命令的
 
#外网联通的情况下,在容器内安装vim命令
apt-get update
apt-get -y install vim
 
#安装完成后,commit我们自己的新镜像
docker commit -m="ubuntu-add-vim" -a="zjy" a4b1b1cc54f0 atguigu/myubuntu:1.3
提交结果,可以明显的看到SIZE变大了

(7)docker build
 通过Dcokerfile构建镜像

docker build -t 新镜像名字:TAG .  # 注意 TAG后面有个空格,有个点
 
example:
docker build -t centosjava8:1.5 .
三、容器命令
(1)docker run
新建启动容器

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
 
常用参数:
--name=NAME   #为容器指定名字为NAME,不使用的话系统自动为容器命名
-d: 后台运行容器并返回容器ID,也即启动守护式容器(后台运行);
 
-i:以交互模式运行容器,通常与 -t 同时使用;
-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;
也即启动交互式容器(前台有伪终端,等待交互,一般连用,即-it);
 
-P: 随机端口映射,大写P
-p: 指定端口映射,小写p
 
 
example:
 
以ubuntu为例,启动后要交互先声明交互模式,其次交互得需要一个终端,因此参数为-it
docker run -it ubuntu /bin/bash
 
指定名称
docker run -it --name=myubuntu ubuntu /bin/bash
启动守护式容器

在大部分的场景下,我们希望 docker 的服务是在后台运行的,
我们可以过 -d 指定容器的后台运行模式。

docker run -d 容器名
 
example:
docker run -d redis:6.0.8
docker run -d ubuntu
注意

上面的docker run -d ubuntu 执行后,使用docker ps -a进行查看,会发现容器已经退出

很重要的要说明的一点: Docker容器后台运行,就必须有一个前台进程.

这个是docker的机制问题,比如你的web容器,我们以nginx为例,正常情况下,我们配置启动服务只需要启动响应的service即可。例如service nginx start。但是,这样做,nginx为后台进程模式运行,就导致docker前台没有运行的应用, 这样的容器后台启动后,会立即自杀,因为它觉得他没事可做了.

最佳的解决方案是,将你要运行的程序以前台进程的形式运行,常见就是命令行模式,类似centos、ubuntu

(2)docker ps
docker ps [OPTIONS]
 
常用参数:
-a :列出当前所有正在运行的容器+历史上运行过的
-l :显示最近创建的容器。
-n nu:显示最近nu个创建的容器。
-q :静默模式,只显示容器编号。
 
example:
docker ps -aq
docker ps -n 3
docker ps -l
(3)退出容器
① exit
run进去容器,exit退出,容器停止

② ctrl+p+q
run进去容器,ctrl+p+q退出,容器不停止

(4)进入正在运行的容器并以命令行交互
① docker exec -it 容器ID/容器名称 bashShell
② docker attach 容器ID
example:
 
#容器ID
docker exec -it c32f612cc218 /bin/bash
docker attach c32f612cc218
 
#容器名称
docker exec -it wizardly_booth /bin/bash
docker attach wizardly_booth
区别 

exec 是在容器中打开新的终端,并且可以启动新的进程。用exit退出,不会导致容器的停止。

attach 直接进入容器启动命令的终端,不会启动新的进程。用exit退出,会导致容器的停止。

推荐大家使用 docker exec 命令,因为退出容器终端,不会导致容器的停止。

(5)启动已停止运行的容器
docker start 容器ID或者容器名
(6)重启容器
docker restart 容器ID或者容器名
(7)停止容器
docker stop 容器ID或者容器名
(8)强制停止容器
docker kill 容器ID或容器名
(9)删除已停止的容器
#删除一个
docker rm 容器ID  
docker rm -f 容器ID  #强制删除
 
#删除多个
docker rm -f $(docker ps -a -q)

docker ps -a -q | xargs docker rm
(10)查看容器日志
docker logs 容器ID
(11)查看容器内运行的进程
docker top 容器ID
(12)查看容器内部细节
docker inspect 容器ID
(13)从容器内拷贝文件到主机上
docker cp  容器ID:容器内路径 目的主机路径
 
example:
#以ubuntu为例,我们在/tmp目录下通过touch a.txt创建a文本,将其复制到本机download目录下
docker cp 958443b97285:/tmp/a.txt /download
(14)导入和导出容器
export 导出容器的内容留作为一个tar归档文件[对应import命令]

import 从tar包中的内容创建一个新的文件系统再导入为镜像[对应export]

docker export 容器ID > 文件名.tar
cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号
 
 
example:
 
#以ubuntu为例
docker export 958443b97285 > abcd.tar
cat abcd.tar | docker import - atguigu/ubuntu:3.7  # 注意 - 左右有分别有一个空格
(15)容器数据卷挂载
将docker容器内的数据保存进宿主机的磁盘中

# 运行一个带有容器卷存储功能的容器实例
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:[OPTION] 镜像名
 
OPTION:
rw   可读可写(read + write)
ro   容器实例内部被限制,只能读取不能写,仅读(read only)
 
example:
 
docker run -it --privileged=true --name=u1 -v /tmp/docker_data:/tmp/dockertest:ro ubuntu /bin/bash
 
 
docker run -it --privileged=true --name=u2 -v /tmp/docker_data:/tmp/dockertest ubuntu /bin/bash  # 不写OPTION默认rw
挂载后可通过【docker inspect 容器ID】查看是否挂载成功

(16)容器数据卷继承
docker run -it  --privileged=true --volumes-from 父类  --name u2 ubuntu
 
 
 
example:
# 新创建u3容器继承u2容器的数据卷挂载,此时u2就算stop也不影响u3
docker run -it --privileged=true --volumes-from u2 --name u3 ubuntu
(17)查看容器资源占用情况
 显示容器资源的使用情况,包括:CPU、内存、网络 I/O 等。

docker stats [OPTIONS] [CONTAINER...]
 
 
OPTIONS:
--all , -a :显示所有的容器,包括未运行的。
 
--format :指定返回值的模板文件。
 
--no-stream :展示当前状态就直接退出了,不再实时更新。
 
--no-trunc :不截断输出。
 
 
example:
docker stats
docker stats mynginx  # 容器名
docker stats af7928654200  # 容器ID
 

 字段解析:

CONTAINER ID 与 NAME: 容器 ID 与名称。
CPU % 与 MEM %: 容器使用的 CPU 和内存的百分比。
MEM USAGE / LIMIT: 容器正在使用的总内存,以及允许使用的内存总量。
NET I/O: 容器通过其网络接口发送和接收的数据量。
BLOCK I/O: 容器从主机上的块设备读取和写入的数据量。
PIDs: 容器创建的进程或线程数。
注意:
docker stats统计结果只能是当前宿主机的全部容器,数据资料是实时的,没有地方存储、没有健康指标过线预警等功能,如果现象要实现监控数据持久化并以图表等形式展现,可以使用CIG,即CAdvisor监控收集+InfluxDB存储数据+Granfana展示图表

(18)Docker save 
docker save 命令用于将 Docker镜像 保存成 tar 包。

docker save [OPTIONS] IMAGE [IMAGE...]
docker save 镜像名:版本号 -o 打包压缩存放位置
 
OPTIONS:
docker save -o, --output    将归档文件输出到的文件。
 
 
example:
docker save 67fa590cfc1c -o haicoder_centos.tar  //打包到当前目录下


(19)Docker load
docker load 命令用于从 tar 归档文件或者标准输入流载入镜像。docker load 命令的相对应的命令为 docker save。

docker load [OPTIONS]
 
OPTIONS:
-i    指定导出的文件。
-q    精简输出信息。
 
 
docker load -i haicoder_centos.tar  // 将归档的镜像文件,载入到镜像。
  

四、docker网络命令
 

(1)查看网络
docker network ls


(2)创建网络 
docker network create xxx网络名字


(3)查看网络源数据
docker network inspect  XXX网络名字
(4)删除网络
docker network rm XXX网络名字
五、Docker-compose容器编排命令
docker-compose -h                      # 查看帮助
docker-compose up                      # 启动所有docker-compose服务
docker-compose up -d                   # 启动所有docker-compose服务并后台运行
docker-compose down                    # 停止并删除容器、网络、卷、镜像。
docker-compose exec  yml里面的服务id          # 进入容器实例内部  
docker-compose exec docker-compose.yml文件中写的服务id /bin/bash
docker-compose ps                      # 展示当前docker-compose编排过的运行的所有容器
docker-compose top                     # 展示当前docker-compose编排过的容器进程
 
docker-compose logs  yml里面的服务id    # 查看容器输出日志
docker-compose config     # 检查配置
docker-compose config -q  # 检查配置,有问题才有输出
docker-compose restart   # 重启服务
docker-compose start     # 启动服务
docker-compose stop      # 停止服务

十七.泛型的定义,使用和自定义泛型

1.泛型的定义

泛型的本质是为了将类型参数化, 也就是说在泛型使用过程中,数据类型被设置为一个参数,在使用时再从外部传入一个数据类型;而一旦传入了具体的数据类型后,传入变量(实参)的数据类型如果不匹配,编译器就会直接报错。这种参数化类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

泛型的使用之后,往一个集合里传入不符合的数据类型会直接报错,而不是像没使用时只用当编译之后才报错

十八.数据库索引

1.1、索引的含义
数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询,更新数据库中表的数据。索引的实现通常使用B树和变种的B+树(MySQL常用的索引就是B+树)。除了数据之外,数据库系统还维护为满足特定查找算法的数据结构,这些数据结构以某种方式引用数据,这种数据结构就是索引。简言之,索引就类似于书本,字典的目录。
1.2、为什么用索引?
打个比方,如果正确合理设计使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是一个人力三轮车。对于没有索引的表,单表查询可能几十万数据就是瓶颈,二通常大型网站单日就可能产生几十万甚至几百万的数据,没有索引查询会变得非常缓慢。一言以蔽之,合理使用索引,可以加快数据库的查询效率和提升程序性能

索引的作用与缺点
2.1、作用

通过创建索引,可以再查询的过程中,提高系统的性能
通过创建唯一性索引,可以保持数据库表中每一行数据的唯一性
在使用分组和排序子句进行数据检索时,可以减少查询中分组和排序的时间
2.2、缺点
创建索引和维护索引要耗费时间,而且时间随着数据量的增加而增大
索引需要占用物理空间,如果要建立聚簇索引,所需要的空间会更大
在对表中的数据进行增删改时需要耗费较多的时间,因为索引也要动态地维护

提醒1:

在任何数据库当中主键上都会自动添加索引对象,id字段上自动有索引,因为id是主键。另外在mysql当中,一个字段上如果有unique约束的话,也会自动创建索引对象。
 
提醒2:

在任何数据库当中,任何一张表的任何一条记录在实际硬盘存储上都有一个硬盘的物理存储编号。

提醒3:

不管索引存储在哪里,索引在mysql当中都是一个树的形式存在。(自平衡二叉树:B-Tree)

索引的创建和删除

创建索引:

create index 要创建的索引名 on 要创建索引的表名(要创建索引的字段);

删除索引:

drop index 要删除的索引名 on 要删除的索引所在的表名;

3、索引的使用场景

3.1、应创建索引的场景

经常需要搜索的列上
作为主键的列上
经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度
经常需要根据范围进行搜索的列上
经常需要排序的列上
经常使用在where子句上面的列上
3.2、不应该创建索引的场景

查询中很少用到的列
对于那些具有很少数据值的列,比如数据表中的性别列,bit数据类型的列
对于那些定义为text,image的列,因为这些列的数据量相当大
当对修改性能的要求远远大于搜索性能时,因为当增加索引时,会提高搜索性能,但是会降低修改性能
                       
原文链接:https://blog.csdn.net/qq_44483424/article/details/121385545

十九.各种集合在项目中的使用场景

二十.反射及反射机制的原理和使用场景

二十一.session和cookie的区别和生命周期

二十二.什么是MVC

MVC是一种设计模式,及Model视图,View视图以及Controller控制器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值