-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
115 lines (54 loc) · 316 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>遇到的坑</title>
<link href="/2023/03/09/%E9%81%87%E5%88%B0%E7%9A%84%E5%9D%91/"/>
<url>/2023/03/09/%E9%81%87%E5%88%B0%E7%9A%84%E5%9D%91/</url>
<content type="html"><![CDATA[<h1 id="遇到的坑"><a href="#遇到的坑" class="headerlink" title="遇到的坑"></a>遇到的坑</h1><p>每个人在开发中都会遇到很多坑,有些很好解决,百度一下就能出来,有些则需要排查好久,这篇文章就是来记录一些我遇到的奇葩的坑。</p><h2 id="提示DataSource的url错误"><a href="#提示DataSource的url错误" class="headerlink" title="提示DataSource的url错误"></a>提示DataSource的url错误</h2><p><a href="https://imgse.com/i/ppnyXVK"><img src="https://s1.ax1x.com/2023/03/09/ppnyXVK.png" alt="ppnyXVK.png"></a></p><p>百度答案是</p><p>加配置</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})</span></span><br></pre></td></tr></table></figure><p>在application.properties/或者application.yml文件中没有添加数据库配置信息</p><p>在spring xml配置文件中引用了数据库地址 所以需要对:等进行转义处理.但是在application.properties/或者application.yml文件并不需要转义,错误和正确方法写在下面了.</p><p>yml或者properties文件没有被扫描到,需要在pom文件中<build></build>添加如下.来保证文件都能正常被扫描到并且加载成功.</p><p>但是这些我都试过了没有用,苦恼了我好久。后来又在尝试第一个办法时,发现控制台也报错了</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">org.springframework.beans.factory.BeanCreationException: Error creating bean with name <span class="string">'xxController'</span>: Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: <span class="keyword">private</span> </span><br></pre></td></tr></table></figure><p>说我的UserServiceImpl和UserMapper不存在,后面排查才发现是target目录没有编译application.yml</p><p>最后在pom.xml中删除<packaging>pom</packaging>这行,再进行重构,target目录就正常了,真是个大坑!!!</p>]]></content>
<tags>
<tag> 随笔 </tag>
</tags>
</entry>
<entry>
<title>注解与反射</title>
<link href="/2023/03/09/%E6%B3%A8%E8%A7%A3%E4%B8%8E%E5%8F%8D%E5%B0%84/"/>
<url>/2023/03/09/%E6%B3%A8%E8%A7%A3%E4%B8%8E%E5%8F%8D%E5%B0%84/</url>
<content type="html"><![CDATA[<h1 id="注解与反射"><a href="#注解与反射" class="headerlink" title="注解与反射"></a>注解与反射</h1><h2 id="注解"><a href="#注解" class="headerlink" title="注解"></a>注解</h2><h3 id="注解是什么"><a href="#注解是什么" class="headerlink" title="注解是什么"></a>注解是什么</h3><p>从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。</p><h3 id="基本的注解"><a href="#基本的注解" class="headerlink" title="基本的注解"></a>基本的注解</h3><p>java提供了5个基本的注解,分别是</p><p><strong>1.@Override</strong></p><p><strong>2.@Deprecated</strong></p><p><strong>3.@SuppressWarnings</strong></p><p><strong>4.@SafeVarargs</strong></p><p><strong>5.@FunctionalInterface</strong></p><h4 id="限定父类重写方法-Override"><a href="#限定父类重写方法-Override" class="headerlink" title="限定父类重写方法:@Override"></a>限定父类重写方法:@Override</h4><p>当子类重写父类方法时,子类可以加上这个注解,这可以确保子类确实重写了父类的方法,避免出现低级错误</p><h4 id="标示已过时-Deprecated"><a href="#标示已过时-Deprecated" class="headerlink" title="标示已过时:@Deprecated"></a>标示已过时:@Deprecated</h4><p>这个注解用于表示某个程序元素类,方法等已过时,当其他程序使用已过时的类,方法时编译器会给出警告(删除线)</p><h4 id="抑制编译器警告-SuppressWarnings"><a href="#抑制编译器警告-SuppressWarnings" class="headerlink" title="抑制编译器警告:@SuppressWarnings"></a>抑制编译器警告:@SuppressWarnings</h4><p>被该注解修饰的元素以及该元素的所有子元素取消显示编译器警告,例如修饰一个类,那他的字段,方法都是显示警告</p><h4 id="“堆污染”警告与-SafeVarargs"><a href="#“堆污染”警告与-SafeVarargs" class="headerlink" title="“堆污染”警告与@SafeVarargs"></a>“堆污染”警告与@SafeVarargs</h4><p>想理解这个就要明白什么是堆污染,堆污染是什么?</p><p>其实很好理解,就是把不带泛型的对象赋给一个带泛型的对象,为什么不行?很简单,因为不带泛型的话,默认会给泛型设定为object,意思就是什么类型都可以往里面塞,那你一个不带泛型的怎么可能给一个带泛型塞呢。</p><p>例如运行如下代码:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">List</span> <span class="variable">list</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ArrayList</span>(); </span><br><span class="line">list.add(<span class="number">20</span>);</span><br><span class="line">List<String> ls = list;</span><br><span class="line">System.out.println(ls.get(<span class="number">0</span>));</span><br></pre></td></tr></table></figure><p>则会抛出堆污染异常Exception in thread “main” java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at Test.Test1.main(Test1.java:29)</p><p>注意:可变参数更容易引发堆污染异常,因为java不允许创建泛型数组,可变参数恰恰是数组。</p><p>抑制这个警告的方法有三个:</p><p>1.@SafeVarargs修饰引发该警告的方法或构造器</p><p>2.使用@suppressWarnings(“unchecked”)</p><p>3.编译时使用-Xlint:varargs</p><h4 id="函数式接口与-Functionallnterface"><a href="#函数式接口与-Functionallnterface" class="headerlink" title="函数式接口与@Functionallnterface"></a>函数式接口与@Functionallnterface</h4><p>什么是函数式?如果接口中只有一个抽象方法(可以包含多个默认方法或多个static方法)</p><p>接口体内只能声明常量字段和抽象方法,并且被隐式声明为public,static,final。</p><p>接口里面不能有私有的方法或变量。</p><p>这个注解有什么用?这个注解保证这个接口只有一个抽象方法,注意这个只能修饰接口</p><h3 id="元注解"><a href="#元注解" class="headerlink" title="元注解"></a>元注解</h3><h4 id="元注解是什么?"><a href="#元注解是什么?" class="headerlink" title="元注解是什么?"></a>元注解是什么?</h4><p>负责注解其他注解。</p><h4 id="使用-Retention"><a href="#使用-Retention" class="headerlink" title="使用@Retention"></a>使用@Retention</h4><p>表示注解在什么级别还有效,用于描述注解的生命周期(SOURCE < CLASS < <strong>RUNTIME</strong>)一般使用RUNTIME</p><p>这个注解需要使用参数。这个参数的类型是RetentionPolicy,所以使用这个注解就要对value赋值。</p><p>value的值有且仅有三个:</p><p>->RetenionPolicy.CLASS 编译器把该注解记录在class文件中。当运行java程序时,JVM不可获取注解信息。这是默认值!</p><p>->RetenionPolicy.RUNTIME编译器把该注解记录在class文件中。当运行java程序时,JVM可获取注解信息,程序可以通过反射获取该注解信息</p><p>->RetenionPolicy.SOURCE 该注解只保存在源代码中,编译器直接丢弃该注解</p><p>例如:@Retention(value =RetenionPolicy.SOURCE) 可简写为@Retention(RetenionPolicy.SOURCE)</p><h4 id="使用-Target"><a href="#使用-Target" class="headerlink" title="使用@Target"></a>使用@Target</h4><p>@Target也只能修饰一个注解定义,作用是指定被修饰的注解能用于修饰哪些程序单元,@Target也包含了一个value值,他的值只能是下面的:ElementType.</p><table><thead><tr><th>取值</th><th>注解使用范围</th></tr></thead><tbody><tr><td>METHOD</td><td>可用于方法上</td></tr><tr><td>TYPE</td><td>可用于类或者接口上</td></tr><tr><td>ANNOTATION_TYPE</td><td>可用于注解类型上(被@interface修饰的类型)</td></tr><tr><td>CONSTRUCTOR</td><td>可用于构造方法上</td></tr><tr><td>FIELD</td><td>可用于域上</td></tr><tr><td>LOCAL_VARIABLE</td><td>可用于局部变量上</td></tr><tr><td>PACKAGE</td><td>用于记录java文件的package信息</td></tr><tr><td>PARAMETER</td><td>可用于参数上</td></tr></tbody></table><p>例如:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test01</span> {</span><br><span class="line"></span><br><span class="line"> <span class="meta">@MyAnnotation</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test</span><span class="params">()</span> {</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Target(value = ElementType.METHOD)</span></span><br><span class="line"><span class="meta">@interface</span> MyAnnotation {</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>上面就是他的用法,不过有个比较容易混淆的地方就是@interface和interface不是同一个东西:</p><p>@interface 不是interface,是注解类 是jdk1.5之后加入的,java没有给它新的关键字,所以就用@interface 这么个东西表示了 这个注解类,就是定义一个可用的注解,包括这个注解用于什么地方,是类,还是方法,还是property,还是方法入参等等,还有这个注解是否编译后进入class 比如我们知道的用于javadoc的注解,是不进入class文件的。</p><p>然后在后面你就可以用这个注解写代码了。总的来说,这就是一个生成javadoc时用到的注释类</p><h4 id="使用-Documented"><a href="#使用-Documented" class="headerlink" title="使用@Documented"></a>使用@Documented</h4><p>这个注解表示是否将我们的注解生成在Javadoc中。</p><p>例如:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> Testable{}</span><br></pre></td></tr></table></figure><h4 id="使用-Inherited"><a href="#使用-Inherited" class="headerlink" title="使用@Inherited"></a>使用@Inherited</h4><p>说明子类可以继承父类中的该注解</p><h3 id="自定义注解"><a href="#自定义注解" class="headerlink" title="自定义注解"></a>自定义注解</h3><p>注解格式:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> test{</span><br><span class="line">String <span class="title function_">name</span><span class="params">()</span> <span class="keyword">default</span> <span class="string">""</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>注意:注解括号{}里面的不是方法,而是注解的参数,用default可以指定默认值,不然注解就必须指定name属性的值</p><p>如果默认值为-1,则代表不存在</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test01</span> {</span><br><span class="line"></span><br><span class="line"> <span class="meta">@MyAnnotation(name = "xz")</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test</span><span class="params">()</span> {</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Target(value = {ElementType.TYPE, ElementType.METHOD})</span></span><br><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@interface</span> MyAnnotation {</span><br><span class="line"> <span class="comment">//注解的参数:参数类型 + 参数名();</span></span><br><span class="line"> String <span class="title function_">name</span><span class="params">()</span>;</span><br><span class="line"> String[] schools() <span class="keyword">default</span> {<span class="string">"小学"</span>,<span class="string">"初中"</span>};</span><br><span class="line"> <span class="type">int</span> <span class="title function_">id</span><span class="params">()</span> <span class="keyword">default</span> -<span class="number">1</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>如果注解只有一个参数,建议使用value命名,这样可以在给参数赋值的时候省略掉参数名</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test01</span> {</span><br><span class="line"></span><br><span class="line"> <span class="meta">@MyAnnotation1("name")</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test1</span><span class="params">()</span> {}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Target(value = {ElementType.TYPE, ElementType.METHOD})</span></span><br><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@interface</span> MyAnnotation1 {</span><br><span class="line">String <span class="title function_">value</span><span class="params">()</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="反射"><a href="#反射" class="headerlink" title="反射"></a>反射</h2><h3 id="反射是什么"><a href="#反射是什么" class="headerlink" title="反射是什么"></a>反射是什么</h3><p>Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键,反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。</p><p>加载完类之后,在堆内存的方法区中就产生了一个class类型的对象(一个类只有个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以我们形象的称之为:反射。</p><p><a href="https://imgse.com/i/ppES1Wn"><img src="https://s1.ax1x.com/2023/03/04/ppES1Wn.png" alt="ppES1Wn.png"></a></p><h3 id="Java反射机制提供的功能"><a href="#Java反射机制提供的功能" class="headerlink" title="Java反射机制提供的功能"></a>Java反射机制提供的功能</h3><ul><li><p>在运行时判断任意一个对象所属的类</p></li><li><p>在运行时构造任意一个类的对象</p></li><li><p>在运行时判断任意一个类所具有的成员变量和方法</p></li><li><p>在运行时获取泛型信息</p></li><li><p>在运行时调用任意一个对象的成员变量和方法</p></li><li><p>在运行时处理注解</p></li><li><p>生成动态代理</p></li><li><p>……</p></li></ul><h3 id="反射相关的主要API"><a href="#反射相关的主要API" class="headerlink" title="反射相关的主要API"></a>反射相关的主要API</h3><ul><li>java.lang.Class :代表一个类</li><li>java.lang.reflect.Method:代表类的方法</li><li>java.lang.reflect.Field:代表类的成员变量</li><li>java.lang.reflect.Constructor:代表类的构造器</li></ul><h3 id="Class类的常用方法"><a href="#Class类的常用方法" class="headerlink" title="Class类的常用方法"></a>Class类的常用方法</h3><table><thead><tr><th align="center">方法名</th><th align="center">功能说明</th></tr></thead><tbody><tr><td align="center">static ClassforName(String name)</td><td align="center">返回指定类名nameClass对象</td></tr><tr><td align="center">Object newInstance()</td><td align="center">调用缺省构造函数,返回Class对象的一个实例</td></tr><tr><td align="center">getName()</td><td align="center">返回此Class对象所表示的实体 (类,接口,数组类或void) 的名称。</td></tr><tr><td align="center">Class getSuperClass()</td><td align="center">返回当前Class对象的父类的Class对象</td></tr><tr><td align="center">Class[] getinterfaces()</td><td align="center">获取当前Class对象的接口</td></tr><tr><td align="center">ClassLoader getClassLoader()</td><td align="center">返回该类的类加载器</td></tr><tr><td align="center">Constructor[] getConstructors()</td><td align="center">返回一个包含某些Constructor对象的数组</td></tr><tr><td align="center">Method getMothed(String name,Class.. T)</td><td align="center">返回一个Method对象,此对象的形参类型为paramType</td></tr><tr><td align="center">Field[] getDeclaredFields()</td><td align="center">返回Field对象的一个数组</td></tr></tbody></table><h3 id="获取Class类的实例"><a href="#获取Class类的实例" class="headerlink" title="获取Class类的实例"></a>获取Class类的实例</h3><p>若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Class clazz= Person.class;</span><br></pre></td></tr></table></figure><p>已知某个类的实例,调用该实例的getClass()方法获取Class对象</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Class</span> <span class="variable">clazz</span> <span class="operator">=</span> person.getClass();</span><br></pre></td></tr></table></figure><p>已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取</p><p>可能抛出ClassNotFoundException</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Class</span> <span class="variable">clazz</span> <span class="operator">=</span> Class.forName(<span class="string">"demo01.Student"</span>);</span><br></pre></td></tr></table></figure><p>内置基本数据类型可以直接用类名.Type</p><p>还可以利用ClassLoader</p><p>示例:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test02</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> ClassNotFoundException {</span><br><span class="line"> <span class="type">Person</span> <span class="variable">person</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Student</span>();</span><br><span class="line"> System.out.println(<span class="string">"这个人是"</span> + person.name);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//方式一:通过对象获得</span></span><br><span class="line"> <span class="type">Class</span> <span class="variable">c1</span> <span class="operator">=</span> person.getClass();</span><br><span class="line"> System.out.println(c1.hashCode());</span><br><span class="line"></span><br><span class="line"> <span class="comment">//方式二:forName获得</span></span><br><span class="line"> <span class="type">Class</span> <span class="variable">c2</span> <span class="operator">=</span> Class.forName(<span class="string">"com.xzw.reflection.Student"</span>);</span><br><span class="line"> System.out.println(c2.hashCode());</span><br><span class="line"></span><br><span class="line"> <span class="comment">//通过类名.class获得</span></span><br><span class="line"> Class<Student> c3 = Student.class;</span><br><span class="line"> System.out.println(c3.hashCode());</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获得父类类型</span></span><br><span class="line"> <span class="type">Class</span> <span class="variable">c5</span> <span class="operator">=</span> c1.getSuperclass();</span><br><span class="line"> System.out.println(c5);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@NoArgsConstructor</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span> {</span><br><span class="line"> String name;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Student</span> <span class="keyword">extends</span> <span class="title class_">Person</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">Student</span><span class="params">()</span> {</span><br><span class="line"> <span class="built_in">this</span>.name = <span class="string">"学生"</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Teacher</span> <span class="keyword">extends</span> <span class="title class_">Person</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">Teacher</span><span class="params">()</span> {</span><br><span class="line"> <span class="built_in">this</span>.name = <span class="string">"老师"</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">结果</span><br><span class="line">------------------------------------------</span><br><span class="line">这个人是学生</span><br><span class="line"><span class="number">1836019240</span></span><br><span class="line"><span class="number">1836019240</span></span><br><span class="line"><span class="number">1836019240</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">com</span>.xzw.reflection.Person</span><br></pre></td></tr></table></figure><h3 id="哪些类型可以有Class对象"><a href="#哪些类型可以有Class对象" class="headerlink" title="哪些类型可以有Class对象"></a>哪些类型可以有Class对象</h3><ul><li>class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类</li><li>interface:接口</li><li>[]:数组</li><li>enum:枚举</li><li>annotation:注解@interface</li><li>primitive type:基本数据类型</li><li>void</li></ul><p>测试:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test03</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> <span class="type">Class</span> <span class="variable">c1</span> <span class="operator">=</span> Object.class; <span class="comment">//类</span></span><br><span class="line"> <span class="type">Class</span> <span class="variable">c2</span> <span class="operator">=</span> Comparable.class; <span class="comment">//接口</span></span><br><span class="line"> <span class="type">Class</span> <span class="variable">c3</span> <span class="operator">=</span> String[].class;<span class="comment">// 一维数组</span></span><br><span class="line"> <span class="type">Class</span> <span class="variable">c4</span> <span class="operator">=</span> <span class="type">int</span>[][].class; <span class="comment">//二维数组</span></span><br><span class="line"> <span class="type">Class</span> <span class="variable">c5</span> <span class="operator">=</span> Override.class; <span class="comment">//注解</span></span><br><span class="line"> <span class="type">Class</span> <span class="variable">c6</span> <span class="operator">=</span> ElementType .class; <span class="comment">//枚举</span></span><br><span class="line"> <span class="type">Class</span> <span class="variable">c7</span> <span class="operator">=</span> Integer.class; <span class="comment">//基本数据类型</span></span><br><span class="line"> <span class="type">Class</span> <span class="variable">c8</span> <span class="operator">=</span> <span class="keyword">void</span>.class; <span class="comment">//void</span></span><br><span class="line"> <span class="type">Class</span> <span class="variable">c9</span> <span class="operator">=</span> Class.class;<span class="comment">//class</span></span><br><span class="line"></span><br><span class="line"> System.out.println(c1);</span><br><span class="line"> System.out.println(c2);</span><br><span class="line"> System.out.println(c3);</span><br><span class="line"> System.out.println(c4);</span><br><span class="line"> System.out.println(c5);</span><br><span class="line"> System.out.println(c6);</span><br><span class="line"> System.out.println(c7);</span><br><span class="line"> System.out.println(c8);</span><br><span class="line"> System.out.println(c9);</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//只要元素类型与维度一样,就是同一个class</span></span><br><span class="line"> <span class="type">int</span>[] a = <span class="keyword">new</span> <span class="title class_">int</span>[<span class="number">10</span>];</span><br><span class="line"> <span class="type">int</span>[] b = <span class="keyword">new</span> <span class="title class_">int</span>[<span class="number">100</span>];</span><br><span class="line"> System.out.println(a.getClass() .hashCode()) ;</span><br><span class="line"> System.out.println(b.getClass() .hashCode()) ;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">结果</span><br><span class="line">-------------------------</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">java</span>.lang.Object</span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">java</span>.lang.Comparable</span><br><span class="line">class [Ljava.lang.String;</span><br><span class="line">class [[I</span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">java</span>.lang.Override</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">java</span>.lang.annotation.ElementType</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">java</span>.lang.Integer</span><br><span class="line"><span class="keyword">void</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">java</span>.lang.Class</span><br><span class="line"><span class="number">1836019240</span></span><br><span class="line"><span class="number">1836019240</span></span><br></pre></td></tr></table></figure><p>两个长度不一样的int数组,由于都是int类型所以hashcode一样</p><p>一个类可以多个对象,但对象又是不同的内存地址 </p><h3 id="java内存分析"><a href="#java内存分析" class="headerlink" title="java内存分析"></a>java内存分析</h3><p><a href="https://imgse.com/i/ppVSCNQ"><img src="https://s1.ax1x.com/2023/03/05/ppVSCNQ.png" alt="ppVSCNQ.png"></a></p><h3 id="类的加载过程"><a href="#类的加载过程" class="headerlink" title="类的加载过程"></a>类的加载过程</h3><p><a href="https://imgse.com/i/ppVpUs0"><img src="https://s1.ax1x.com/2023/03/05/ppVpUs0.png" alt="ppVpUs0.png"></a></p><ul><li><p>加载:</p><ul><li>将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构然后生成一个代表这个类的java.lang.Class对象</li></ul></li><li><p>链接:将Java类的二进制代码合并到JVM的运行状态之中的过程</p><ul><li>验证:确保加载的类信息符合JVM规范,没有安全方面的问题</li><li>准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配</li><li>解析:虚拟机常量池内的符号引用 (常量名)替换为直接引用(地址)的过程</li></ul></li><li><p>初始化:</p><ul><li><p>执行类构造器<clinit>(方法的过程。类构造器<clinit>()方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。 (类构造器是构造类信息的,不是构造该类对象的构造器)</clinit></clinit></p></li><li><p>当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。</p></li><li><p>虚拟机会保证一个类的<clinit>(方法在多线程环境中被正确加锁和同步。</clinit></p></li></ul></li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test04</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> <span class="type">A</span> <span class="variable">a</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">A</span>();</span><br><span class="line"> System.out.println(A.m);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">A</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">static</span> {</span><br><span class="line"> System.out.println(<span class="string">"A类静态代码块初始化"</span>);</span><br><span class="line"> m = <span class="number">300</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">static</span> <span class="type">int</span> <span class="variable">m</span> <span class="operator">=</span> <span class="number">100</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">A</span><span class="params">()</span> {</span><br><span class="line"> System.out.println(<span class="string">"A类的无参构造初始化"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">结果</span><br><span class="line">---------------------------</span><br><span class="line">A类静态代码块初始化</span><br><span class="line">A类的无参构造初始化</span><br><span class="line"><span class="number">100</span></span><br></pre></td></tr></table></figure><p><a href="https://imgse.com/i/ppVdHOJ"><img src="https://s1.ax1x.com/2023/03/06/ppVdHOJ.png" alt="ppVdHOJ.png"></a></p><h3 id="什么时候会发生类初始化"><a href="#什么时候会发生类初始化" class="headerlink" title="什么时候会发生类初始化"></a>什么时候会发生类初始化</h3><ul><li><p>类的主动引用(一定会发生类的初始化)</p><ul><li>当虚拟机启动,先初始化main方法所在的类</li><li>new一个类的对象</li><li>调用类的静态成员(除了final常量)和静态方法</li><li>使用java.lang.reflect包的方法对类进行反射调用</li><li>当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类</li></ul></li><li><p>类的被动引用(不会发生类的初始化)</p><ul><li>当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化</li><li>通过数组定义类引用,不会触发此类的初始化</li><li>引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test05</span> {</span><br><span class="line"> <span class="keyword">static</span> {</span><br><span class="line"> System.out.println(<span class="string">"main类被加载"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> ClassNotFoundException {</span><br><span class="line"> <span class="comment">//1.主动引用</span></span><br><span class="line"> <span class="type">Son</span> <span class="variable">son</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Son</span>();</span><br><span class="line"></span><br><span class="line"> <span class="comment">//2.反射也会产生主动引用</span></span><br><span class="line"> Class.forName(<span class="string">"com.xzw.reflection.Son"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//3.访问静态变量</span></span><br><span class="line"> System.out.println(Son.m);</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//4.不会产生类的引用的方法,引用父类静态变量</span></span><br><span class="line"> System.out.println(Son.b);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//5.通过数组定义类引用</span></span><br><span class="line"> Son[] array = <span class="keyword">new</span> <span class="title class_">Son</span>[<span class="number">5</span>];</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//6.引用常量</span></span><br><span class="line"> System.out.println(Son.M);</span><br><span class="line"> </span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Father</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">static</span> <span class="type">int</span> <span class="variable">b</span> <span class="operator">=</span> <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">static</span> {</span><br><span class="line"> System.out.println(<span class="string">"父类被加载"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Son</span> <span class="keyword">extends</span> <span class="title class_">Father</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">static</span> {</span><br><span class="line"> System.out.println(<span class="string">"子类被加载"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">static</span> <span class="type">int</span> <span class="variable">m</span> <span class="operator">=</span><span class="number">100</span>;</span><br><span class="line"> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">M</span> <span class="operator">=</span> <span class="number">1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">结果</span><br><span class="line">-------------------------------------</span><br><span class="line"><span class="number">1.</span></span><br><span class="line">main类被加载</span><br><span class="line">父类被加载</span><br><span class="line">子类被加载 </span><br><span class="line"><span class="number">2.</span></span><br><span class="line">main类被加载</span><br><span class="line">父类被加载</span><br><span class="line">子类被加载</span><br><span class="line"><span class="number">3.</span></span><br><span class="line">main类被加载</span><br><span class="line">父类被加载</span><br><span class="line">子类被加载</span><br><span class="line"><span class="number">100</span></span><br><span class="line"><span class="number">4.</span></span><br><span class="line">main类被加载</span><br><span class="line">父类被加载</span><br><span class="line"><span class="number">2</span></span><br><span class="line"><span class="number">5.</span> </span><br><span class="line">main类被加载</span><br><span class="line"><span class="number">6.</span></span><br><span class="line">main类被加载</span><br><span class="line"><span class="number">1</span></span><br></pre></td></tr></table></figure></li></ul><h3 id="类加载器的作用"><a href="#类加载器的作用" class="headerlink" title="类加载器的作用"></a>类加载器的作用</h3><ul><li><p>类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的iava.lang.Class对象,作为方法区中类数据的访问入口。</p></li><li><p>类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象</p></li></ul><p><a href="https://imgse.com/i/ppZF4pD"><img src="https://s1.ax1x.com/2023/03/06/ppZF4pD.png" alt="ppZF4pD.png"></a></p><p><a href="https://imgse.com/i/ppZklAx"><img src="https://s1.ax1x.com/2023/03/06/ppZklAx.png" alt="ppZklAx.png"></a></p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test06</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> ClassNotFoundException {</span><br><span class="line"> <span class="comment">//获取类的加载器</span></span><br><span class="line"> <span class="type">ClassLoader</span> <span class="variable">systemClassLoader</span> <span class="operator">=</span> ClassLoader.getSystemClassLoader();</span><br><span class="line"> System.out.println(systemClassLoader);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获取系统类加载器的父类加载器 -->扩展类加载器</span></span><br><span class="line"> <span class="type">ClassLoader</span> <span class="variable">parent</span> <span class="operator">=</span> systemClassLoader.getParent();</span><br><span class="line"> System.out.println(parent);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获取扩展类加载器的父类加载器 -->根加载器</span></span><br><span class="line"> <span class="type">ClassLoader</span> <span class="variable">parent1</span> <span class="operator">=</span> parent.getParent();</span><br><span class="line"> System.out.println(parent1);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//测试当前类是哪个加载器加载的</span></span><br><span class="line"> <span class="type">ClassLoader</span> <span class="variable">classLoader</span> <span class="operator">=</span> Class.forName(<span class="string">"com.xzw.reflection.Test06"</span>).getClassLoader();</span><br><span class="line"> System.out.println(classLoader);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//测试JDK内置的类是谁加载的</span></span><br><span class="line"> classLoader = Class.forName(<span class="string">"java.lang.Object"</span>).getClassLoader();</span><br><span class="line"> System.out.println(classLoader);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//如何获得系统类加载器可以加载的路径</span></span><br><span class="line"> System.out.println(System.getProperty(<span class="string">"java.class.path"</span>));</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">结果</span><br><span class="line">---------------------------------</span><br><span class="line">sun.misc.Launcher$AppClassLoader@18b4aac2</span><br><span class="line">sun.misc.Launcher$ExtClassLoader@6d6f6e28</span><br><span class="line"><span class="literal">null</span></span><br><span class="line">sun.misc.Launcher$AppClassLoader@18b4aac2</span><br><span class="line"><span class="literal">null</span></span><br><span class="line">D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\charsets.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\deploy.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\ext\access-bridge-<span class="number">64.</span>jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\ext\cldrdata.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\ext\dnsns.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\ext\jaccess.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\ext\jfxrt.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\ext\localedata.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\ext\nashorn.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\ext\sunec.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\ext\sunjce_provider.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\ext\sunmscapi.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\ext\sunpkcs11.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\ext\zipfs.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\javaws.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\jce.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\jfr.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\jfxswt.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\jsse.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\management-agent.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\plugin.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\resources.jar;D:\java\jdk1<span class="number">.8</span><span class="number">.0_291</span>\jre\lib\rt.jar;D:\workspace\workspace-idea\annotation\target\classes;D:\java\apache-maven-<span class="number">3.6</span><span class="number">.1</span>\maven-repo\org\projectlombok\lombok\<span class="number">1.18</span><span class="number">.20</span>\lombok-<span class="number">1.18</span><span class="number">.20</span>.jar;D:\IntelliJ IDEA <span class="number">2021.3</span>\lib\idea_rt.jar </span><br></pre></td></tr></table></figure><h3 id="获取运行时类的完整结构"><a href="#获取运行时类的完整结构" class="headerlink" title="获取运行时类的完整结构"></a>获取运行时类的完整结构</h3><p>通过反射获取运行时类的完整结松</p><p>Field、Method、Constructor、 Superclass、Interface、Annotation</p><ul><li>实现的全部接口</li><li>所继承的父类</li><li>全部的构造器</li><li>全部的方法</li><li>全部的Field</li><li>注解</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo07</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> ClassNotFoundException, NoSuchMethodException {</span><br><span class="line"> <span class="type">Class</span> <span class="variable">c1</span> <span class="operator">=</span> Class.forName(<span class="string">"com.xzw.reflection.User"</span>);</span><br><span class="line"> <span class="type">User</span> <span class="variable">user</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">User</span>();</span><br><span class="line"> c1 = user.getClass();</span><br><span class="line"> System.out.println(c1.getName());</span><br><span class="line"> System.out.println(c1.getSimpleName());</span><br><span class="line"></span><br><span class="line"> <span class="comment">//只能找到public属性</span></span><br><span class="line"> Field[] fields = c1.getFields();</span><br><span class="line"></span><br><span class="line"> fields = c1.getDeclaredFields();</span><br><span class="line"> <span class="keyword">for</span> (Field field : fields) {</span><br><span class="line"> System.out.println(field);</span><br><span class="line"> }</span><br><span class="line"> System.out.println(<span class="string">"---------------------------------"</span>);</span><br><span class="line"></span><br><span class="line"> Method[] methods = c1.getMethods();</span><br><span class="line"> <span class="keyword">for</span> (Method method : methods) {</span><br><span class="line"> System.out.println(<span class="string">"正常的"</span> + method);</span><br><span class="line"> }</span><br><span class="line"> methods = c1.getDeclaredMethods();</span><br><span class="line"> <span class="keyword">for</span> (Method method : methods) {</span><br><span class="line"> System.out.println(<span class="string">"getDeclaredMethods"</span> + method);</span><br><span class="line"> }</span><br><span class="line"> System.out.println(<span class="string">"---------------------------------"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获得指定方法</span></span><br><span class="line"> <span class="type">Method</span> <span class="variable">getName</span> <span class="operator">=</span> c1.getMethod(<span class="string">"getName"</span>, <span class="literal">null</span>);</span><br><span class="line"> <span class="type">Method</span> <span class="variable">setName</span> <span class="operator">=</span> c1.getMethod(<span class="string">"setName"</span>, String.class);</span><br><span class="line"> System.out.println(getName);</span><br><span class="line"> System.out.println(setName);</span><br><span class="line"> System.out.println(<span class="string">"---------------------------------"</span>);</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//获得指定的构造器</span></span><br><span class="line"> Constructor[] constructors = c1.getConstructors();</span><br><span class="line"> <span class="keyword">for</span> (Constructor constructor : constructors) {</span><br><span class="line"> System.out.println(constructor);</span><br><span class="line"> }</span><br><span class="line"> constructors = c1.getDeclaredConstructors();</span><br><span class="line"> <span class="keyword">for</span> (Constructor constructor : constructors) {</span><br><span class="line"> System.out.println(constructor);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">结果</span><br><span class="line">--------------------------------</span><br><span class="line">com.xzw.reflection.User</span><br><span class="line">User</span><br><span class="line"><span class="keyword">private</span> java.lang.String com.xzw.reflection.User.name</span><br><span class="line"><span class="keyword">private</span> <span class="type">int</span> com.xzw.reflection.User.id</span><br><span class="line"><span class="keyword">private</span> <span class="type">int</span> com.xzw.reflection.User.age</span><br><span class="line">---------------------------------</span><br><span class="line">正常的<span class="keyword">public</span> <span class="type">boolean</span> com.xzw.reflection.User.equals(java.lang.Object)</span><br><span class="line">正常的<span class="keyword">public</span> java.lang.String com.xzw.reflection.User.toString()</span><br><span class="line">正常的<span class="keyword">public</span> <span class="type">int</span> com.xzw.reflection.User.hashCode()</span><br><span class="line">正常的<span class="keyword">public</span> java.lang.String com.xzw.reflection.User.getName()</span><br><span class="line">正常的<span class="keyword">public</span> <span class="type">int</span> com.xzw.reflection.User.getId()</span><br><span class="line">正常的<span class="keyword">public</span> <span class="keyword">void</span> com.xzw.reflection.User.setName(java.lang.String)</span><br><span class="line">正常的<span class="keyword">public</span> <span class="type">int</span> com.xzw.reflection.User.getAge()</span><br><span class="line">正常的<span class="keyword">public</span> <span class="keyword">void</span> com.xzw.reflection.User.setId(<span class="type">int</span>)</span><br><span class="line">正常的<span class="keyword">public</span> <span class="keyword">void</span> com.xzw.reflection.User.setAge(<span class="type">int</span>)</span><br><span class="line">正常的<span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> java.lang.Object.wait() <span class="keyword">throws</span> java.lang.InterruptedException</span><br><span class="line">正常的<span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> java.lang.Object.wait(<span class="type">long</span>,<span class="type">int</span>) <span class="keyword">throws</span> java.lang.InterruptedException</span><br><span class="line">正常的<span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">native</span> <span class="keyword">void</span> java.lang.Object.wait(<span class="type">long</span>) <span class="keyword">throws</span> java.lang.InterruptedException</span><br><span class="line">正常的<span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">native</span> java.lang.Class java.lang.Object.getClass()</span><br><span class="line">正常的<span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">native</span> <span class="keyword">void</span> java.lang.Object.notify()</span><br><span class="line">正常的<span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">native</span> <span class="keyword">void</span> java.lang.Object.notifyAll()</span><br><span class="line">getDeclaredMethodspublic <span class="type">boolean</span> com.xzw.reflection.User.equals(java.lang.Object)</span><br><span class="line">getDeclaredMethodspublic java.lang.String com.xzw.reflection.User.toString()</span><br><span class="line">getDeclaredMethodspublic <span class="type">int</span> com.xzw.reflection.User.hashCode()</span><br><span class="line">getDeclaredMethodspublic java.lang.String com.xzw.reflection.User.getName()</span><br><span class="line">getDeclaredMethodspublic <span class="type">int</span> com.xzw.reflection.User.getId()</span><br><span class="line">getDeclaredMethodspublic <span class="keyword">void</span> com.xzw.reflection.User.setName(java.lang.String)</span><br><span class="line">getDeclaredMethodspublic <span class="type">int</span> com.xzw.reflection.User.getAge()</span><br><span class="line">getDeclaredMethodspublic <span class="keyword">void</span> com.xzw.reflection.User.setId(<span class="type">int</span>)</span><br><span class="line">getDeclaredMethodspublic <span class="keyword">void</span> com.xzw.reflection.User.setAge(<span class="type">int</span>)</span><br><span class="line">getDeclaredMethodsprotected <span class="type">boolean</span> com.xzw.reflection.User.canEqual(java.lang.Object)</span><br><span class="line">---------------------------------</span><br><span class="line"><span class="keyword">public</span> java.lang.String com.xzw.reflection.User.getName()</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> com.xzw.reflection.User.setName(java.lang.String)</span><br><span class="line">---------------------------------</span><br><span class="line"><span class="keyword">public</span> com.xzw.reflection.User()</span><br><span class="line"><span class="keyword">public</span> com.xzw.reflection.User(java.lang.String,<span class="type">int</span>,<span class="type">int</span>)</span><br><span class="line"><span class="keyword">public</span> com.xzw.reflection.User()</span><br><span class="line"><span class="keyword">public</span> com.xzw.reflection.User(java.lang.String,<span class="type">int</span>,<span class="type">int</span>)</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test08</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {</span><br><span class="line"> <span class="type">Class</span> <span class="variable">c1</span> <span class="operator">=</span> Class.forName(<span class="string">"com.xzw.reflection.User"</span>);</span><br><span class="line"> <span class="comment">//本质是调用了类的无参构造器</span></span><br><span class="line"> <span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> c1.newInstance();</span><br><span class="line"> System.out.println(o);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//通过构造器创建对象</span></span><br><span class="line"> <span class="type">Constructor</span> <span class="variable">constructor</span> <span class="operator">=</span> c1.getDeclaredConstructor(String.class, <span class="type">int</span>.class, <span class="type">int</span>.class);</span><br><span class="line"> <span class="type">Object</span> <span class="variable">o1</span> <span class="operator">=</span> constructor.newInstance(<span class="string">"xc"</span>, <span class="number">1</span>,<span class="number">1</span>);</span><br><span class="line"> System.out.println(o1);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//通过反射获取一个方法</span></span><br><span class="line"> <span class="type">User</span> <span class="variable">o2</span> <span class="operator">=</span> (User) c1.newInstance();</span><br><span class="line"> <span class="type">Method</span> <span class="variable">setName</span> <span class="operator">=</span> c1.getDeclaredMethod(<span class="string">"setName"</span>, String.class);</span><br><span class="line"> <span class="comment">//invoke:激活</span></span><br><span class="line"> <span class="comment">//(对象,方法的值)</span></span><br><span class="line"> setName.invoke(o2, <span class="string">"xz"</span>);</span><br><span class="line"> System.out.println(o2.getName());</span><br><span class="line"></span><br><span class="line"> <span class="comment">//通过反射操作属性</span></span><br><span class="line"> <span class="type">User</span> <span class="variable">o3</span> <span class="operator">=</span> (User) c1.newInstance();</span><br><span class="line"> <span class="type">Field</span> <span class="variable">name</span> <span class="operator">=</span> c1.getDeclaredField(<span class="string">"name"</span>);</span><br><span class="line"> <span class="comment">//不能直接操作私有属性,我们需要关闭程序的安全检测,属性或者你的方法的setAccessible(true)</span></span><br><span class="line"> name.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> name.set(o3, <span class="string">"xz2"</span>);</span><br><span class="line"> System.out.println(o3.getName());</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">结果</span><br><span class="line">-----------------------------------</span><br><span class="line">User(name=<span class="literal">null</span>, id=<span class="number">0</span>, age=<span class="number">0</span>)</span><br><span class="line">User(name=xc, id=<span class="number">1</span>, age=<span class="number">1</span>)</span><br><span class="line">xz</span><br><span class="line">xz2</span><br></pre></td></tr></table></figure><p>性能对比:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test09</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InvocationTargetException, NoSuchMethodException, IllegalAccessException {</span><br><span class="line"> test01();</span><br><span class="line"> test02();</span><br><span class="line"> test03();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">test01</span><span class="params">()</span> {</span><br><span class="line"> <span class="type">User</span> <span class="variable">user</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">User</span>();</span><br><span class="line"></span><br><span class="line"> <span class="type">Long</span> <span class="variable">startTime</span> <span class="operator">=</span> System.currentTimeMillis();</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < <span class="number">1000000000</span>; i++) {</span><br><span class="line"> user.getName();</span><br><span class="line"> }</span><br><span class="line"> <span class="type">Long</span> <span class="variable">endTime</span> <span class="operator">=</span> System.currentTimeMillis();</span><br><span class="line"> System.out.println(<span class="string">"普通方法执行10亿次:"</span> + (endTime - startTime) + <span class="string">"ms"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">test02</span><span class="params">()</span> <span class="keyword">throws</span> NoSuchMethodException, InvocationTargetException, IllegalAccessException {</span><br><span class="line"> <span class="type">User</span> <span class="variable">user</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">User</span>();</span><br><span class="line"> <span class="type">Class</span> <span class="variable">c1</span> <span class="operator">=</span> user.getClass();</span><br><span class="line"></span><br><span class="line"> <span class="type">Method</span> <span class="variable">getName</span> <span class="operator">=</span> c1.getDeclaredMethod(<span class="string">"getName"</span>, <span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line"> <span class="type">Long</span> <span class="variable">startTime</span> <span class="operator">=</span> System.currentTimeMillis();</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < <span class="number">1000000000</span>; i++) {</span><br><span class="line"> getName.invoke(user,<span class="literal">null</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="type">Long</span> <span class="variable">endTime</span> <span class="operator">=</span> System.currentTimeMillis();</span><br><span class="line"> System.out.println(<span class="string">"反射方法执行10亿次:"</span> + (endTime - startTime) + <span class="string">"ms"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">test03</span><span class="params">()</span> <span class="keyword">throws</span> NoSuchMethodException, InvocationTargetException, IllegalAccessException {</span><br><span class="line"> <span class="type">User</span> <span class="variable">user</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">User</span>();</span><br><span class="line"> <span class="type">Class</span> <span class="variable">c1</span> <span class="operator">=</span> user.getClass();</span><br><span class="line"></span><br><span class="line"> <span class="type">Method</span> <span class="variable">getName</span> <span class="operator">=</span> c1.getDeclaredMethod(<span class="string">"getName"</span>, <span class="literal">null</span>);</span><br><span class="line"> getName.setAccessible(<span class="literal">true</span>);</span><br><span class="line"> <span class="type">Long</span> <span class="variable">startTime</span> <span class="operator">=</span> System.currentTimeMillis();</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < <span class="number">1000000000</span>; i++) {</span><br><span class="line"> getName.invoke(user,<span class="literal">null</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="type">Long</span> <span class="variable">endTime</span> <span class="operator">=</span> System.currentTimeMillis();</span><br><span class="line"> System.out.println(<span class="string">"关闭检测执行10亿次:"</span> + (endTime - startTime) + <span class="string">"ms"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">结果:</span><br><span class="line">------------------------------------------</span><br><span class="line">普通方法执行<span class="number">10</span>亿次:4ms</span><br><span class="line">反射方法执行<span class="number">10</span>亿次:3247ms</span><br><span class="line">关闭检测执行<span class="number">10</span>亿次:1220ms</span><br></pre></td></tr></table></figure><h3 id="反射操作泛型"><a href="#反射操作泛型" class="headerlink" title="反射操作泛型"></a>反射操作泛型</h3><ul><li>Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题,但是,一旦编译完成,所有和泛型有关的类型全部擦除</li><li>为了通过反射操作这些类型,Java新增了 ParameterizedType,GenericArrayType,TypeVariable 和 WildcardType 几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型.</li><li>ParameterizedType:表示一种参数化类型比如Collection<String></String></li><li>GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型</li><li>TypeVariable:是各种类型变量的公共父接口</li><li>WildcardType:代表一种通配符类型表达式</li></ul><p>通过反射获取泛型:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test10</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> NoSuchMethodException {</span><br><span class="line"> <span class="type">Method</span> <span class="variable">method</span> <span class="operator">=</span> Test10.class.getMethod(<span class="string">"test01"</span>, Map.class, List.class);</span><br><span class="line"> Type[] genericParameterTypes = method.getGenericParameterTypes();</span><br><span class="line"> <span class="keyword">for</span> (Type genericParameterType : genericParameterTypes) {</span><br><span class="line"> System.out.println(<span class="string">"#"</span> + genericParameterType);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> method = Test10.class.getMethod(<span class="string">"test02"</span>, <span class="literal">null</span>);</span><br><span class="line"> <span class="type">Type</span> <span class="variable">type</span> <span class="operator">=</span> method.getGenericReturnType();</span><br><span class="line"> System.out.println(type);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test01</span><span class="params">(Map<String,User> map, List<User> list)</span> {</span><br><span class="line"> System.out.println(<span class="string">"test01"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> Map<String,User> <span class="title function_">test02</span><span class="params">()</span> {</span><br><span class="line"> System.out.println(<span class="string">"test02"</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">结果:</span><br><span class="line">---------------------------------------------------</span><br><span class="line">#java.util.Map<java.lang.String, com.xzw.reflection.User></span><br><span class="line">#java.util.List<com.xzw.reflection.User></span><br><span class="line">java.util.Map<java.lang.String, com.xzw.reflection.User> </span><br></pre></td></tr></table></figure><h3 id="反射操作注解"><a href="#反射操作注解" class="headerlink" title="反射操作注解"></a>反射操作注解</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test11</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> ClassNotFoundException, NoSuchFieldException {</span><br><span class="line"> <span class="type">Class</span> <span class="variable">c1</span> <span class="operator">=</span> Class.forName(<span class="string">"com.xzw.reflection.Student2"</span>);</span><br><span class="line"> <span class="comment">//通过反射获取注解</span></span><br><span class="line"> Annotation[] annotations = c1.getAnnotations();</span><br><span class="line"> <span class="keyword">for</span> (Annotation annotation : annotations) {</span><br><span class="line"> System.out.println(annotation);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获得注解的value的值</span></span><br><span class="line"> <span class="type">Table</span> <span class="variable">annotation</span> <span class="operator">=</span> (Table)c1.getAnnotation(Table.class);</span><br><span class="line"> <span class="type">String</span> <span class="variable">value</span> <span class="operator">=</span> annotation.value();</span><br><span class="line"> System.out.println(value);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获得类指定的注解</span></span><br><span class="line"> java.lang.reflect.<span class="type">Field</span> <span class="variable">field</span> <span class="operator">=</span> c1.getDeclaredField(<span class="string">"name"</span>);</span><br><span class="line"> <span class="type">Field</span> <span class="variable">annotation1</span> <span class="operator">=</span> field.getAnnotation(Field.class);</span><br><span class="line"> System.out.println(annotation1.columnName());</span><br><span class="line"> System.out.println(annotation1.type());</span><br><span class="line"> System.out.println(annotation1.length());</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="meta">@NoArgsConstructor</span></span><br><span class="line"><span class="meta">@Table("db_student")</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Student2</span> {</span><br><span class="line"> <span class="meta">@Field(columnName = "db_id", type = "int", length = 10)</span></span><br><span class="line"> <span class="keyword">private</span> <span class="type">int</span> id;</span><br><span class="line"> <span class="meta">@Field(columnName = "db_age", type = "int", length = 10)</span></span><br><span class="line"> <span class="keyword">private</span> <span class="type">int</span> age;</span><br><span class="line"> <span class="meta">@Field(columnName = "db_name", type = "varchar", length = 3)</span></span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//类名的注解</span></span><br><span class="line"><span class="meta">@Target(ElementType.TYPE)</span></span><br><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@interface</span> Table {</span><br><span class="line"> String <span class="title function_">value</span><span class="params">()</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//属性的注解</span></span><br><span class="line"><span class="meta">@Target(ElementType.FIELD)</span></span><br><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@interface</span> Field {</span><br><span class="line"> String <span class="title function_">columnName</span><span class="params">()</span>;</span><br><span class="line"> String <span class="title function_">type</span><span class="params">()</span>;</span><br><span class="line"> <span class="type">int</span> <span class="title function_">length</span><span class="params">()</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">结果:</span><br><span class="line">-------------------------------------------</span><br><span class="line"><span class="meta">@com</span>.xzw.reflection.Table(value=db_student)</span><br><span class="line">db_student</span><br><span class="line">db_name</span><br><span class="line">varchar</span><br><span class="line"><span class="number">3</span></span><br></pre></td></tr></table></figure><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p><a href="https://www.bilibili.com/video/BV1p4411P7V3?p=1&vd_source=d28a32457971d5e2f307a6c96eb52f60">注解和反射</a></p>]]></content>
<tags>
<tag> java </tag>
</tags>
</entry>
<entry>
<title>Docker学习</title>
<link href="/2022/07/03/Docker%E5%AD%A6%E4%B9%A0/"/>
<url>/2022/07/03/Docker%E5%AD%A6%E4%B9%A0/</url>
<content type="html"><![CDATA[<h1 id="Docker"><a href="#Docker" class="headerlink" title="Docker"></a>Docker</h1><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><blockquote><p>官网:<a href="https://docs.docker.com/">https://docs.docker.com</a></p><p>仓库:<a href="https://hub.docker.com/">https://hub.docker.com</a></p></blockquote><p>Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache 2.0 协议开源。</p><p>Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。</p><h3 id="Docker与虚拟机"><a href="#Docker与虚拟机" class="headerlink" title="Docker与虚拟机"></a>Docker与虚拟机</h3><p>虚拟机技术缺点︰</p><ol><li>资源占用十分多</li><li>冗余步骤多</li><li>启动慢</li></ol><blockquote><p>容器化</p></blockquote><p>docker采用的是容器化技术</p><p>容器化技术不是模拟的一个完整的操作系统</p><p>Docker和虚拟机技术的不同:</p><ul><li>传统虚拟机,虚拟出一套硬件,运行一个完整的操作系统,然后在这个系统上安装和运行软件</li><li>容器内的应用直接运行在宿主机的内核,容器是没有自己的内核的,也没有虚拟我们的硬件,所以就轻便了</li><li>每个容器间是互相隔离,每个容器内都有一个属于自己的文件系统,互不影响</li></ul><h2 id="Docker安装"><a href="#Docker安装" class="headerlink" title="Docker安装"></a>Docker安装</h2><h3 id="Docker的基本组成"><a href="#Docker的基本组成" class="headerlink" title="Docker的基本组成"></a>Docker的基本组成</h3><p><img src="/2022/07/03/Docker%E5%AD%A6%E4%B9%A0/1.jpg" alt="image-20220703231236493"></p><p><strong>镜像( image ) :</strong></p><p>docker镜像就好比是一个模板,可以通过这个模板来创建容器服务,tomcat镜像-==> run ==> tomcat01容器(提供服务器),通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中)。</p><p><strong>容器( container ) :</strong></p><p>Docker利用容器技术,独立运行一个或者一个组应用,通过镜像来创建的。</p><p>启动,停止,删除,等基本命令</p><p>可以把这个容器理解为一个简易的linux系统</p><p><strong>仓库( repository ) :</strong></p><p>仓库就是存放镜像的地方</p><p>仓库分为公有仓库和私有仓库</p><p>Docker Hub (默认是国外的)</p><p>阿里云….都有容器服务器(配置镜像加速)</p><h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><p>linux环境</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">[root@izbp1ecuerkuubxjbrduatz /]# uname -r #查看系统内核版本</span><br><span class="line">3.10.0-514.26.2.el7.x86_64</span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz /]# cat /etc/os-release #查看系统版本</span><br><span class="line">NAME="CentOS Linux"</span><br><span class="line">VERSION="7 (Core)"</span><br><span class="line">ID="centos"</span><br><span class="line">ID_LIKE="rhel fedora"</span><br><span class="line">VERSION_ID="7"</span><br><span class="line">PRETTY_NAME="CentOS Linux 7 (Core)"</span><br><span class="line">ANSI_COLOR="0;31"</span><br><span class="line">CPE_NAME="cpe:/o:centos:centos:7"</span><br><span class="line">HOME_URL="https://www.centos.org/"</span><br><span class="line">BUG_REPORT_URL="https://bugs.centos.org/"</span><br><span class="line"></span><br><span class="line">CENTOS_MANTISBT_PROJECT="CentOS-7"</span><br><span class="line">CENTOS_MANTISBT_PROJECT_VERSION="7"</span><br><span class="line">REDHAT_SUPPORT_PRODUCT="centos"</span><br><span class="line">REDHAT_SUPPORT_PRODUCT_VERSION="7"</span><br></pre></td></tr></table></figure><p>根据官方文档,在安装之前,要先卸载旧版本</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">1.卸载旧版本</span></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz /]# yum remove docker \</span><br><span class="line"><span class="meta prompt_">> </span><span class="language-bash">docker-client-latest \</span></span><br><span class="line"><span class="language-bash">> docker-common \</span></span><br><span class="line"><span class="language-bash">> docker-latest \</span></span><br><span class="line"><span class="language-bash">> docker-latest-logrotate \</span></span><br><span class="line"><span class="language-bash">> docker-logrotate \</span></span><br><span class="line"><span class="language-bash">> docker-engine</span></span><br><span class="line">Loaded plugins: fastestmirror</span><br><span class="line">No Match for argument: docker</span><br><span class="line">No Match for argument: docker-client-latest</span><br><span class="line">No Match for argument: docker-common</span><br><span class="line">No Match for argument: docker-latest</span><br><span class="line">No Match for argument: docker-latest-logrotate</span><br><span class="line">No Match for argument: docker-logrotate</span><br><span class="line">No Match for argument: docker-engine</span><br><span class="line">No Packages marked for removal</span><br></pre></td></tr></table></figure><p>安装包</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">命令:yum install -y yum-utils</span></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz /]# yum install -y yum-utils</span><br><span class="line">Loaded plugins: fastestmirror</span><br><span class="line">Repodata is over 2 weeks old. Install yum-cron? Or run: yum makecache fast</span><br><span class="line">base | 3.6 kB 00:00:00 </span><br><span class="line">epel | 4.7 kB 00:00:00 </span><br><span class="line">extras | 2.9 kB 00:00:00 </span><br><span class="line">updates | 2.9 kB 00:00:00 </span><br><span class="line">(1/5): epel/x86_64/group_gz | 96 kB 00:00:00 </span><br><span class="line">(2/5): epel/x86_64/updateinfo | 1.1 MB 00:00:00 </span><br><span class="line">(3/5): extras/7/x86_64/primary_db | 247 kB 00:00:00 </span><br><span class="line">(4/5): epel/x86_64/primary_db | 7.0 MB 00:00:00 </span><br><span class="line">(5/5): updates/7/x86_64/primary_db | 16 MB 00:00:00 </span><br><span class="line">Determining fastest mirrors</span><br><span class="line">Resolving Dependencies</span><br><span class="line"><span class="meta prompt_">--> </span><span class="language-bash">Running transaction check</span></span><br><span class="line"><span class="meta prompt_">---> </span><span class="language-bash">Package yum-utils.noarch 0:1.1.31-54.el7_8 will be installed</span></span><br><span class="line"><span class="meta prompt_">--> </span><span class="language-bash">Processing Dependency: python-kitchen <span class="keyword">for</span> package: yum-utils-1.1.31-54.el7_8.noarch</span></span><br><span class="line"><span class="meta prompt_">--> </span><span class="language-bash">Processing Dependency: libxml2-python <span class="keyword">for</span> package: yum-utils-1.1.31-54.el7_8.noarch</span></span><br><span class="line"><span class="meta prompt_">--> </span><span class="language-bash">Running transaction check</span></span><br><span class="line"><span class="meta prompt_">---> </span><span class="language-bash">Package libxml2-python.x86_64 0:2.9.1-6.el7_9.6 will be installed</span></span><br><span class="line"><span class="meta prompt_">--> </span><span class="language-bash">Processing Dependency: libxml2 = 2.9.1-6.el7_9.6 <span class="keyword">for</span> package: libxml2-python-2.9.1-6.el7_9.6.x86_64</span></span><br><span class="line"><span class="meta prompt_">---> </span><span class="language-bash">Package python-kitchen.noarch 0:1.1.1-5.el7 will be installed</span></span><br><span class="line"><span class="meta prompt_">--> </span><span class="language-bash">Processing Dependency: python-chardet <span class="keyword">for</span> package: python-kitchen-1.1.1-5.el7.noarch</span></span><br><span class="line"><span class="meta prompt_">--> </span><span class="language-bash">Running transaction check</span></span><br><span class="line"><span class="meta prompt_">---> </span><span class="language-bash">Package libxml2.x86_64 0:2.9.1-6.el7_2.3 will be updated</span></span><br><span class="line"><span class="meta prompt_">---> </span><span class="language-bash">Package libxml2.x86_64 0:2.9.1-6.el7_9.6 will be an update</span></span><br><span class="line"><span class="meta prompt_">---> </span><span class="language-bash">Package python-chardet.noarch 0:2.2.1-3.el7 will be installed</span></span><br><span class="line"><span class="meta prompt_">--> </span><span class="language-bash">Finished Dependency Resolution</span></span><br><span class="line"></span><br><span class="line">Dependencies Resolved</span><br><span class="line"></span><br><span class="line">========================================================================================</span><br><span class="line"> Package Arch Version Repository Size</span><br><span class="line">========================================================================================</span><br><span class="line">Installing:</span><br><span class="line"> yum-utils noarch 1.1.31-54.el7_8 base 122 k</span><br><span class="line">Installing for dependencies:</span><br><span class="line"> libxml2-python x86_64 2.9.1-6.el7_9.6 updates 247 k</span><br><span class="line"> python-chardet noarch 2.2.1-3.el7 base 227 k</span><br><span class="line"> python-kitchen noarch 1.1.1-5.el7 base 267 k</span><br><span class="line">Updating for dependencies:</span><br><span class="line"> libxml2 x86_64 2.9.1-6.el7_9.6 updates 668 k</span><br><span class="line"></span><br><span class="line">Transaction Summary</span><br><span class="line">========================================================================================</span><br><span class="line">Install 1 Package (+3 Dependent packages)</span><br><span class="line">Upgrade ( 1 Dependent package)</span><br><span class="line"></span><br><span class="line">Total download size: 1.5 M</span><br><span class="line">Downloading packages:</span><br><span class="line">Delta RPMs disabled because /usr/bin/applydeltarpm not installed.</span><br><span class="line">(1/5): python-chardet-2.2.1-3.el7.noarch.rpm | 227 kB 00:00:00 </span><br><span class="line">(2/5): libxml2-python-2.9.1-6.el7_9.6.x86_64.rpm | 247 kB 00:00:00 </span><br><span class="line">(3/5): libxml2-2.9.1-6.el7_9.6.x86_64.rpm | 668 kB 00:00:00 </span><br><span class="line">(4/5): yum-utils-1.1.31-54.el7_8.noarch.rpm | 122 kB 00:00:00 </span><br><span class="line">(5/5): python-kitchen-1.1.1-5.el7.noarch.rpm | 267 kB 00:00:00 </span><br><span class="line">----------------------------------------------------------------------------------------</span><br><span class="line">Total 6.5 MB/s | 1.5 MB 00:00 </span><br><span class="line">Running transaction check</span><br><span class="line">Running transaction test</span><br><span class="line">Transaction test succeeded</span><br><span class="line">Running transaction</span><br><span class="line"> Updating : libxml2-2.9.1-6.el7_9.6.x86_64 1/6 </span><br><span class="line"> Installing : libxml2-python-2.9.1-6.el7_9.6.x86_64 2/6 </span><br><span class="line"> Installing : python-chardet-2.2.1-3.el7.noarch 3/6 </span><br><span class="line"> Installing : python-kitchen-1.1.1-5.el7.noarch 4/6 </span><br><span class="line"> Installing : yum-utils-1.1.31-54.el7_8.noarch 5/6 </span><br><span class="line"> Cleanup : libxml2-2.9.1-6.el7_2.3.x86_64 6/6 </span><br><span class="line"> Verifying : python-chardet-2.2.1-3.el7.noarch 1/6 </span><br><span class="line"> Verifying : libxml2-2.9.1-6.el7_9.6.x86_64 2/6 </span><br><span class="line"> Verifying : libxml2-python-2.9.1-6.el7_9.6.x86_64 3/6 </span><br><span class="line"> Verifying : python-kitchen-1.1.1-5.el7.noarch 4/6 </span><br><span class="line"> Verifying : yum-utils-1.1.31-54.el7_8.noarch 5/6 </span><br><span class="line"> Verifying : libxml2-2.9.1-6.el7_2.3.x86_64 6/6 </span><br><span class="line"></span><br><span class="line">Installed:</span><br><span class="line"> yum-utils.noarch 0:1.1.31-54.el7_8 </span><br><span class="line"></span><br><span class="line">Dependency Installed:</span><br><span class="line"> libxml2-python.x86_64 0:2.9.1-6.el7_9.6 python-chardet.noarch 0:2.2.1-3.el7 </span><br><span class="line"> python-kitchen.noarch 0:1.1.1-5.el7 </span><br><span class="line"></span><br><span class="line">Dependency Updated:</span><br><span class="line"> libxml2.x86_64 0:2.9.1-6.el7_9.6 </span><br><span class="line"></span><br><span class="line">Complete!</span><br></pre></td></tr></table></figure><p>设置镜像仓库</p><p>这里需要注意,默认镜像仓库地址是国外的,我们可以将地址更改为阿里云镜像地址</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">yum-config-manager \</span><br><span class="line"> --add-repo \</span><br><span class="line"> https ://download.docker.com/linux/centos/docker-ce.repo #默认是国外的</span><br><span class="line">yum-config-manager \</span><br><span class="line"> --add-repo \</span><br><span class="line"> http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo</span><br><span class="line"> </span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash"><span class="comment">########</span></span></span><br><span class="line"></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz /]# yum-config-manager \</span><br><span class="line"><span class="meta prompt_">> </span><span class="language-bash"> --add-repo \</span></span><br><span class="line"><span class="language-bash">> http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo</span></span><br><span class="line">Loaded plugins: fastestmirror</span><br><span class="line">adding repo from: http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo</span><br><span class="line">grabbing file http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo to /etc/yum.repos.d/docker-ce.repo</span><br><span class="line">repo saved to /etc/yum.repos.d/docker-ce.repo</span><br></pre></td></tr></table></figure><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">更新yum软件包索引</span></span><br><span class="line">yum makecache fast</span><br></pre></td></tr></table></figure><p>安装docker</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">docker-ce表示docker的社区版 ee企业版</span></span><br><span class="line">yum install docker-ce docker-ce-cli containerd.io</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>启动docker</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">systemctl start docker</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">使用docker version 查看是否安装成功</span></span><br><span class="line"></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz /]# docker version</span><br><span class="line">Client: Docker Engine - Community</span><br><span class="line"> Version: 20.10.17</span><br><span class="line"> API version: 1.41</span><br><span class="line"> Go version: go1.17.11</span><br><span class="line"> Git commit: 100c701</span><br><span class="line"> Built: Mon Jun 6 23:05:12 2022</span><br><span class="line"> OS/Arch: linux/amd64</span><br><span class="line"> Context: default</span><br><span class="line"> Experimental: true</span><br><span class="line"></span><br><span class="line">Server: Docker Engine - Community</span><br><span class="line"> Engine:</span><br><span class="line"> Version: 20.10.17</span><br><span class="line"> API version: 1.41 (minimum version 1.12)</span><br><span class="line"> Go version: go1.17.11</span><br><span class="line"> Git commit: a89b842</span><br><span class="line"> Built: Mon Jun 6 23:03:33 2022</span><br><span class="line"> OS/Arch: linux/amd64</span><br><span class="line"> Experimental: false</span><br><span class="line"> containerd:</span><br><span class="line"> Version: 1.6.6</span><br><span class="line"> GitCommit: 10c12954828e7c7c9b6e0ea9b0c02b01407d3ae1</span><br><span class="line"> runc:</span><br><span class="line"> Version: 1.1.2</span><br><span class="line"> GitCommit: v1.1.2-0-ga916309</span><br><span class="line"> docker-init:</span><br><span class="line"> Version: 0.19.0</span><br><span class="line"> GitCommit: de40ad0</span><br></pre></td></tr></table></figure><p>hello-world</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">使用hello-world命令来查看是否安装成功</span></span><br><span class="line"></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz /]# docker run hello-world</span><br><span class="line">Unable to find image 'hello-world:latest' locally</span><br><span class="line">latest: Pulling from library/hello-world</span><br><span class="line">2db29710123e: Pull complete </span><br><span class="line">Digest: sha256:13e367d31ae85359f42d637adf6da428f76d75dc9afeb3c21faea0d976f5c651</span><br><span class="line">Status: Downloaded newer image for hello-world:latest</span><br><span class="line"></span><br><span class="line">Hello from Docker! #表示安装成功</span><br><span class="line">This message shows that your installation appears to be working correctly.</span><br><span class="line"></span><br><span class="line">To generate this message, Docker took the following steps:</span><br><span class="line"> 1. The Docker client contacted the Docker daemon.</span><br><span class="line"> 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.</span><br><span class="line"> (amd64)</span><br><span class="line"> 3. The Docker daemon created a new container from that image which runs the</span><br><span class="line"> executable that produces the output you are currently reading.</span><br><span class="line"> 4. The Docker daemon streamed that output to the Docker client, which sent it</span><br><span class="line"> to your terminal.</span><br><span class="line"></span><br><span class="line">To try something more ambitious, you can run an Ubuntu container with:</span><br><span class="line"><span class="meta prompt_"> $ </span><span class="language-bash">docker run -it ubuntu bash</span></span><br><span class="line"></span><br><span class="line">Share images, automate workflows, and more with a free Docker ID:</span><br><span class="line"> https://hub.docker.com/</span><br><span class="line"></span><br><span class="line">For more examples and ideas, visit:</span><br><span class="line"> https://docs.docker.com/get-started/</span><br></pre></td></tr></table></figure><p>查看下载的hello-world镜像</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[root@izbp1ecuerkuubxjbrduatz /]# docker images #查看docker镜像</span><br><span class="line">REPOSITORY TAG IMAGE ID CREATED SIZE</span><br><span class="line">hello-world latest feb5d9fea6a5 9 months ago 13.3kB</span><br></pre></td></tr></table></figure><p>卸载docker</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">1、卸载依赖</span></span><br><span class="line">yum remove docker-ce docker-ce-cli containerd.io</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">2、删除资源</span></span><br><span class="line">rm -rf /var/ lib/docker</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">/var/ lib/docker docker的默认工作路径</span></span><br></pre></td></tr></table></figure><h3 id="阿里云镜像加速"><a href="#阿里云镜像加速" class="headerlink" title="阿里云镜像加速"></a>阿里云镜像加速</h3><p><img src="/2022/07/03/Docker%E5%AD%A6%E4%B9%A0/2.png" alt="image-20220704010316077"></p><p>在阿里云中找到容器镜像服务,再选择镜像加速器即可</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">sudo mkdir -p /etc/docker</span><br><span class="line">sudo tee /etc/docker/daemon.json <<-'EOF'</span><br><span class="line">{</span><br><span class="line"> "registry-mirrors": ["https://i2tczddq.mirror.aliyuncs.com"]</span><br><span class="line">}</span><br><span class="line">EOF</span><br><span class="line">sudo systemctl daemon-reload</span><br><span class="line">sudo systemctl restart docker</span><br></pre></td></tr></table></figure><h3 id="启动流程"><a href="#启动流程" class="headerlink" title="启动流程"></a>启动流程</h3><p><img src="/2022/07/03/Docker%E5%AD%A6%E4%B9%A0/image-20220704125551476.png" alt="image-20220704125551476"></p><h3 id="运行原理"><a href="#运行原理" class="headerlink" title="运行原理"></a>运行原理</h3><p><strong>docker是怎么工作的?</strong></p><p>Docker是一个 Client - Server结构的系统,Docker的守护进程运行在主机上,通过Socket从客户端访问。</p><p>DockerServer接收到Docker-Client的指令,就会执行这个命令</p><p><img src="/2022/07/03/Docker%E5%AD%A6%E4%B9%A0/3.png" alt="img"></p><h2 id="Docker的常用命令"><a href="#Docker的常用命令" class="headerlink" title="Docker的常用命令"></a>Docker的常用命令</h2><blockquote><p>命令的文档地址:<a href="https://docs.docker.com/reference">https://docs.docker.com/reference</a></p></blockquote><h3 id="帮助命令"><a href="#帮助命令" class="headerlink" title="帮助命令"></a>帮助命令</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">docker version #查看docker的版本信息</span><br><span class="line">docker info #查看docker的系统信息,包括镜像和容器的数量</span><br><span class="line">docker 命令 --help #帮助命令(可查看可选的参数)</span><br><span class="line">docker COMMAND --help</span><br></pre></td></tr></table></figure><h3 id="镜像命令"><a href="#镜像命令" class="headerlink" title="镜像命令"></a>镜像命令</h3><blockquote><p><strong>docker images</strong> 查看本地主机的所有镜像</p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker images</span><br><span class="line">REPOSITORY TAG IMAGE ID CREATED SIZE</span><br><span class="line">hello-world latest feb5d9fea6a5 9 months ago 13.3kB</span><br></pre></td></tr></table></figure><p>参数介绍</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">解释:</span></span><br><span class="line">1.REPOSITORY 镜像的仓库源</span><br><span class="line">2.TAG 镜像的标签</span><br><span class="line">3.IMAGE ID 镜像的id</span><br><span class="line">4.CREATED 镜像的创建时间</span><br><span class="line">5.SIZE 镜像的大小</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">可选参数</span></span><br><span class="line">-a, --all #列出所有镜像</span><br><span class="line">-q, --quiet #只显示镜像ID</span><br></pre></td></tr></table></figure><blockquote><p><strong>docker search</strong> 搜索镜像</p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker search mysql</span><br><span class="line">NAME DESCRIPTION STARS OFFICIAL AUTOMATED</span><br><span class="line">mysql MySQL is a widely used, open-source relation… 12819 [OK] </span><br><span class="line">mariadb MariaDB Server is a high performing open sou… 4917 [OK] </span><br><span class="line">percona Percona Server is a fork of the MySQL relati… 580 [OK] </span><br><span class="line">phpmyadmin phpMyAdmin - A web interface for MySQL and M… 564 [OK] </span><br><span class="line">bitnami/mysql Bitnami MySQL Docker Image 71 [OK]</span><br><span class="line">linuxserver/mysql-workbench 37 </span><br></pre></td></tr></table></figure><p>参数介绍 </p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">可选参数</span></span><br><span class="line">Search the Docker Hub for images</span><br><span class="line">Options:</span><br><span class="line"> -f, --filter filter Filter output based on conditions provided</span><br><span class="line"> --format string Pretty-print search using a Go template</span><br><span class="line"> --limit int Max number of search results (default 25)</span><br><span class="line"> --no-trunc Don't truncate output</span><br><span class="line"> </span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">搜索stars大于3000的镜像</span></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker search mysql --filter=STARS=3000</span><br><span class="line">NAME DESCRIPTION STARS OFFICIAL AUTOMATED</span><br><span class="line">mysql MySQL is a widely used, open-source relation… 10308 [OK]</span><br><span class="line">mariadb MariaDB is a community-developed fordockerk of MyS… 3819 [OK]</span><br></pre></td></tr></table></figure><blockquote><p><strong>docker pull</strong> 下载镜像</p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">下载镜像 docker pull 镜像名[:tag] 下载镜像</span></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker pull mysql</span><br><span class="line">Using default tag: latest #如果不写tag,默认就是最新版</span><br><span class="line">latest: Pulling from library/mysql</span><br><span class="line">72a69066d2fe: Pull complete #分层下载 docker image的核心 联合文件系统</span><br><span class="line">93619dbc5b36: Pull complete </span><br><span class="line">99da31dd6142: Pull complete </span><br><span class="line">626033c43d70: Pull complete </span><br><span class="line">37d5d7efb64e: Pull complete </span><br><span class="line">ac563158d721: Pull complete </span><br><span class="line">d2ba16033dad: Pull complete </span><br><span class="line">688ba7d5c01a: Pull complete </span><br><span class="line">00e060b6d11d: Pull complete </span><br><span class="line">1c04857f594f: Pull complete </span><br><span class="line">4d7cfa90e6ea: Pull complete </span><br><span class="line">e0431212d27d: Pull complete </span><br><span class="line">Digest: sha256:e9027fe4d91c0153429607251656806cc784e914937271037f7738bd5b8e7709 #签名</span><br><span class="line">Status: Downloaded newer image for mysql:latest</span><br><span class="line">docker.io/library/mysql:latest#真实地址</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">指定版本下载</span></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker pull mysql:5.7</span><br><span class="line">5.7: Pulling from library/mysql</span><br><span class="line">72a69066d2fe: Already exists </span><br><span class="line">93619dbc5b36: Already exists </span><br><span class="line">99da31dd6142: Already exists </span><br><span class="line">626033c43d70: Already exists </span><br><span class="line">37d5d7efb64e: Already exists </span><br><span class="line">ac563158d721: Already exists </span><br><span class="line">d2ba16033dad: Already exists </span><br><span class="line">0ceb82207cd7: Pull complete </span><br><span class="line">37f2405cae96: Pull complete </span><br><span class="line">e2482e017e53: Pull complete </span><br><span class="line">70deed891d42: Pull complete </span><br><span class="line">Digest: sha256:f2ad209efe9c67104167fc609cca6973c8422939491c9345270175a300419f94</span><br><span class="line">Status: Downloaded newer image for mysql:5.7</span><br><span class="line">docker.io/library/mysql:5.7</span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><p>docker rmi 删除镜像</p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">1.删除指定的镜像<span class="built_in">id</span></span></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker rmi -f 镜像id</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">2.删除多个镜像<span class="built_in">id</span></span></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker rmi -f 镜像id 镜像id 镜像id</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">3.删除全部的镜像<span class="built_in">id</span></span></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker rmi -f $(docker images -aq)</span><br></pre></td></tr></table></figure><h3 id="容器命令"><a href="#容器命令" class="headerlink" title="容器命令"></a>容器命令</h3><p>说明:有了镜像才可以创建容器</p><blockquote><p><strong>docker run [可选参数] image</strong> 运行容器</p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">docker run [可选参数] image</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">参数说明</span></span><br><span class="line">--name="名字" 指定容器名字</span><br><span class="line">-d 后台方式运行</span><br><span class="line">-it 使用交互方式运行,进入容器查看内容</span><br><span class="line">-p 指定容器的端口</span><br><span class="line">( -p ip:主机端口:容器端口 配置主机端口映射到容器端口</span><br><span class="line"> -p 主机端口:容器端口 (常用)</span><br><span class="line"> -p 容器端口)</span><br><span class="line">-P 随机指定端口(大写的P)</span><br></pre></td></tr></table></figure><blockquote><p><strong>docker run -it [容器ID] /bin/bash</strong> 进入容器</p></blockquote><blockquote><p><strong>exit</strong> 退出容器</p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash"><span class="built_in">exit</span> 停止并退出容器(后台方式运行则仅退出)</span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">Ctrl+P+Q 不停止容器退出</span></span><br><span class="line"></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker run -it mysql /bin/bash</span><br><span class="line">root@2385ad07b816:/# ls</span><br><span class="line">bin docker-entrypoint-initdb.d home mediaproc sbin tmp</span><br><span class="line">boot entrypoint.sh lib mntroot srv usr</span><br><span class="line">dev etc lib64 optrun sys var</span><br><span class="line">root@2385ad07b816:/# exit</span><br><span class="line">exit</span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# </span><br></pre></td></tr></table></figure><blockquote><p><strong>docker ps</strong> 列出容器</p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">docker ps</span> </span><br><span class="line"> # 列出当前正在运行的容器</span><br><span class="line">-a # 列出所有容器的运行记录</span><br><span class="line">-n=? # 显示最近创建的n个容器</span><br><span class="line">-q # 只显示容器的编号</span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><p>删除容器</p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker rm 容器id #删除指定的容器,不能删除正在运行的容器,强制删除使用 rm -f</span><br><span class="line">docker rm -f $(docker ps -aq) #删除所有的容器</span><br><span class="line">docker ps -a -q|xargs docker rm #删除所有的容器</span><br></pre></td></tr></table></figure><blockquote><p>启动容器命令</p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">docker start 容器id #启动容器</span><br><span class="line">docker restart 容器id #重启容器</span><br><span class="line">docker stop 容器id #停止当前运行的容器</span><br><span class="line">docker kill 容器id #强制停止当前容器</span><br></pre></td></tr></table></figure><h3 id="其他命令"><a href="#其他命令" class="headerlink" title="其他命令"></a>其他命令</h3><p><strong>后台启动容器</strong></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">命令 docker run -d 镜像名</span></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz /]# docker run -d centos</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">间题docker ps,发现centos停止了</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">常见的坑: docker容器使用后台运行,就必须要有要一个前台进程,docker发现没有应用,就会自动停止</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了</span></span><br></pre></td></tr></table></figure><blockquote><p><strong>查看日志</strong></p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker logs --help</span><br><span class="line"></span><br><span class="line">Usage: docker logs [OPTIONS] CONTAINER</span><br><span class="line"></span><br><span class="line">Fetch the logs of a container</span><br><span class="line"></span><br><span class="line">Options:</span><br><span class="line"> --details Show extra details provided to logs</span><br><span class="line"> -f, --follow Follow log output</span><br><span class="line"> --since string Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or</span><br><span class="line"> relative (e.g. 42m for 42 minutes)</span><br><span class="line"> -n, --tail string Number of lines to show from the end of the logs (default</span><br><span class="line"> "all")</span><br><span class="line"> -t, --timestamps Show timestamps</span><br><span class="line"> --until string Show logs before a timestamp (e.g. 2013-01-02T13:23:37Z)</span><br><span class="line"> or relative (e.g. 42m for 42 minutes)</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">常用:</span></span><br><span class="line">docker logs -tf 容器id</span><br><span class="line">docker logs --tail number 容器id #num为要显示的日志条数</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">docker容器后台运行,必须要有一个前台的进程,否则会自动停止</span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">编写shell脚本循环执行,使得centos容器保持运行状态</span></span><br><span class="line"></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker run -d centos /bin/sh -c "while true;do echo hi;sleep 5;done"</span><br><span class="line">85e26c4d7ff8f9d8f4a028c3cff06159548a58db9e069ce3908f09bbce8c4f81</span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker ps</span><br><span class="line">CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES</span><br><span class="line">85e26c4d7ff8 centos "/bin/sh -c 'while t…" 21 seconds ago Up 20 seconds dreamy_kowalevski</span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker logs -tf --tail 10 85e26c4d7ff8</span><br><span class="line">2022-07-04T08:02:37.078745794Z hi</span><br><span class="line">2022-07-04T08:02:42.081780082Z hi</span><br><span class="line">2022-07-04T08:02:47.083866743Z hi</span><br><span class="line">2022-07-04T08:02:52.085997777Z hi</span><br><span class="line">2022-07-04T08:02:57.088071630Z hi</span><br><span class="line">2022-07-04T08:03:02.093218951Z hi</span><br><span class="line">2022-07-04T08:03:07.095377635Z hi</span><br><span class="line">2022-07-04T08:03:12.097649023Z hi</span><br><span class="line">2022-07-04T08:03:17.100388998Z hi</span><br><span class="line">2022-07-04T08:03:22.102402807Z hi</span><br><span class="line">2022-07-04T08:03:27.104152864Z hi</span><br><span class="line">2022-07-04T08:03:32.106562318Z hi</span><br></pre></td></tr></table></figure><blockquote><p><strong>查看容器进程信息</strong></p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker ps</span><br><span class="line">CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES</span><br><span class="line">85e26c4d7ff8 centos "/bin/sh -c 'while t…" 6 minutes ago Up 6 minutes dreamy_kowalevski</span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker top 85e26c4d7ff8</span><br><span class="line">UID PID PPID C STIME TTY TIME CMD</span><br><span class="line">root 18894 18849 0 16:01 ? 00:00:00 /bin/sh -c while true;do echo hi;sleep 5;done</span><br><span class="line">root 19606 18894 0 16:08 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 5</span><br></pre></td></tr></table></figure><blockquote><p><strong>查看容器的元数据</strong></p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker inspect 容器id</span><br></pre></td></tr></table></figure><blockquote><p><strong>进入当前正在运行的容器</strong></p></blockquote><p>方式一:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker exec -it 85e26c4d7ff8 /bin/bash</span><br><span class="line">[root@85e26c4d7ff8 /]# ps -ef</span><br><span class="line">UID PID PPID C STIME TTY TIME CMD</span><br><span class="line">root 1 0 0 08:01 ? 00:00:00 /bin/sh -c while true;do echo hi;sleep 5</span><br><span class="line">root 352 0 0 08:30 pts/0 00:00:00 /bin/bash</span><br><span class="line">root 369 1 0 08:30 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-sheb</span><br><span class="line">root 370 352 0 08:30 pts/0 00:00:00 ps -ef</span><br></pre></td></tr></table></figure><p>方式二:</p><blockquote><p><strong>docker attach 容器id</strong></p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker attach 85e26c4d7ff8</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">docker <span class="built_in">exec</span> 进入容器后开启一个新的终端,可以在里面操作(常用)</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">docker attach 进入容器正在执行的终端,不会启动新的进程</span></span><br></pre></td></tr></table></figure><blockquote><p><strong>docker cp 容器id:容器内路径 目的主机路径</strong> 拷贝容器的文件到主机中</p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# cd /home</span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz home]# ls</span><br><span class="line">admin staragent www</span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz home]# docker attach d34382c71220</span><br><span class="line">[root@d34382c71220 /]# cd /home</span><br><span class="line">[root@d34382c71220 home]# ls</span><br><span class="line">[root@d34382c71220 home]# touch w.java</span><br><span class="line">[root@d34382c71220 home]# ls</span><br><span class="line">w.java</span><br><span class="line">[root@d34382c71220 home]# exit</span><br><span class="line">exit</span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz home]# docker cp d34382c71220:/home/w.java /home</span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz home]# ls</span><br><span class="line">admin staragent w.java www</span><br></pre></td></tr></table></figure><h3 id="命令小结"><a href="#命令小结" class="headerlink" title="命令小结"></a>命令小结</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line">attach Attach to a running container #当前shell下attach连接指定运行镜像</span><br><span class="line">build Build an image from a Dockerfile #通过Dockerfile定制镜像</span><br><span class="line">commit Create a new image from a container's changes #提交当前容器为新的镜像</span><br><span class="line">cp Copy files/folders from a container to a HOSTDIR or to STDOUT #从容器中拷贝指定文件或者目录到宿主机中</span><br><span class="line">create Create a new container #创建一个新的容器,同run 但不启动容器</span><br><span class="line">diff Inspect changes on a container's filesystem #查看docker容器变化</span><br><span class="line">events Get real time events from the server#从docker服务获取容器实时事件</span><br><span class="line">exec Run a command in a running container#在已存在的容器上运行命令</span><br><span class="line">export Export a container's filesystem as a tar archive #导出容器的内容流作为一个tar归档文件(对应import)</span><br><span class="line">history Show the history of an image #展示一个镜像形成历史</span><br><span class="line">images List images #列出系统当前镜像</span><br><span class="line">import Import the contents from a tarball to create a filesystem image #从tar包中的内容创建一个新的文件系统映像(对应export)</span><br><span class="line">info Display system-wide information #显示系统相关信息</span><br><span class="line">inspect Return low-level information on a container or image #查看容器详细信息</span><br><span class="line">kill Kill a running container #kill指定docker容器</span><br><span class="line">load Load an image from a tar archive or STDIN #从一个tar包中加载一个镜像(对应save)</span><br><span class="line">login Register or log in to a Docker registry#注册或者登陆一个docker源服务器</span><br><span class="line">logout Log out from a Docker registry #从当前Docker registry退出</span><br><span class="line">logs Fetch the logs of a container #输出当前容器日志信息</span><br><span class="line">pause Pause all processes within a container#暂停容器</span><br><span class="line">port List port mappings or a specific mapping for the CONTAINER #查看映射端口对应的容器内部源端口</span><br><span class="line">ps List containers #列出容器列表</span><br><span class="line">pull Pull an image or a repository from a registry #从docker镜像源服务器拉取指定镜像或者库镜像</span><br><span class="line">push Push an image or a repository to a registry #推送指定镜像或者库镜像至docker源服务器</span><br><span class="line">rename Rename a container #重命名容器</span><br><span class="line">restart Restart a running container #重启运行的容器</span><br><span class="line">rm Remove one or more containers #移除一个或者多个容器</span><br><span class="line">rmi Remove one or more images #移除一个或多个镜像(无容器使用该镜像才可以删除,否则需要删除相关容器才可以继续或者-f强制删除)</span><br><span class="line">run Run a command in a new container #创建一个新的容器并运行一个命令</span><br><span class="line">save Save an image(s) to a tar archive#保存一个镜像为一个tar包(对应load)</span><br><span class="line">search Search the Docker Hub for images #在docker</span><br><span class="line">hub中搜索镜像</span><br><span class="line">start Start one or more stopped containers#启动容器</span><br><span class="line">stats Display a live stream of container(s) resource usage statistics #统计容器使用资源</span><br><span class="line">stop Stop a running container #停止容器</span><br><span class="line">tag Tag an image into a repository #给源中镜像打标签</span><br><span class="line">top Display the running processes of a container #查看容器中运行的进程信息</span><br><span class="line">unpause Unpause all processes within a container #取消暂停容器</span><br><span class="line">version Show the Docker version information#查看容器版本号</span><br><span class="line">wait Block until a container stops, then print its exit code #截取容器停止时的退出状态值</span><br></pre></td></tr></table></figure><h2 id="Docker镜像"><a href="#Docker镜像" class="headerlink" title="Docker镜像"></a>Docker镜像</h2><blockquote><p>UnionFS(联合文件系统)</p></blockquote><p>UnionFS(联合文件系统) :Union文件系统(UnionFS )是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtualfilesystem)。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。</p><p>特性︰一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录</p><blockquote><p>Docker镜像加载原理</p></blockquote><p>docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。</p><p>bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。</p><p>rootfs (root file system),在bootfs之上。包含的就是典型Linux系统中的/dev, /proc, /bin,/letc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu , Centos等等。</p><p><img src="/2022/07/03/Docker%E5%AD%A6%E4%B9%A0/a7db9520ca41485180295d7259e4289a.png" alt="a7db9520ca41485180295d7259e4289a"></p><h3 id="commit-镜像"><a href="#commit-镜像" class="headerlink" title="commit 镜像"></a>commit 镜像</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">[root@izbp1ecuerkuubxjbrduatz home]# docker ps</span><br><span class="line">CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES</span><br><span class="line">0493248e23dd tomcat "/bin/bash" 57 seconds ago Up 56 seconds 8080/tcp epic_joliot</span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz home]# docker commit -a"w" -m"add webapps app" 0493248e23dd tomcat02:1.0</span><br><span class="line">sha256:5f28f09a8fa75ece3bf481a722e1ef9c72916d29fb0fa55b5e1647dcd7d00b15</span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz home]# docker images</span><br><span class="line">REPOSITORY TAG IMAGE ID CREATED SIZE</span><br><span class="line">tomcat02 1.0 5f28f09a8fa7 7 seconds ago 684MB</span><br><span class="line">nginx latest 605c77e624dd 6 months ago 141MB</span><br><span class="line">tomcat 9.0 b8e65a4d736d 6 months ago 680MB</span><br><span class="line">tomcat latest fb5657adc892 6 months ago 680MB</span><br><span class="line">redis latest 7614ae9453d1 6 months ago 113MB</span><br><span class="line">mysql 5.7 c20987f18b13 6 months ago 448MB</span><br><span class="line">centos latest 5d0da3dc9764 9 months ago 231MB</span><br></pre></td></tr></table></figure><h2 id="容器数据卷"><a href="#容器数据卷" class="headerlink" title="容器数据卷"></a>容器数据卷</h2><h3 id="什么是容器数据卷?"><a href="#什么是容器数据卷?" class="headerlink" title="什么是容器数据卷?"></a>什么是容器数据卷?</h3><p>==为了实现数据持久化,使容器之间可以共享数据。可以将容器内的目录,挂载到宿主机上或其他容器内,实现同步和共享的操作。即使将容器删除,挂载到本地的数据卷也不会丢失。==</p><h3 id="使用数据卷"><a href="#使用数据卷" class="headerlink" title="使用数据卷"></a>使用数据卷</h3><blockquote><p><strong>docker run -it -v 主机目录:容器目录</strong> </p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">[root@izbp1ecuerkuubxjbrduatz home]# docker run -it -v /home/test:/home centos /bin/bash</span><br><span class="line">[root@abbc164fc027 /]# cd /home #容器内</span><br><span class="line">[root@abbc164fc027 home]# touch hello.java</span><br><span class="line">[root@abbc164fc027 home]# ls</span><br><span class="line">hello.java</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">主机内</span></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz /]# cd /home</span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz home]# cd test</span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz test]# ls</span><br><span class="line">hello.java</span><br></pre></td></tr></table></figure><p><strong>容器与主机建立挂载关系后,即使容器未运行,在主机内修改对应文件,再次开启容器后,容器内的文件也会发生改变。</strong></p><h3 id="具名和匿名挂载"><a href="#具名和匿名挂载" class="headerlink" title="具名和匿名挂载"></a>具名和匿名挂载</h3><blockquote><p><strong>docker run -d -v 容器内目录 镜像名/id</strong> 匿名挂载</p></blockquote><blockquote><p><strong>docker volume ls</strong> 查看所有挂载的卷</p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker volume ls</span><br><span class="line">DRIVER VOLUME NAME</span><br><span class="line">local 0f224b38756cefb0d8478f09e198f517f52780e8fe8e4888685c3668a74e4f60</span><br></pre></td></tr></table></figure><blockquote><p><strong>docker run -d -v 卷名:容器内目录 镜像名/id</strong> 具名挂载</p></blockquote><blockquote><p><strong>docker volume inspect 卷名</strong></p></blockquote><p><strong>所有docker容器内的卷,在未指定主机内目录时,都在:==/var/lib/docker/volumes/卷名/_data==下,可通过具名挂载可以方便的找到卷,因此广泛使用这种方式进行挂载。</strong></p><h3 id="数据卷容器"><a href="#数据卷容器" class="headerlink" title="数据卷容器"></a>数据卷容器</h3><blockquote><p><strong>docker run -it –name container02 –volumes from container01 镜像名/id</strong> 将两个容器进行挂载</p></blockquote><h2 id="DockerFile"><a href="#DockerFile" class="headerlink" title="DockerFile"></a>DockerFile</h2><p>Dockerfile是用来构建docker镜像的构建文件</p><h3 id="构建步骤"><a href="#构建步骤" class="headerlink" title="构建步骤"></a>构建步骤</h3><p>编写一个dockerfile文件,随后运行命令:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker build -f 文件路径 -t 镜像名 . <span class="comment"># 文件名为Dockerfile时可省略且最后的.不要忽略</span></span><br><span class="line">docker run <span class="comment"># 运行镜像</span></span><br><span class="line">docker push <span class="comment"># 发布镜像</span></span><br></pre></td></tr></table></figure><h3 id="DockerFile命令"><a href="#DockerFile命令" class="headerlink" title="DockerFile命令"></a>DockerFile命令</h3><table><thead><tr><th align="center">命令</th><th align="center">效果</th></tr></thead><tbody><tr><td align="center">FROM</td><td align="center">基础镜像,一切从这里构建:Centos/Ubuntu</td></tr><tr><td align="center">MAINTAINER</td><td align="center">镜像是谁写的,镜像作者+邮箱</td></tr><tr><td align="center">RUN</td><td align="center">镜像构建的时候需要运行的命令</td></tr><tr><td align="center">ADD</td><td align="center">为镜像添加内容(压缩包)</td></tr><tr><td align="center">WORKDIR</td><td align="center">镜像工作目录(进入容器时的目录)</td></tr><tr><td align="center">VOLUME</td><td align="center">挂载的目录</td></tr><tr><td align="center">EXPOSE</td><td align="center">暴露端口配置</td></tr><tr><td align="center">CMD/ENTRYPOINT</td><td align="center">指定容器启动时要运行的命令(CMD只有最后一个会生效,可被替代,ENTRYPOINT在先前命令后追加)</td></tr><tr><td align="center">COPY</td><td align="center">类似于ADD,将文件拷贝到镜像中</td></tr><tr><td align="center">ENV</td><td align="center">构建时设置环境变量</td></tr></tbody></table><h3 id="构建过程"><a href="#构建过程" class="headerlink" title="构建过程"></a>构建过程</h3><ul><li>每个保留关键字(指令)都建议使用大写字母</li><li>从上到下顺序执行</li><li>“#” 表示注释</li><li>每一个指令都会创建提交一个新的镜像层并提交</li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">1、编写Dockerfile的文件</span></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz dockerfile]# cat mydockerfile-centos</span><br><span class="line">FROM centos</span><br><span class="line">MAINTAINER w<1582891731@qq. com></span><br><span class="line"></span><br><span class="line">ENV MYPATH /usr/local</span><br><span class="line">WORKDIR $MYPATH</span><br><span class="line"></span><br><span class="line">RUN yum -y instal1 vim</span><br><span class="line">RUN yum -y instal1 net-too1s</span><br><span class="line"></span><br><span class="line">EXPOSE 80</span><br><span class="line">CMD echo $MYPATH</span><br><span class="line">CMD echo "----end----"</span><br><span class="line">CMD /bin/bash</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">2、通过这个文件构建镜像</span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">命令docker build -f dockerfile文件路径 -t镜像名:[tag]</span></span><br><span class="line">Successfully built ce25858fcccd</span><br><span class="line">Successfully tagged mycentos:0.1</span><br></pre></td></tr></table></figure><h2 id="Docker网络"><a href="#Docker网络" class="headerlink" title="Docker网络"></a>Docker网络</h2><h3 id="理解Docker0"><a href="#理解Docker0" class="headerlink" title="理解Docker0"></a>理解Docker0</h3><p>通过命令<strong>ip addr</strong>查看本地ip地址,我们发现除了本机回环地址和埃里远的内网地址外,还多了一个网卡:Docker0,这是Docker服务启动后自动生成的。</p><p><img src="/2022/07/03/Docker%E5%AD%A6%E4%B9%A0/55.png" alt="image-20220711164548092"></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">[root@izbp1ecuerkuubxjbrduatz ~]<span class="comment"># docker run -d -P --name tomcat01 tomcat:7.0</span></span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看容器的内部网络地址 ip addr 容器启动的时候会得到一个eth0@if41 ip地址,docker为我们分配的</span></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker exec -it tomcat01 ip addr</span><br><span class="line">1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1</span><br><span class="line"> link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00</span><br><span class="line"> inet 127.0.0.1/8 scope host lo</span><br><span class="line"> valid_lft forever preferred_lft forever</span><br><span class="line">40: eth0@if41: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default </span><br><span class="line"> link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0</span><br><span class="line"> inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0</span><br><span class="line"> valid_lft forever preferred_lft forever</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>原理:我们每启动一个docker容器,docker就会给容器分配一个默认的可用ip,我们只要安装了docker,就会有一个网卡docker0(bridge)。网卡采用桥接模式,并使用veth-pair技术(veth-pair就是一堆虚拟设备接口,成对出现,一端连着协议,一端彼此相连,充当一个桥梁。)。</p><p><img src="/2022/07/03/Docker%E5%AD%A6%E4%B9%A0/66.png" alt="image-20220711175656929"></p><p>docker中的所有网络接口都是虚拟的 ,转发效率高。删除容器后,对应的网桥也随之删除。</p><h3 id="自定义网络"><a href="#自定义网络" class="headerlink" title="自定义网络"></a>自定义网络</h3><blockquote><p>docker network ls # 查看所有的docker网络 </p></blockquote><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker network ls</span><br><span class="line">NETWORK ID NAME DRIVER SCOPE</span><br><span class="line">51cae7947442 bridge bridge local</span><br><span class="line">4a34486b77d8 host host local</span><br><span class="line">baa0e52d9df3 none null local</span><br></pre></td></tr></table></figure><p><strong>docker中的网络模式有:</strong></p><ul><li>bridge:桥接(docker默认,自己创建也使用bridge模式)</li><li>none:不配置网络 </li><li>host:和宿主机共享网络</li><li>container: 容器内网络联通(用得少)</li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">我们直接启动的命令 --net bridge, 而这个就是我们的docker0</span></span><br><span class="line">docker run -d -P --name tomcat01 tomcat # --net bridge是默认的</span><br><span class="line">docker run -d -P --name tomcat01 --net bridge tomcat</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">docker0特点: 默认,域名不能访问</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">自定义网络</span></span><br><span class="line">docker network create --driver 网络模式 --subnet 子网ip --gateway 网关 网络名</span><br><span class="line"></span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet</span><br><span class="line">fbfee9a7add1380a262d0be48fa4d30a2ee07fe2a7b0ae3051e2b521f2b1a502</span><br><span class="line">[root@izbp1ecuerkuubxjbrduatz ~]# docker network ls</span><br><span class="line">NETWORK ID NAME DRIVER SCOPE</span><br><span class="line">51cae7947442 bridge bridge local</span><br><span class="line">4a34486b77d8 host host local</span><br><span class="line">fbfee9a7add1 mynet bridge local</span><br><span class="line">baa0e52d9df3 none null local</span><br></pre></td></tr></table></figure><h3 id="网络连通"><a href="#网络连通" class="headerlink" title="网络连通"></a>网络连通</h3><p>对于建立在不同网络下(docker0, newnet)的两个容器tomcat01和tomcat02,他们的网段不同,因此是无法彼此ping通容器内部的:</p><p>这时我们需要通过<strong>docker network connect</strong>命令打通容器与网络之间的连接:</p><blockquote><p>docker network connect 网络名 容器名/id</p></blockquote><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p><a href="https://www.bilibili.com/video/BV1og4y1q7M4?spm_id_from=333.999.0.0&vd_source=d28a32457971d5e2f307a6c96eb52f60" target="_blank">Docker</a></p>]]></content>
<tags>
<tag> Docker </tag>
</tags>
</entry>
<entry>
<title>Redis学习</title>
<link href="/2022/04/14/Redis%E5%AD%A6%E4%B9%A0/"/>
<url>/2022/04/14/Redis%E5%AD%A6%E4%B9%A0/</url>
<content type="html"><![CDATA[<h1 id="Redis简介"><a href="#Redis简介" class="headerlink" title="Redis简介"></a>Redis简介</h1><p>Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。</p><h1 id="基础知识"><a href="#基础知识" class="headerlink" title="基础知识"></a>基础知识</h1><p>redis默认有16个数据库(0-15),默认使用的是第0个数据库</p><p>可以使用select切换数据库</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> select 3 <span class="comment">#切换数据库</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379[3]> dbsize <span class="comment">#查看DB大小</span></span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line"></span><br><span class="line">keys * 查看所有的key</span><br><span class="line">flushdb 清空当前数据库</span><br><span class="line">flushall 清空所有数据库</span><br><span class="line">exists 数据是否存在,存在返回1,不存在返回0</span><br><span class="line">move 数据 数据库编号 将当前key移动到指定的数据库</span><br><span class="line">expire name 10 <span class="comment">#设置key的过期时间,单位是秒</span></span><br><span class="line">ttl name <span class="comment">#查看当前key的剩余时间</span></span><br><span class="line"><span class="built_in">type</span> <span class="comment">#查看key的类型</span></span><br></pre></td></tr></table></figure><blockquote><p>redis是单线程的!</p></blockquote><p>Redis是很快的,官方表示,Redis是基于内存操作,CPU不是Redis性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就使用单线程了!|</p><p><strong>为什么redis单线程还那么快?</strong></p><ol><li><p>单线程不一定比多线程慢!</p></li><li><p>redis是基于内存的,所以使用单线程去操作效率就是最高的,多线程(CPU上下文会切换∶耗时的操作 )</p></li><li><p>redis中的数据结构是专门进行设计的,数据结构简单,对数据操作也简单,类似于Hashmap。</p></li></ol><h1 id="五大数据类型"><a href="#五大数据类型" class="headerlink" title="五大数据类型"></a>五大数据类型</h1><p><strong>Redis-key</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> keys * <span class="comment">#查看所有的key</span></span><br><span class="line">(empty list or <span class="built_in">set</span>)</span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> name w <span class="comment"># set key</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379> keys *</span><br><span class="line">1)<span class="string">"name"</span></span><br><span class="line">127.0.0.1:6379><span class="built_in">set</span> age 1</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379> keys *</span><br><span class="line">1) <span class="string">"age"</span></span><br><span class="line">2) <span class="string">"name"</span></span><br><span class="line">127.0.0.1:6379> EXISTs name <span class="comment">#判断当前的key是否存在</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379>EXISTS name1</span><br><span class="line">(<span class="built_in">integer</span>) o</span><br><span class="line">127.0.0.1:6379>move name 1 <span class="comment">#将当前key移动到指定的数据库</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> keys *</span><br><span class="line">1) <span class="string">"age"</span></span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> name w</span><br><span class="line">oK</span><br><span class="line">127.0.0.1:6379> keys *</span><br><span class="line">1) <span class="string">"age"</span></span><br><span class="line">2) <span class="string">"name"</span></span><br><span class="line">127.0.0.1:6379> get name</span><br><span class="line"><span class="string">"w"</span></span><br><span class="line">127.0.0.1:6379> EXPIRE name 10 <span class="comment">#设置key的过期时间,单位是秒</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> ttl name <span class="comment">#查看当前key的剩余时间</span></span><br><span class="line">(<span class="built_in">integer</span>) 4</span><br><span class="line">127.0.0.1:6379> ttl name</span><br><span class="line">(<span class="built_in">integer</span>) -2</span><br><span class="line">127.0.0.1:6379> get name</span><br><span class="line">(nil)</span><br></pre></td></tr></table></figure><h2 id="String(字符串)"><a href="#String(字符串)" class="headerlink" title="String(字符串)"></a>String(字符串)</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379><span class="built_in">set</span> keyl v1 <span class="comment">#设置值</span></span><br><span class="line">oK</span><br><span class="line">127.0.0.1:6379> get key1 <span class="comment">#获得值</span></span><br><span class="line"><span class="string">"v1"</span></span><br><span class="line">127.0.0.1:6379> keys * <span class="comment">#获得值</span></span><br><span class="line">1) <span class="string">"key1"</span></span><br><span class="line">127.0.0.1:6379> EXISTs key1</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> APPEND key1 <span class="string">"he11o"</span> <span class="comment">#追加字符串,如果当前key不存在,就相当于set key</span></span><br><span class="line">(<span class="built_in">integer</span>) 7</span><br><span class="line">127.0.0.1:6379> strlen key1 <span class="comment">#获取字符串长度</span></span><br><span class="line">(<span class="built_in">integer</span>) 7</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#步长i++</span></span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> views o <span class="comment">#初始浏览量为0</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379> get views</span><br><span class="line"><span class="string">"O"</span></span><br><span class="line">127.0.0.1:6379> incr views <span class="comment">#自增1</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> get views</span><br><span class="line"><span class="string">"1"</span></span><br><span class="line">127.0.0.1:6379> decr views <span class="comment">#自减1</span></span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line">127.0.0.1:6379> get views</span><br><span class="line"><span class="string">"0"</span></span><br><span class="line">127.0.0.1:6379> INCRBY views 10 <span class="comment">#指定增量</span></span><br><span class="line">(<span class="built_in">integer</span>) 10</span><br><span class="line">127.0.0.1:6379> decrby views 5 <span class="comment">#指定增量</span></span><br><span class="line">(<span class="built_in">integer</span>) 5</span><br></pre></td></tr></table></figure><p><strong>字符串范围 range</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> <span class="built_in">set</span> key1 <span class="string">"hello"</span></span><br><span class="line">Ok</span><br><span class="line">127.0.0.1:6379> get key1</span><br><span class="line"><span class="string">"he11o"</span></span><br><span class="line">127.0.0.1:6379>GETRANGE key1 0 3 <span class="comment">#截取字符串</span></span><br><span class="line"><span class="string">"hell"</span></span><br><span class="line">127.0.0.1:6379> GETRANGE key1 0 -1 <span class="comment">#获取全部字符串</span></span><br><span class="line"><span class="string">"hello"</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#替换!</span></span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> key2 abcdefg</span><br><span class="line">ok</span><br><span class="line">127.0.0.1:6379> get key2</span><br><span class="line"><span class="string">"abcdefg"</span></span><br><span class="line">127.0.0.1:6379>SETRANGE key2 1 xx <span class="comment">#替换指定位置开始的字符串</span></span><br><span class="line">(<span class="built_in">integer</span>) 7</span><br><span class="line">127.0.0.1:6379> get key2</span><br><span class="line"><span class="string">"axxdefg"</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">setex (<span class="built_in">set</span> with expire) <span class="comment">#设置过期时间</span></span><br><span class="line">setnx (<span class="built_in">set</span> <span class="keyword">if</span> not exist) <span class="comment">#不存在再设置(在分布式锁中会常常使用!)</span></span><br><span class="line"></span><br><span class="line">127.0.0.1:6379> setex key3 30 <span class="string">"hello"</span> <span class="comment">#设置key3的值为hello,30秒后过期</span></span><br><span class="line">ok</span><br><span class="line">127.0.0.1:6379> ttl key3</span><br><span class="line">(<span class="built_in">integer</span>) 26</span><br><span class="line">127.0.0.1:6379> get key3</span><br><span class="line"><span class="string">"hello"</span></span><br><span class="line">127.0.0.1:6379> setnx mykey <span class="string">"redis"</span> <span class="comment">#如果mykey不存在,创建mykey</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> keys *</span><br><span class="line">1) <span class="string">"key2"</span></span><br><span class="line">2) <span class="string">"mykey"</span></span><br><span class="line">3) <span class="string">"key1"</span></span><br><span class="line">127.0.0.1:6379> ttl key3</span><br><span class="line">(<span class="built_in">integer</span>) -2</span><br><span class="line">127.0.0.1:6379> setnx mykey <span class="string">"MongoDB"</span> <span class="comment">#如果mykey存在,创建失败</span></span><br><span class="line">(<span class="built_in">integer</span>) o</span><br><span class="line">127.0.0.1:6379> get mykey</span><br><span class="line"><span class="string">"redis"</span></span><br></pre></td></tr></table></figure><p><strong>mset mget</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 <span class="comment">#同时设置多个值</span></span><br><span class="line">ok</span><br><span class="line">127.0.0.1:6379> keys *</span><br><span class="line">1) <span class="string">"k1"</span></span><br><span class="line">2) <span class="string">"k2"</span></span><br><span class="line">3) <span class="string">"k3"</span></span><br><span class="line">127.0.0.1:6379> mget k1 k2 k3<span class="comment">#同时获取多个值</span></span><br><span class="line">1) <span class="string">"v1"</span></span><br><span class="line">2) <span class="string">"v2"</span></span><br><span class="line">3) <span class="string">"v3"</span></span><br><span class="line">127.0.0.1:6379> msetnx k1 v1 k4 v4 <span class="comment"># msetnx是一个原子性的操作,要么一起成功,要么一起失败</span></span><br><span class="line">(<span class="built_in">integer</span>) o</span><br><span class="line">127.0.0.1:6379> get k4</span><br><span class="line">(ni1)</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 对象</span></span><br><span class="line"><span class="built_in">set</span> user:1 {name:zhangsan,age:3] <span class="comment">#设置一个user:1对象值为json字符来保存一个对象</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 这里的key是一个巧妙的设计: user:{id}:{filed} </span></span><br><span class="line">127.0.0.1:6379> mset user: 1:name zhangsan user: 1:age 2</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379> mget user:1:name user: 1:age</span><br><span class="line">1) <span class="string">"zhangsan"</span></span><br><span class="line">2) <span class="string">"2"</span></span><br></pre></td></tr></table></figure><h2 id="List-列表"><a href="#List-列表" class="headerlink" title="List(列表)"></a>List(列表)</h2><p><strong>在list里面,所有命令都是以l开头的</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> LPUSH list one <span class="comment">#将一个值或多个值插入列表头部(左)</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379>LPUSH list two</span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br><span class="line">127.0.0.1:6379> LPUSH list three</span><br><span class="line">(<span class="built_in">integer</span>) 3</span><br><span class="line">127.0.0.1:6379> LRANGE list 0 -1 <span class="comment">#获取1ist中值!</span></span><br><span class="line">1)<span class="string">"three"</span></span><br><span class="line">2) <span class="string">"two"</span></span><br><span class="line">3) <span class="string">"one "</span></span><br><span class="line">127.0.0.1:6379> LRANGE list 0 1 <span class="comment">#通过区间获取具体的值!</span></span><br><span class="line">1) <span class="string">"three"</span></span><br><span class="line">2) <span class="string">"two"</span></span><br><span class="line">127.0.0.1:6379> Rpush list right <span class="comment">#将一个值或者多个值,插入到列表尾部(右)</span></span><br><span class="line">(<span class="built_in">integer</span>) 4</span><br><span class="line">127.0.0.1:6379> LRANGE list 0 -1</span><br><span class="line">1) <span class="string">"three"</span></span><br><span class="line">2) <span class="string">"two"</span></span><br><span class="line">3) <span class="string">"one"</span></span><br><span class="line">4) <span class="string">"right"</span></span><br></pre></td></tr></table></figure><p><strong>LPOP RPOP</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> LRANGE list 0 -1</span><br><span class="line">1) <span class="string">"three"</span></span><br><span class="line">2) <span class="string">"two"</span></span><br><span class="line">3) <span class="string">"one"</span></span><br><span class="line">4) <span class="string">"right"</span></span><br><span class="line">127.0.0.1:6379> Lpop list <span class="comment">#移除1ist的第一个元素</span></span><br><span class="line"><span class="string">"three"</span></span><br><span class="line">127.0.0.1:6379> Rpop list <span class="comment">#移除1ist的最后一个元素</span></span><br><span class="line"><span class="string">"right"</span></span><br><span class="line">127.0.0.1:6379> LRANGE list 0 -1</span><br><span class="line">1)<span class="string">"two"</span></span><br><span class="line">2) <span class="string">"one"</span></span><br></pre></td></tr></table></figure><p><strong>Lindex</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> LRANGE list 0 -1</span><br><span class="line">1) <span class="string">"two"</span></span><br><span class="line">2) <span class="string">"one"</span></span><br><span class="line">127.0.0.1:6379> lindex list 1 <span class="comment">#通过下标获得 list中的某一个值!</span></span><br><span class="line"><span class="string">"one"</span></span><br><span class="line">127.0.0.1:6379> lindex list 0</span><br><span class="line"><span class="string">"two"</span></span><br></pre></td></tr></table></figure><p><strong>Llen</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> Lpush list one</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> Lpush list two</span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br><span class="line">127.0.0.1:6379> Lpush list three</span><br><span class="line">(<span class="built_in">integer</span>) 3</span><br><span class="line">127.0.o.1:6379> Llen list <span class="comment">#返回列表的长度</span></span><br><span class="line">(<span class="built_in">integer</span>) 3</span><br></pre></td></tr></table></figure><p><strong>Lrem</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379>LRANGE list 0 -1</span><br><span class="line">1)<span class="string">"three"</span></span><br><span class="line">2)<span class="string">"three"</span></span><br><span class="line">3)<span class="string">"two"</span></span><br><span class="line">4) <span class="string">"one"</span></span><br><span class="line">127.0.0.1:6379>lrem list 1 one <span class="comment">#移除1ist集合中指定个数的value,精确匹配</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> LRANGE list 0 -1</span><br><span class="line">1) <span class="string">"three"</span></span><br><span class="line">2) <span class="string">"three"</span></span><br><span class="line">3) <span class="string">"two"</span></span><br><span class="line">127.0.0.1:6379> lrem list 1 three</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> LRANGE list 0 -1</span><br><span class="line">1)<span class="string">"three"</span></span><br><span class="line">2)<span class="string">"two"</span></span><br><span class="line">127.0.0.1:6379> Lpush list three</span><br><span class="line">(<span class="built_in">integer</span>) 3</span><br><span class="line">127.0.0.1:6379> lrem list 2 three</span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br><span class="line">127.0.0.1:6379> LRANGE list 0 -1</span><br><span class="line">1)<span class="string">"two"</span></span><br></pre></td></tr></table></figure><p><strong>Ltrim</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> Rpush mylist <span class="string">"hello"</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> Rpush mylist <span class="string">"hello1"</span></span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br><span class="line">127.0.0.1:6379> Rpush mylist <span class="string">"hello2"</span></span><br><span class="line">(<span class="built_in">integer</span>) 3</span><br><span class="line">127.0.0.1:6379> Rpush mylist <span class="string">"hello3"</span></span><br><span class="line">(<span class="built_in">integer</span>) 4</span><br><span class="line">127.0.0.1:6379> 1trim mylist 1 2 <span class="comment">#通过下标截取指定的长度</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379> LRANGE my7ist o -1</span><br><span class="line">1) <span class="string">"hello1"</span></span><br><span class="line">2) <span class="string">"hello2"</span></span><br></pre></td></tr></table></figure><p><strong>lset</strong></p><p>将列表中指定下标的值替换为另外一个值,更新操作</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> EXISTs list </span><br><span class="line">(<span class="built_in">integer</span>) o</span><br><span class="line">127.0.0.1:6379> 1set list 0 item <span class="comment">#如果不存在,就会报错</span></span><br><span class="line">(error) ERR no such key</span><br><span class="line">127.0.0.1:6379> 1push list value1</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> LRANGE list 0 0</span><br><span class="line">1)<span class="string">"value1"</span></span><br><span class="line">127.0.0.1:6379> 1set list 0 item <span class="comment">#如果存在,更新当前下标的值</span></span><br><span class="line">ok</span><br><span class="line">127.0.0.1:6379> LRANGE 1ist 0 0</span><br><span class="line">1) <span class="string">"item"</span></span><br></pre></td></tr></table></figure><p><strong>linsert</strong></p><p>将某个具体的value插入到列表中某个元素的前面或者后面</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> Rpush mylist <span class="string">"hello"</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> Rpush mylist <span class="string">"world"</span></span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br><span class="line">127.0.0.1:6379> LINSERT mylist before <span class="string">"world"</span> <span class="string">"other"</span></span><br><span class="line">(<span class="built_in">integer</span>) 3</span><br><span class="line">127.0.0.1:6379> LRANGE mylist 0 -1</span><br><span class="line">1) <span class="string">"hello"</span></span><br><span class="line">2) <span class="string">"other"</span></span><br><span class="line">3) <span class="string">"world"</span></span><br><span class="line">127.0.0.1:6379> LINSERT mylist after wor1d new</span><br><span class="line">(<span class="built_in">integer</span>) 4</span><br><span class="line">127.0.0.1:6379>LRANGE mylist o -1</span><br><span class="line">1) <span class="string">"hello"</span></span><br><span class="line">2) <span class="string">"other"</span></span><br><span class="line">3) <span class="string">"world"</span></span><br><span class="line">4) <span class="string">"new"</span></span><br></pre></td></tr></table></figure><h2 id="Set-集合"><a href="#Set-集合" class="headerlink" title="Set(集合)"></a>Set(集合)</h2><p><strong>set中的值是不能重复的</strong></p><p><strong>在Set里面,所有命令都是以s开头的</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> sadd myset <span class="string">"hello"</span> <span class="comment">#set集合中添加元素</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> sadd myset <span class="string">"w"</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379>SMEMBERS myset <span class="comment">#查看指定set的所有值</span></span><br><span class="line">1) <span class="string">"he1lo"</span></span><br><span class="line">2) <span class="string">"w"</span></span><br><span class="line">127.0.0.1:6379>SISMEMBER scard myset <span class="comment">#获取set集合中的元素个数</span></span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br><span class="line">127.0.0.1:6379>SISMEMBER myset hello <span class="comment">#判断某个值是不是在set集合中</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379>SISMEMBER myset world</span><br><span class="line">(<span class="built_in">integer</span>) o</span><br></pre></td></tr></table></figure><p><strong>srem</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> srem myset hello <span class="comment">#移除set集合中的指定元素</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> scard myset</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379>SMEMBERS myset</span><br><span class="line">1) <span class="string">"w"</span></span><br></pre></td></tr></table></figure><p><strong>set 无序不重复集合。抽随机</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379>SMEMBERS myset</span><br><span class="line">1) <span class="string">"w2"</span></span><br><span class="line">2) <span class="string">"w"</span></span><br><span class="line">3) <span class="string">"s"</span></span><br><span class="line">127.0.0.1:6379> SRANDMEMBER myset <span class="comment">#随机抽选出一个元素</span></span><br><span class="line"><span class="string">"w"</span></span><br><span class="line">127.0.0.1:6379>SRANDMEMBER myset</span><br><span class="line"><span class="string">"s"</span></span><br><span class="line">127.0.0.1:6379>SRANDMEMBER myset 2 <span class="comment">#随机抽选出指定个数的元素</span></span><br><span class="line">1) <span class="string">"w2"</span></span><br><span class="line">2) <span class="string">"w"</span></span><br></pre></td></tr></table></figure><p><strong>删除指定的key,随机删除key</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379>SMEMBERS myset</span><br><span class="line">1) <span class="string">"w2"</span></span><br><span class="line">2) <span class="string">"w"</span></span><br><span class="line">3) <span class="string">"s"</span></span><br><span class="line">127.0.0.1:6379> spop myset <span class="comment">#随机删除一些set集合中的元素</span></span><br><span class="line"><span class="string">"w2"</span></span><br><span class="line">127.0.0.1:6379> spop myset</span><br><span class="line"><span class="string">"w"</span></span><br><span class="line">127.0.0.1:6379>SMEMBERS myset</span><br><span class="line">1)<span class="string">"s"</span></span><br></pre></td></tr></table></figure><p><strong>微博,B站,共同关注!(交集)</strong><br>数字集合类:</p><ul><li>差集 SDIFF</li><li>交集</li><li>并集</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> SDIFF key1 key2 <span class="comment">#差集</span></span><br><span class="line">1) <span class="string">"b"</span></span><br><span class="line">2) <span class="string">"a"</span></span><br><span class="line">127.0.0.1:6379>SINTER key1 key2 <span class="comment">#交集 共同好友就可以这样实现</span></span><br><span class="line">1) <span class="string">"c"</span></span><br><span class="line">127.0.0.1:6379>SUNION key1 key2 <span class="comment">#并集</span></span><br><span class="line">1) <span class="string">"b"</span></span><br><span class="line">2) <span class="string">"c"</span></span><br><span class="line">3) <span class="string">"e"</span></span><br><span class="line">4) <span class="string">"a"</span></span><br><span class="line">5) <span class="string">"d"</span></span><br></pre></td></tr></table></figure><h2 id="Hash-哈希"><a href="#Hash-哈希" class="headerlink" title="Hash(哈希)"></a>Hash(哈希)</h2><p>Map集合,key-map</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> hset myhash field1 w <span class="comment">#set一个具体 key-vlaue</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> hget myhash field1 <span class="comment"># 获取一个字段值</span></span><br><span class="line"><span class="string">"w"</span></span><br><span class="line">127.0.0.1:6379> hset myhash field2 s</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> HGETALL myhash</span><br><span class="line">1) <span class="string">"field1"</span></span><br><span class="line">2) <span class="string">"w"</span></span><br><span class="line">3) <span class="string">"field2"</span></span><br><span class="line">4) <span class="string">"s"</span></span><br><span class="line">127.0.0.1:6379> hdel myhash field1 <span class="comment">#删除hash指定key字段,对应的value值也就消失了</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> hgetall myhash</span><br><span class="line">1) <span class="string">"field2"</span></span><br><span class="line">2) <span class="string">"s"</span></span><br></pre></td></tr></table></figure><p><strong>hlen</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> hset myhash field1 hello field2 world</span><br><span class="line">ok</span><br><span class="line">127.0.0.1:6379> HGETALL myhash</span><br><span class="line">1) <span class="string">"field2"</span></span><br><span class="line">2) <span class="string">"world"</span></span><br><span class="line">3) <span class="string">"field1"</span></span><br><span class="line">4) <span class="string">"hello"</span></span><br><span class="line">127.0.0.1:6379> hlen myhash <span class="comment">#获取hash表的字段数量!</span></span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br><span class="line">127.0.0.1:6379>HEXISTs myhash field2 <span class="comment">#判断hash中指定字段是否存在</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379>HEXISTs myhash field3</span><br><span class="line">(<span class="built_in">integer</span>) o</span><br><span class="line">127.0.0.1:6379> hkeys myhash <span class="comment">#只获得所有field</span></span><br><span class="line">1) <span class="string">"field2"</span></span><br><span class="line">2) <span class="string">"field1"</span></span><br><span class="line">127.0.0.1:6379> hvals myhash <span class="comment">#只获得所有value</span></span><br><span class="line">1) <span class="string">"world"</span></span><br><span class="line">2) <span class="string">"hello"</span></span><br></pre></td></tr></table></figure><h2 id="Zset-有序集合"><a href="#Zset-有序集合" class="headerlink" title="Zset(有序集合)"></a>Zset(有序集合)</h2><p>在set的基础上,增加了一个值,set 看k1 v1 zset k1 score1 v1 </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> zadd myset 1 one <span class="comment">#添加一个值</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> zadd myset 2 two 3 three <span class="comment">#添加多个值</span></span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br><span class="line">127.0.0.1:6379>ZRANGE myset 0 -1</span><br><span class="line">1) <span class="string">"one"</span></span><br><span class="line">2) <span class="string">"two"</span></span><br><span class="line">3) <span class="string">"three"</span></span><br></pre></td></tr></table></figure><p><strong>排序如何实现</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> zadd salary 2500 xiaohong <span class="comment">#添加三个用户</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> zadd salary 5000 zhangsan</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> zadd salary 500 w</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf <span class="comment">#显示全部的用户,从小到大</span></span><br><span class="line">1) <span class="string">"w"</span></span><br><span class="line">2) <span class="string">"xiaohong"</span></span><br><span class="line">3) <span class="string">"zhangsan"</span></span><br><span class="line">127.0.0.1:6379>ZRANGEBYSCORE salary -inf +inf withscores <span class="comment">#显示全部的用户并附带成绩</span></span><br><span class="line">1) <span class="string">"w"</span></span><br><span class="line">2) <span class="string">"500"</span></span><br><span class="line">3) <span class="string">"xiaohong"</span></span><br><span class="line">4) <span class="string">"2500"</span></span><br><span class="line">5) <span class="string">"zhangsan"</span></span><br><span class="line">5) <span class="string">"5000"</span></span><br></pre></td></tr></table></figure><p><strong>zrem</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> zrange salary 0 -1</span><br><span class="line">1) <span class="string">"w"</span></span><br><span class="line">2) <span class="string">"xiaohong"</span></span><br><span class="line">3) <span class="string">"zhangsan"</span></span><br><span class="line">127.0.0.1:6379> zrem salary xiaohong <span class="comment">#移除有序集合中的指定元素</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> zrange salary 0 -1</span><br><span class="line">1) <span class="string">"w"</span></span><br><span class="line">2) <span class="string">"zhangsan"</span></span><br><span class="line">127.0.0.1:6379> zcard salary <span class="comment">#获取有序集合中的个数</span></span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br></pre></td></tr></table></figure><h1 id="三种特殊数据类型"><a href="#三种特殊数据类型" class="headerlink" title="三种特殊数据类型"></a>三种特殊数据类型</h1><h2 id="geospatial"><a href="#geospatial" class="headerlink" title="geospatial"></a>geospatial</h2><p>朋友的定位,附近的人,打车距离计算?</p><p>6个命令</p><ul><li>GEOADD</li><li>GEODIST</li><li>GEOHASH</li><li>GEOPOS</li><li>GEORADIUS</li><li>GEORADIUSBYLEMBER</li></ul><blockquote><p>geoadd</p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#getadd添加地理位置</span></span><br><span class="line"><span class="comment">#两极无法直接添加,一般会下载城市数据,通过java程序一次性导入</span></span><br><span class="line"></span><br><span class="line">127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing 114.05 22.52 shenzhen</span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br><span class="line">127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian</span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br></pre></td></tr></table></figure><blockquote><p>geopos</p></blockquote><p>获得当前定位:一定是一个坐标值</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379>GEOPOS china:city beijing<span class="comment"># 获取指定的城市的经度和纬度!</span></span><br><span class="line">1)1) <span class="string">"116.39999896287918091"</span></span><br><span class="line"> 2) <span class="string">"39.90000009167092543"</span></span><br><span class="line">127.0.0.1:6379>GEOPOS china:city beijing chongqing</span><br><span class="line">1) 1) <span class="string">"116.39999896287918091"</span></span><br><span class="line"> 2) <span class="string">"39.90000009167092543"</span></span><br><span class="line">2) 1) <span class="string">"106.49999767541885376"</span></span><br><span class="line"> 2) <span class="string">"29.52999957900659211"</span></span><br></pre></td></tr></table></figure><blockquote><p>geodist</p></blockquote><p>两人之间的距离</p><p>单位:</p><ul><li><p>m表示单位为米。</p></li><li><p>km表示单位为千米。</p></li><li><p>mi表示单位为英里。</p></li><li><p>ft表示单位为英尺。</p></li></ul><blockquote><p>georadius 以给定的经纬度为中心,找出某一半径内的元素</p></blockquote><p>我附近的人?(获得所有附近的人的地址,定位!)通过半径来查询!</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km <span class="comment">#以110,30这个经纬度为中心,寻找方圆1000km内的城市</span></span><br><span class="line">1) <span class="string">"chongqing"</span></span><br><span class="line">2) <span class="string">"xian"</span></span><br><span class="line">3) <span class="string">"shenzhen"</span></span><br><span class="line">4) <span class="string">"hangzhou"</span></span><br><span class="line">127.0.0.1:6379> GEORADIUS china:city 110 30 500 km</span><br><span class="line">1) <span class="string">"chongqing"</span></span><br><span class="line">2) <span class="string">"xian"</span></span><br><span class="line">127.0.0.1:6379>GEORADIUS china:city 110 30 500 km withdist <span class="comment">#显示到中心的距离</span></span><br><span class="line">1) 1) <span class="string">"chongqi"</span></span><br><span class="line"> 2) <span class="string">"341.9374"</span></span><br><span class="line">2) 1) <span class="string">"xian"</span></span><br><span class="line"> 2) <span class="string">"483.8340"</span><span class="string">"</span></span><br><span class="line"><span class="string">127.0.0.1:6379>GEORADIUS china:city 110 30 500 km withcoord</span></span><br><span class="line"><span class="string">1) 1) "</span>chongqi<span class="string">"</span></span><br><span class="line"><span class="string"> 2) 1) "</span>106.49999767541885376<span class="string">"</span></span><br><span class="line"><span class="string"> 2) "</span>29.52999957900659211<span class="string">"</span></span><br><span class="line"><span class="string">2) 1) "</span>xian<span class="string">"</span></span><br><span class="line"><span class="string"> 2) 1) "</span>108.96000176668167114<span class="string">"</span></span><br><span class="line"><span class="string"> 2) "</span>34.25999964418929977<span class="string">"</span></span><br><span class="line"><span class="string">127.0.0.1:6379>GEORADIUS china:city 110 30 500 km withdist withcoord count 1 #筛选出指定的结果</span></span><br><span class="line"><span class="string">1) 1) "</span>chongqing<span class="string">"</span></span><br><span class="line"><span class="string"> 2)"</span>341.9374<span class="string">"</span></span><br><span class="line"><span class="string"> 3) 1) "</span>106.49999767541885376<span class="string">"</span></span><br><span class="line"><span class="string"> 2) "</span>29.52999957900659211<span class="string">"</span></span><br></pre></td></tr></table></figure><blockquote><p>georadiusbymember</p></blockquote><p>找出位于指定元素周围的其他元素</p><blockquote><p>geohash 返回一个或多个位置元素的Geohash表示</p></blockquote><p>该命令将返回11个字符的Geohash字符串</p><p>底层用Zset实现</p><h2 id="Hyperloglog"><a href="#Hyperloglog" class="headerlink" title="Hyperloglog"></a>Hyperloglog</h2><blockquote><p>什么是基数?</p></blockquote><p>A{1,3,5,7,8,7}</p><p>B{1,3,5,7,8}</p><p>基数(一个集合中不重复的元素)=5,可以接受误差</p><blockquote><p>简介</p></blockquote><p>Redis 2.8.9版本就更新了Hyperloglog数据结构!Redis Hyperloglog基数统计的算法</p><p>网页的UV(一个人访问一个网站多次,但是还是算作一个人)</p><p>传统的方式,set保存用户的id,然后就可以统计set中的元素数量作为标准判断。这个方式如果保存大量的用户id,就会比较麻烦</p><h2 id="Bitmaps"><a href="#Bitmaps" class="headerlink" title="Bitmaps"></a>Bitmaps</h2><blockquote><p>位存储</p></blockquote><p>统计用户信息,活跃,不活跃。登录、未登录。打卡,365打卡。两个状态的,都可以使用Bitmaps。<br>Bitmaps位图,数据结构。都是操作二进制位来进行记录,就只有0和1两个状态<br>365天= 365bit 1字节= 8bit 46个字节左右</p><p>使用bitmap来记录周一到周日的打卡!</p><p>周一∶1 周二:0 周三:0 周四:1 …….</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> setbit sign 0 1</span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line">127.0.0.1:6379> setbit sign 1 0</span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line">i27.0.0.1:6379> setbit sign 2 0</span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line">127.0.0.1:6379> setbit sign 3 1</span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line">127.0.0.1:6379> setbit sign 4 1</span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line">127.0.0.1:6379> setbit sign 5 0</span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line">127.0.0.1:6379> setbit sign 6 0</span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br></pre></td></tr></table></figure><p>查看某一天是否有打卡</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> getbit sign 3</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379> getbit sign 6</span><br><span class="line">(<span class="built_in">integer</span>) o</span><br></pre></td></tr></table></figure><p>统计打卡的天数</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> bitcount sign</span><br><span class="line">(<span class="built_in">integer</span>) 3</span><br></pre></td></tr></table></figure><h1 id="事务"><a href="#事务" class="headerlink" title="事务"></a>事务</h1><p>Redis事务本质︰一组命令的集合。一个事务中的所有命令都会被序列化,在事务执行过程的过程中,会按照顺序执行。</p><p>一次性、顺序性、排他性,执行一系列的命令!</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">-----队列set1 set2 set3执行------</span><br></pre></td></tr></table></figure><p><strong>Redis事务没有没有隔离级别的概念!</strong></p><p>所有的命令在事务中并没有直接被执行。只有在发起执行命令的时候才会被执行 Exec</p><p><strong>Redis单条命令是保证原子性的,但是事务不保证原子性!</strong></p><p>过程:</p><ul><li><p>开启事务(multi)</p></li><li><p>命令入队(…)</p></li><li><p>执行事务(exec)</p></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> multi</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> k1 v1</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> k2 v2</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379> get k2</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> k3 v3</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379> <span class="built_in">exec</span></span><br><span class="line">1) OK</span><br><span class="line">2) OK</span><br><span class="line">3) <span class="string">"v2"</span></span><br><span class="line">4) OK</span><br></pre></td></tr></table></figure><blockquote><p>放弃事务</p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> multi</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> k1 v1</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> k2 v2</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> k4 v4</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379> DISCARD</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379>get k4</span><br><span class="line">(ni1)</span><br></pre></td></tr></table></figure><blockquote><p>编译型异常(代码有问题,命令有错),事务中所有的命令都不会被执行。</p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> multi</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> k1 v1</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> k2 v2</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> k3 v3</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379>getset k3 <span class="comment">#错误的命令</span></span><br><span class="line">(error) ERR wrong number of arguments <span class="keyword">for</span> <span class="string">'getset'</span> <span class="built_in">command</span></span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> k4 v4</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> k5 v5</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379> <span class="built_in">exec</span> <span class="comment">#执行事务报错!</span></span><br><span class="line">(error) EXECABORT Transaction discarded because of previous errors.</span><br><span class="line">127.0.0.1:6379> get k5 <span class="comment">#所有的命令都不会被执行!</span></span><br><span class="line">(nil)</span><br></pre></td></tr></table></figure><blockquote><p>运行时异常(1/0),如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的,错误命令会抛出异常</p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379><span class="built_in">set</span> k1 <span class="string">"v1"</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379> multi</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379> incr k1 <span class="comment">#会执行的时候失败</span></span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> k2 v2</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> k3 v3</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379> get k3</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379> <span class="built_in">exec</span></span><br><span class="line">1)(error)ERR value is not an <span class="built_in">integer</span> or out of range <span class="comment">#虽然第一条命令报错了,但是依旧正常执行成功</span></span><br><span class="line">2) OK</span><br><span class="line">3) OK</span><br><span class="line">4) <span class="string">"v3"</span></span><br><span class="line">127.0.0.1:6379> get k2</span><br><span class="line"><span class="string">"v2"</span></span><br><span class="line">127.0.0.1:6379> get k3</span><br><span class="line"><span class="string">"v3"</span></span><br></pre></td></tr></table></figure><blockquote><p>监控 Watch</p></blockquote><p>悲观锁: 很悲观,认为什么时候都会出问题,无论做什么都会加锁。</p><p>乐观锁: </p><ul><li>很乐观,认为什么时候都不会出问题,所以不会上锁。更新数据的时候去判断一下,在此期间是否有人修改过这个数据</li><li>获取version</li><li>更新的时候比较version</li></ul><blockquote><p>Redis监视测试</p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> <span class="built_in">set</span> money 100</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379> <span class="built_in">set</span> out 0</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379> watch money <span class="comment">#监视money对象</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379> multi <span class="comment">#事务正常结束,数据期间没有发生变动,这个时候就正常执行成功</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379>DECRBY money 20</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379>INCRBY out 20</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6379><span class="built_in">exec</span></span><br><span class="line">1) (<span class="built_in">integer</span>) 80</span><br><span class="line">2) (<span class="built_in">integer</span>) 20</span><br></pre></td></tr></table></figure><p>如果事务执行失败就使用unwatch命令解锁后重新上锁即可</p><h1 id="Jedis"><a href="#Jedis" class="headerlink" title="Jedis"></a>Jedis</h1><blockquote><p>什么是Jedis? 是Redis官方推荐的java连接开发工具,使用]ava操作Redis中间件。如果你要使用java操作redis,那么一定要对Jedis十分的熟悉。</p></blockquote><ol><li>导入对应依赖</li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><!--导入jedis的包--></span><br><span class="line"><dependencies></span><br><span class="line"><dependency></span><br><span class="line"><groupId>redis.clients</groupId></span><br><span class="line"><artifactId>jedis</artifactId></span><br><span class="line"><version><span class="number">3.2</span><span class="number">.0</span></version></span><br><span class="line"></dependency></span><br><span class="line"><! --fastjson--></span><br><span class="line"><dependency></span><br><span class="line"><groupId>com.alibaba</groupId></span><br><span class="line"><artifactId>fastjson</artifactId></span><br><span class="line"><version><span class="number">1.2</span><span class="number">.62</span></version></span><br><span class="line"> </dependency></span><br><span class="line"></dependencies></span><br></pre></td></tr></table></figure><ol start="2"><li>编码测试:</li></ol><ul><li><p>连接数据库</p></li><li><p>操作命令</p></li><li><p>断开连接</p></li></ul><h1 id="SpringBoot整合"><a href="#SpringBoot整合" class="headerlink" title="SpringBoot整合"></a>SpringBoot整合</h1><p>在SpringBoot2.x之后,原来使用的jedis被替换为了lettuce</p><p>jedis :采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全的情况,使用jedis pool连接池。更像BIO模式</p><p>lettuce :采用netty,实例可以再多个线程中进行共享,不存在线程不安全的情况,可以减少线程数量。更像NIO模式</p><p>配置文件</p><figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">spring.redis.port</span>=<span class="string">6379</span></span><br><span class="line"><span class="attr">spring.redis.host</span>=<span class="string">127.0.0.1</span></span><br></pre></td></tr></table></figure><p>在redis里,所有实体类需要序列化</p><h1 id="Redis-conf"><a href="#Redis-conf" class="headerlink" title="Redis.conf"></a>Redis.conf</h1><p>配置文件unit单位对大小写不敏感</p><blockquote><p>网络</p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">bind</span> 127.0.0.1 <span class="comment">#绑定的ip</span></span><br><span class="line">protected-mode <span class="built_in">yes</span> <span class="comment"># 保护模式</span></span><br></pre></td></tr></table></figure><blockquote><p>通用GENERAL</p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">daemonize <span class="built_in">yes</span> <span class="comment">#以守护进程的方式运行,默认是no,我们需要自己开启为yes</span></span><br><span class="line">pidfile /var/run/redis_6379.pid <span class="comment"># 如果以后台的方式运行,我们就需要指定一个pid 文件</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 日志</span></span><br><span class="line"><span class="comment"># specify the server verbosity level.</span></span><br><span class="line"><span class="comment"># This can be one of:</span></span><br><span class="line"><span class="comment"># debug (a lot of information,useful for development/testing)</span></span><br><span class="line"><span class="comment"># verbose (many rarely useful info,but not a mess like the debug level)</span></span><br><span class="line"><span class="comment"># notice (moderately verbose,what you want in production probably) 生产环境</span></span><br><span class="line"><span class="comment"># warning (only very important / critical messages are logged)</span></span><br><span class="line">loglevel notice</span><br><span class="line">logfile <span class="string">""</span> <span class="comment">#日志的文件位置名</span></span><br><span class="line">databases 16 <span class="comment">#数据库的数量,默认是16个数据库</span></span><br><span class="line">always-shop-logo <span class="built_in">yes</span> <span class="comment">#是否总是显示LOGO</span></span><br></pre></td></tr></table></figure><blockquote><p>快照</p></blockquote><p>即持久化,在规定的时间内,执行了多少次操作,则会持久化到文件.rdb .aof</p><p>redis 是内存数据库,如果没有持久化,那么数据断电即失</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#如果900s内,如果至少有一个key进行了修改,我们即进行持久化操作</span></span><br><span class="line">save 900 1</span><br><span class="line"><span class="comment">#如果300s内,如果至少10个key进行了修改,我们即进行持久化操作</span></span><br><span class="line">save 300 10</span><br><span class="line"><span class="comment">#如果60s内,如果至少10000个key进行了修改,我们即进行持久化操作</span></span><br><span class="line">save 60 10000</span><br><span class="line">rdbcompression <span class="built_in">yes</span> <span class="comment">#是否压缩rdb文件,需要消耗一些cpu资源</span></span><br><span class="line">rdbchecksum <span class="built_in">yes</span> <span class="comment">#保存rdb文件的时候,进行错误的检查校验!</span></span><br></pre></td></tr></table></figure><blockquote><p>SECURITY 安全</p></blockquote><p>可以在这里设置redis的密码,默认是没有密码!</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> config get requirepass <span class="comment">#获取redis的密码</span></span><br><span class="line">1) <span class="string">"requirepass"</span></span><br><span class="line">2) <span class="string">""</span></span><br><span class="line">127.0.0.1:6379> config <span class="built_in">set</span> requirepass <span class="string">"123456"</span> <span class="comment"># 设置redis的密码</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379> config get requirepass <span class="comment"># 发现所有的命令都没有权限了</span></span><br><span class="line">(error)NOAUTH Authentication required.</span><br><span class="line">127.0.0.1:6379> ping</span><br><span class="line">(error) NOAUTH Authentication required.</span><br><span class="line">127.0.0.1:6379> auth 123456 <span class="comment"># 使用密码进行登录</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379> config get requirepass</span><br><span class="line">1) <span class="string">"requirepass"</span></span><br><span class="line">2) <span class="string">"123456"</span></span><br></pre></td></tr></table></figure><blockquote><p>APPEND ONLY模式aof配置</p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">appendon1y no <span class="comment">#默认是不开启aof模式的,默认是使用rdb方式持久化的,在大部分所有的情况下,rdb完全够用</span></span><br><span class="line">appendfilename <span class="string">"appendonly.aof"</span> <span class="comment">#持久化文件的名字</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#appendfsync always #每次修改都会sync。消耗性能</span></span><br><span class="line">appendfsync everysec <span class="comment">#每秒执行一次sync,可能会丢失这1s的数据</span></span><br><span class="line"><span class="comment">#appendfsync no #不执行sync,这个时候操作系统自己同步数据,速度最快</span></span><br></pre></td></tr></table></figure><h1 id="Redis持久化"><a href="#Redis持久化" class="headerlink" title="Redis持久化"></a>Redis持久化</h1><p>Redis是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失。所以Redis提供了持久化功能。</p><h2 id="RDB-Redis-DataBase"><a href="#RDB-Redis-DataBase" class="headerlink" title="RDB ( Redis DataBase )"></a>RDB ( Redis DataBase )</h2><p><img src="/2022/04/14/Redis%E5%AD%A6%E4%B9%A0/2.jpg" alt="image-20220703231236493"></p><p>在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。</p><p>Redis会单独创建 ( fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的。这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。默认的就是RDB,一般情况下不需要修改这个配置.</p><blockquote><p>触发机制</p></blockquote><ol><li><p>save的规则满足的情况下,会自动触发rdb规则</p></li><li><p>执行flushall命令,也会触发我们的rdb规则</p></li><li><p>退出redis,也会产生rdb文件</p></li></ol><p>备份就自动生成一个dump.rdb</p><blockquote><p>如何恢复rdb文件</p></blockquote><ol><li><p>只需要将rdb文件放在我们redis启动目录就可以,redis启动的时候会自动检查dump.rdb恢复其中的数据!</p></li><li><p>查看需要存在的位置</p></li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> config get <span class="built_in">dir</span></span><br><span class="line">1) <span class="string">"dir"</span></span><br><span class="line">2) <span class="string">"/usr/loca1/bin"</span>_ <span class="comment"># 如果在这个目录下存在 dump.rdb 文件,启动就会自动恢复其中的数据</span></span><br></pre></td></tr></table></figure><h2 id="AOF-Append-Only-File"><a href="#AOF-Append-Only-File" class="headerlink" title="AOF( Append Only File )"></a>AOF( Append Only File )</h2><p>将我们的所有命令都记录下来,history,恢复的时候就把这个文件全部再执行一遍</p><blockquote><p>是什么</p></blockquote><p><img src="/2022/04/14/Redis%E5%AD%A6%E4%B9%A0/3.jpg" alt="image-20220703231236493"></p><p>以日志的形式来记录每个写操作,将Redis执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作</p><p><strong>Aof保存的是appendonly.aof文件</strong></p><p>默认是不开启的,我们需要手动进行配置,我们只需要将appendoly改为yes就开启了aof,重启redis就可以生效了。</p><p>如果这个aof文件有错误,这个时候redis是启动不起来的,我们需要修复这个aof文件</p><p>redis给我们提供了一个工具redis-check-aof –fix</p><p>优点:</p><ol><li>每一次修改都同步,文件的完整性会更加好。</li><li>每秒同步一次,可能会丢失一秒的数据。</li><li>从不同步,效率最高的。</li></ol><p>缺点:</p><ol><li>相对于数据文件来说,aof远远大于rdb,修复的速度也比rdb慢。</li><li>Aof运行效率也要比rdb慢,所以我们redis默认的配置就是rdb持久化。</li></ol><h1 id="Redis发布订阅"><a href="#Redis发布订阅" class="headerlink" title="Redis发布订阅"></a>Redis发布订阅</h1><p>Redis发布订阅(pub/sub)是一种消息通信模式∶发送者(pub)发送消息,订阅者(sub)接收消息。微信、微博、关注系统。</p><p>Redis客户端可以订阅任意数量的频道。</p><p>订阅/发布消息图∶</p><p><img src="/2022/04/14/Redis%E5%AD%A6%E4%B9%A0/4.png" alt="image-20220703231236493"></p><p>下图展示了频道channel1,以及订阅这个频道的三个客户端―— client2、client5和client1之间的关系∶</p><p><img src="/2022/04/14/Redis%E5%AD%A6%E4%B9%A0/5.png" alt="image-20220703231236493"></p><p>当有新消息通过PUBLISH命令发送给频道channel1时,这个消息就会被发送给订阅它的三个客户端︰</p><p><img src="/2022/04/14/Redis%E5%AD%A6%E4%B9%A0/6.png" alt="image-20220703231236493"></p><p>订阅端:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> SUBSCRIBE w <span class="comment"># 订阅一个频道w</span></span><br><span class="line">Reading messages. . . (press ctr1-c to quit</span><br><span class="line">1) <span class="string">"subscribe"</span></span><br><span class="line">2) <span class="string">"w"</span></span><br><span class="line">3) (<span class="built_in">integer</span>) 1</span><br><span class="line"><span class="comment">#等待读取推送的信息</span></span><br><span class="line">1) <span class="string">"message"</span> <span class="comment">#消息</span></span><br><span class="line">2) <span class="string">"w"</span> <span class="comment">#哪个频道的消息</span></span><br><span class="line">3) <span class="string">"he11o"</span> <span class="comment">#消息的具体内容</span></span><br><span class="line">1) <span class="string">"message"</span></span><br><span class="line">2) <span class="string">"w"</span></span><br><span class="line">3) <span class="string">"hello,redis"</span></span><br></pre></td></tr></table></figure><p>发送端:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> PUBLISH w <span class="string">"hello"</span> <span class="comment">#发布者发布消息到频道</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6379>PUBLISH w <span class="string">"hello, redis"</span> <span class="comment">#发布者发布消息到频道</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br></pre></td></tr></table></figure><h1 id="Redis主从复制"><a href="#Redis主从复制" class="headerlink" title="Redis主从复制"></a>Redis主从复制</h1><p><strong>概念</strong></p><p>主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(mastler/leader),后者称为从节点<br>(slave/follower);数据的复制是单向的,只能由主节点到从节点。Master以写为主,Slave以读为主。</p><p>默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。</p><p><strong>主从复制的作用主要包括:</strong></p><ol><li><p>数据冗余︰主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。</p></li><li><p>故障恢复∶当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。</p></li><li><p>负载均衡︰在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。</p></li><li><p>高可用(集群)基石︰除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。</p></li></ol><p>一般来说,要将Redis运用于工程项目中,只使用一台Redis是万万不能的(宕机),原因如下∶</p><ol><li><p>从结构上,单个Redis服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力较大;</p></li><li><p>从容量上,单个Redis服务器内存容量有限,就算一台Redis服务器内存容量为256G,也不能将所有内存用作Redis存储内存,一般来说,单台Redis最大使用内存不应该超过20G。</p></li></ol><p>电商网站上的商品,一般都是一次上传,无数次浏览的,说专业点也就是”多读少写”。</p><p>对于这种场景,可以使用如下架构:</p><p><img src="/2022/04/14/Redis%E5%AD%A6%E4%B9%A0/7.png" alt="image-20220703231236493"></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379> info replication <span class="comment">#查看当前库的信息</span></span><br><span class="line"><span class="comment"># Replication</span></span><br><span class="line">role:master <span class="comment">#角色 master</span></span><br><span class="line">connected_slaves:0 <span class="comment">#没有从机</span></span><br><span class="line">master_failover_state:no-failover</span><br><span class="line">master_replid:e1898b9410ce62b2f39ede99279537b8a2e2f8aa</span><br><span class="line">master_replid2:0000000000000000000000000000000000000000</span><br><span class="line">master_repl_offset:0</span><br><span class="line">second_repl_offset:-1</span><br><span class="line">repl_backlog_active:0</span><br><span class="line">repl_backlog_size:1048576</span><br><span class="line">repl_backlog_first_byte_offset:0</span><br><span class="line">repl_backlog_histlen:0</span><br></pre></td></tr></table></figure><blockquote><p>复制原理</p></blockquote><p>Slave启动成功连接到master后会发送一个sync同步命令</p><p>Master接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到<br>slave,并完成一次完全同步。</p><p>全量复制∶而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。</p><p>增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步</p><p>但是只要是重新连接master,一次完全同步(全量复制)将被自动执行</p><h2 id="哨兵模式"><a href="#哨兵模式" class="headerlink" title="哨兵模式"></a>哨兵模式</h2><blockquote><p>概述</p></blockquote><p>主从切换技术的方法是︰当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。Redis从2.8开始正式提供了Sentinel (哨兵)架构来解决这个问题。</p><p>谋朝篡位的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。</p><p>哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是<strong>哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。</strong></p><p><img src="/2022/04/14/Redis%E5%AD%A6%E4%B9%A0/8.png" alt="image-20220703231236493"></p><p>这里的哨兵有两个作用</p><ul><li><p>通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。</p></li><li><p>当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。</p></li></ul><p>然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。</p><p><img src="/2022/04/14/Redis%E5%AD%A6%E4%B9%A0/9.png" alt="image-20220703231236493"></p><p>假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为<strong>主观下线</strong>。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover[故障转移]操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为<strong>客观下线</strong>。</p><p>1、配置哨兵配置文件sentinel.conf</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># sentinel monitor 被监控的名称 hostport 1</span></span><br><span class="line">sentinel monitor myredis 127.0.0.1 6379 1</span><br></pre></td></tr></table></figure><p>后面的这个数字1,代表主机挂了,slave投票让谁接替成为主机,票数最多的,就会成为主机</p><p>如果此时主机回来了,只能归并到新的主机下,当做从机。</p><h1 id="Redis缓存穿透和雪崩"><a href="#Redis缓存穿透和雪崩" class="headerlink" title="Redis缓存穿透和雪崩"></a>Redis缓存穿透和雪崩</h1><p>Redis缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面。但同时,它也带来了一些问题。其中,最要害的问题,就是数据的一致性问题,从严格意义上讲,这个问题无解。如果对数据的一致性要求很高,那么就不能使用缓存。</p><p>另外的一些典型问题就是,缓存穿透、缓存雪崩和缓存击穿。目前,业界也都有比较流行的解决方案。</p><h2 id="缓存穿透-查不到"><a href="#缓存穿透-查不到" class="headerlink" title="缓存穿透(查不到)"></a>缓存穿透(查不到)</h2><blockquote><p>概念</p></blockquote><p>缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。</p><blockquote><p>解决方案</p></blockquote><p><strong>布隆过滤器</strong></p><p>布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力。</p><p><img src="/2022/04/14/Redis%E5%AD%A6%E4%B9%A0/10.png" alt="image-20220703231236493"></p><p><strong>缓存空对象</strong></p><p>当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源。</p><p><img src="/2022/04/14/Redis%E5%AD%A6%E4%B9%A0/11.png" alt="image-20220703231236493"></p><p>但是这种方法会存在两个问题:</p><ol><li><p>如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键。</p></li><li><p>即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。</p></li></ol><h2 id="缓存击穿-量太大,缓存过期"><a href="#缓存击穿-量太大,缓存过期" class="headerlink" title="缓存击穿(量太大,缓存过期)"></a>缓存击穿(量太大,缓存过期)</h2><blockquote><p>概述</p></blockquote><p>这里需要注意和缓存击穿的区别,缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。</p><p>当某个key在过期的瞬间,有大量的请求并发访问,这类数据一般是热点数据,由于缓存过期,会同时访问数据库来查询最新数据,并且回写缓存,会导使数据库瞬间压力过大。</p><blockquote><p>解决方案</p></blockquote><p><strong>设置热点数据永不过期</strong></p><p>从缓存层面来看,没有设置过期时间,所以不会出现热点key过期后产生的问题。</p><p><strong>加互斥锁</strong></p><p>分布式锁∶使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。</p><h2 id="缓存雪崩"><a href="#缓存雪崩" class="headerlink" title="缓存雪崩"></a>缓存雪崩</h2><blockquote><p>概念</p></blockquote><p>缓存雪崩,是指在某一个时间段,缓存集中过期失效。Redis宕机</p><p>产生雪崩的原因之一,比如在写本文的时候,马上就要到双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。</p><p><img src="/2022/04/14/Redis%E5%AD%A6%E4%B9%A0/12.png" alt="image-20220703231236493"></p><p>其实集中过期,倒不是非常致命,比较致命的缓存雪崩,是缓存服务器某个节点宕机或断网。因为自然形成的缓存雪崩,一定是在某个时间段集中创建缓存,这个时候,数据库也是可以顶住压力的。无非就是对数据库产生周期性的压力而已。而缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮。</p><blockquote><p>解决方案</p></blockquote><p><strong>redis高可用</strong></p><p>这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。</p><p><strong>限流降级</strong></p><p>这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。</p><p><strong>数据预热</strong></p><p>数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。</p>]]></content>
<tags>
<tag> redis </tag>
</tags>
</entry>
<entry>
<title>Linux学习</title>
<link href="/2022/04/13/Linux%E5%AD%A6%E4%B9%A0/"/>
<url>/2022/04/13/Linux%E5%AD%A6%E4%B9%A0/</url>
<content type="html"><![CDATA[<h1 id="关机命令"><a href="#关机命令" class="headerlink" title="关机命令"></a>关机命令</h1><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">sync # 将数据由内存同步到硬盘中。</span><br><span class="line"></span><br><span class="line">shutdown # 关机指令,你可以man shutdown 来看一下帮助文档。例如你可以运行如下命令关机:</span><br><span class="line"></span><br><span class="line">shutdown –h 10 # 这个命令告诉大家,计算机将在10分钟后关机</span><br><span class="line"></span><br><span class="line">shutdown –h now # 立马关机</span><br><span class="line"></span><br><span class="line">shutdown –h 20:25 # 系统会在今天20:25关机</span><br><span class="line"></span><br><span class="line">shutdown –h +10 # 十分钟后关机</span><br><span class="line"></span><br><span class="line">shutdown –r now # 系统立马重启</span><br><span class="line"></span><br><span class="line">shutdown –r +10 # 系统十分钟后重启</span><br><span class="line"></span><br><span class="line">reboot # 就是重启,等同于 shutdown –r now</span><br><span class="line"></span><br><span class="line">halt # 关闭系统,等同于shutdown –h now 和 poweroff</span><br></pre></td></tr></table></figure><p><strong>不管是重启系统还是关闭系统,首先要运行 sync 命令,把内存中的数据写到磁盘中。</strong></p><h1 id="常用命令"><a href="#常用命令" class="headerlink" title="常用命令"></a>常用命令</h1><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">ls: 列出目录</span><br><span class="line"></span><br><span class="line"> -a :全部的文件,连同隐藏文件( 开头为 . 的文件) 一起列出来(常用)</span><br><span class="line"></span><br><span class="line"> -l :长数据串列出,包含文件的属性与权限等等数据;(常用)</span><br><span class="line"></span><br><span class="line">cd:切换目录</span><br><span class="line"></span><br><span class="line">pwd:显示目前的目录</span><br><span class="line"></span><br><span class="line">mkdir:创建一个新的目录</span><br><span class="line"></span><br><span class="line"> -m :配置文件的权限,直接配置,不需要看默认权限 (umask) 的脸色</span><br><span class="line"></span><br><span class="line"> -p :将所需要的目录(包含上一级目录)递归创建起来!</span><br><span class="line"></span><br><span class="line">rmdir:删除一个空的目录</span><br><span class="line"></span><br><span class="line">cp: 复制文件或目录</span><br><span class="line"></span><br><span class="line">rm: 移除文件或目录</span><br><span class="line"></span><br><span class="line"> -f :就是 force 的意思,忽略不存在的文件,不会出现警告信息;</span><br><span class="line"></span><br><span class="line"> -i :互动模式,在删除前会询问使用者是否动作</span><br><span class="line"></span><br><span class="line"> -r :递归删除!最常用在目录的删除了!这是非常危险的选项!!!</span><br><span class="line"></span><br><span class="line">mv: 移动文件与目录,或修改文件与目录的名称</span><br><span class="line"></span><br><span class="line"> -f :force 强制的意思,如果目标文件已经存在,不会询问而直接覆盖;</span><br><span class="line"></span><br><span class="line"> -i :若目标文件 (destination) 已经存在时,就会询问是否覆盖!</span><br><span class="line"></span><br><span class="line"> -u :若目标文件已经存在,且 source 比较新,才会升级 (update)</span><br></pre></td></tr></table></figure><p>pwd 是 Print Working Directory 的缩写,也就是显示目前所在目录的命令。</p><p><strong>不要执行rm -rf,否则会将你所有的文件删除!</strong></p><h1 id="基本属性"><a href="#基本属性" class="headerlink" title="基本属性"></a>基本属性</h1><p><img src="/2022/04/13/Linux%E5%AD%A6%E4%B9%A0/2.png" alt="image-20220703231236493"></p><p>实例中,boot文件的第一个属性用”d”表示。”d”在Linux中代表该文件是一个目录文件。</p><p>在Linux中第一个字符代表这个文件是目录、文件或链接文件等等:</p><p>当为[ d ]则是目录</p><p>当为[ - ]则是文件;</p><p>若是[ l ]则表示为链接文档 ( link file );</p><p>若是[ b ]则表示为装置文件里面的可供储存的接口设备 ( 可随机存取装置 );</p><p>若是[ c ]则表示为装置文件里面的串行端口设备,例如键盘、鼠标 ( 一次性读取装置 )。</p><p>接下来的字符中,以三个为一组,且均为『rwx』 的三个参数的组合。</p><p>其中,[ r ]代表可读(read)、[ w ]代表可写(write)、[ x ]代表可执行(execute)。</p><p>要注意的是,这三个权限的位置不会改变,如果没有权限,就会出现减号[ - ]而已。</p><p>每个文件的属性由左边第一部分的10个字符来确定</p><p>从左至右用0-9这些数字来表示。</p><p>第0位确定文件类型,第1-3位确定属主(该文件的所有者)拥有该文件的权限。第4-6位确定属组(所有者的同组用户)拥有该文件的权限,第7-9位确定其他用户拥有该文件的权限。</p><p>其中:</p><p>第1、4、7位表示读权限,如果用”r”字符表示,则有读权限,如果用”-“字符表示,则没有读权限;</p><p>第2、5、8位表示写权限,如果用”w”字符表示,则有写权限,如果用”-“字符表示没有写权限;</p><p>第3、6、9位表示可执行权限,如果用”x”字符表示,则有执行权限,如果用”-“字符表示,则没有执行权限。</p><p>对于文件来说,它都有一个特定的所有者,也就是对该文件具有所有权的用户。</p><p>同时,在Linux系统中,用户是按组分类的,一个用户属于一个或多个组。</p><p>文件所有者以外的用户又可以分为文件所有者的同组用户和其他用户。</p><p>因此,Linux系统按文件所有者、文件所有者同组用户和其他用户来规定了不同的文件访问权限。</p><p>在以上实例中,boot 文件是一个目录文件,属主和属组都为 root。</p><h1 id="修改文件属性"><a href="#修改文件属性" class="headerlink" title="修改文件属性"></a>修改文件属性</h1><p><strong>1、chgrp:更改文件属组</strong></p><p>chgrp [-R] 属组名 文件名<br> -R:递归更改文件属组,就是在更改某个目录文件的属组时,如果加上-R的参数,那么该目录下的所有文件的属组都会更改。</p><p><strong>2、chown:更改文件属主,也可以同时更改文件属组</strong></p><p>chown [–R] 属主名 文件名</p><p>chown [-R] 属主名:属组名 文件名</p><p><strong>3、chmod:更改文件9个属性</strong></p><p>chmod [-R] xyz 文件或目录</p><p>Linux文件属性有两种设置方法,一种是数字,一种是符号。</p><p>Linux文件的基本权限就有九个,分别是owner/group/others三种身份各有自己的read/write/execute权限。</p><p>文件的权限字符为:『-rwxrwxrwx』, 这九个权限是三个三个一组的!其中,我们可以使用数字来代表各个权限,各权限的分数对照表如下:</p><p>r:4 w:2 x:1</p><p>每种身份(owner/group/others)各自的三个权限(r/w/x)分数是需要累加的,例如当权限为:[-rwxrwx—] 分数则是:</p><p>owner = rwx = 4+2+1 = 7</p><p>group = rwx = 4+2+1 = 7</p><p>others= — = 0+0+0 = 0</p><p>chmod 770 filename</p><p>chmod 777 filename为赋予文件所有权限</p><h1 id="文件内容查看"><a href="#文件内容查看" class="headerlink" title="文件内容查看"></a>文件内容查看</h1><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">cat 由第一行开始显示文件内容</span><br><span class="line"></span><br><span class="line">tac 从最后一行开始显示,可以看出 tac 是 cat 的倒着写!</span><br><span class="line"></span><br><span class="line">nl 显示的时候,顺道输出行号!</span><br><span class="line"></span><br><span class="line">more 一页一页的显示文件内容</span><br><span class="line"></span><br><span class="line">less 与 more 类似,但是比 more 更好的是,他可以往前翻页!</span><br><span class="line"></span><br><span class="line">head 只看头几行</span><br><span class="line"></span><br><span class="line">tail 只看尾巴几行</span><br></pre></td></tr></table></figure><p><strong>more 一页一页翻动</strong></p><p>空白键 (space):代表向下翻一页;</p><p>Enter :代表向下翻『一行』;</p><p>/字串 :代表在这个显示的内容当中,向下搜寻『字串』这个关键字;</p><p>:f :立刻显示出档名以及目前显示的行数;</p><p>q :代表立刻离开 more ,不再显示该文件内容。</p><p><strong>less 一页一页翻动</strong></p><p>less运行时可以输入的命令有:</p><p>空白键 :向下翻动一页;</p><p>[pagedown]:向下翻动一页;</p><p>[pageup] :向上翻动一页;</p><p>/字串 :向下搜寻『字串』的功能;</p><p>?字串 :向上搜寻『字串』的功能;</p><p>n :重复前一个搜寻 (与 / 或 ? 有关!)</p><p>N :反向的重复前一个搜寻 (与 / 或 ? 有关!)</p><p>q :离开 less 这个程序;</p><p><strong>head 取出文件前面几行</strong></p><p>语法:</p><p>head [-n number] 文件</p><p>选项与参数:-n 后面接数字,代表显示几行的意思!</p><p>默认的情况中,显示前面 10 行!若要显示前 20 行,就得要这样:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@w etc]<span class="comment"># head -n 20 /etc/csh.login</span></span><br></pre></td></tr></table></figure><p><strong>tail 取出文件后面几行</strong></p><p>语法:</p><p>tail [-n number] 文件</p><p>选项与参数:</p><p>-n :后面接数字,代表显示几行的意思</p><p>默认的情况中,显示最后 10 行!若要显示最后 20 行,就得要这样:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@w etc]<span class="comment"># tail -n 20 /etc/csh.login</span></span><br></pre></td></tr></table></figure><h1 id="Vim编辑器"><a href="#Vim编辑器" class="headerlink" title="Vim编辑器"></a>Vim编辑器</h1><p>vim 键盘图:</p><p><img src="/2022/04/13/Linux%E5%AD%A6%E4%B9%A0/3.jpg" alt="image-20220703231236493"></p><p><strong>三种模式</strong></p><p>基本上 vi/vim 共分为三种模式,分别是命令模式(Command mode),输入模式(Insert mode)和底线命令模式(Last line mode)。这三种模式的作用分别是:</p><p><strong>命令模式:</strong></p><p>用户刚刚启动 vi/vim,便进入了命令模式。</p><p>此状态下敲击键盘动作会被Vim识别为命令,而非输入字符。比如我们此时按下i,并不会输入一个字符,i被当作了一个命令。</p><p>以下是常用的几个命令:</p><p>i 切换到输入模式,以输入字符。</p><p>x 删除当前光标所在处的字符。</p><p>: 切换到底线命令模式,以在最底一行输入命令。</p><p>若想要编辑文本:启动Vim,进入了命令模式,按下i,切换到输入模式。</p><p>命令模式只有一些最基本的命令,因此仍要依靠底线命令模式输入更多命令。</p><p><strong>输入模式:</strong></p><p>在命令模式下按下i就进入了输入模式。</p><p>在输入模式中,可以使用以下按键:</p><p>字符按键以及Shift组合,输入字符</p><p>ENTER,回车键,换行</p><p>BACK SPACE,退格键,删除光标前一个字符</p><p>DEL,删除键,删除光标后一个字符</p><p>方向键,在文本中移动光标</p><p>HOME/END,移动光标到行首/行尾</p><p>Page Up/Page Down,上/下翻页</p><p>Insert,切换光标为输入/替换模式,光标将变成竖线/下划线</p><p>ESC,退出输入模式,切换到命令模式</p><p><strong>底线命令模式</strong></p><p>在命令模式下按下:(英文冒号)就进入了底线命令模式。</p><p>底线命令模式可以输入单个或多个字符的命令,可用的命令非常多。</p><p>在底线命令模式中,基本的命令有(已经省略了冒号):</p><p>q 退出程序</p><p>w 保存文件</p><p>按ESC键可随时退出底线命令模式。</p><p>在一般模式中按下 :wq 储存后离开 vim!</p><h1 id="账号管理"><a href="#账号管理" class="headerlink" title="账号管理"></a>账号管理</h1><p>Linux系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统。</p><p>用户的账号一方面可以帮助系统管理员对使用系统的用户进行跟踪,并控制他们对系统资源的访问;另一方面也可以帮助用户组织文件,并为用户提供安全性保护。</p><p>每个用户账号都拥有一个唯一的用户名和各自的口令。</p><p>用户在登录时键入正确的用户名和口令后,就能够进入系统和自己的主目录。</p><p>实现用户账号的管理,要完成的工作主要有如下几个方面:</p><ul><li><p>用户账号的添加、删除与修改。</p></li><li><p>用户口令的管理。</p></li><li><p>用户组的管理。</p></li></ul><p><strong>添加账号 useradd</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">useradd 选项 用户名</span><br></pre></td></tr></table></figure><p>参数说明:</p><p>选项 :</p><p>-c comment 指定一段注释性描述。</p><p>-d 目录 指定用户主目录,如果此目录不存在,则同时使用-m选项,可以创建主目录。</p><p>-g 用户组 指定用户所属的用户组。</p><p>-G 用户组,用户组 指定用户所属的附加组。</p><p>-m 使用者目录如不存在则自动建立。</p><p>-s Shell文件 指定用户的登录Shell。</p><p>-u 用户号 指定用户的用户号,如果同时有-o选项,则可以重复使用其他用户的标识号。</p><p>用户名 :</p><p>指定新账号的登录名。</p><p>一般使用useradd -m 用户名</p><p><strong>切换用户</strong></p><p>1.切换用户的命令为:su username 【username为用户名】</p><p>2.从普通用户切换到root用户,还可以使用命令:sudo su</p><p>3.在终端输入exit或logout或使用快捷方式ctrl+d,可以退回到原来用户,其实ctrl+d也是执行的exit命令</p><p>4.在切换用户时,如果想在切换用户之后使用新用户的工作环境,可以在su和username之间加-,例如:【su - root】</p><p>$表示普通用户</p><p>“#”表示超级用户,也就是root用户</p><p><strong>删除帐号</strong></p><p>如果一个用户的账号不再使用,可以从系统中删除。</p><p>删除用户账号就是要将/etc/passwd等系统文件中的该用户记录删除,必要时还删除用户的主目录。</p><p>删除一个已有的用户账号使用userdel命令,其格式如下:</p><p>userdel 选项 用户名</p><p>常用的选项是 -r,它的作用是把用户的主目录一起删除。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@w home]<span class="comment"># userdel -r w</span></span><br></pre></td></tr></table></figure><p>此命令删除用户kuangshen在系统文件中(主要是/etc/passwd, /etc/shadow, /etc/group等)的记录,同时删除用户的主目录。</p><p><strong>修改帐号</strong></p><p>修改用户账号就是根据实际情况更改用户的有关属性,如用户号、主目录、用户组、登录Shell等。</p><p>修改已有用户的信息使用usermod命令,其格式如下:</p><p>usermod 选项 用户名</p><p>常用的选项包括-c, -d, -m, -g, -G, -s, -u以及-o等,这些选项的意义与useradd命令中的选项一样,可以为用户指定新的资源值。</p><p><strong>用户口令的管理</strong></p><p>用户管理的一项重要内容是用户口令的管理。用户账号刚创建时没有口令,但是被系统锁定,无法使用,必须为其指定口令后才可以使用,即使是指定空口令。</p><p>指定和修改用户口令的Shell命令是passwd。超级用户可以为自己和其他用户指定口令,普通用户只能用它修改自己的口令。</p><p>命令的格式为:</p><p>passwd 选项 用户名</p><p>可使用的选项:</p><p>-l 锁定口令,即禁用账号。</p><p>-u 口令解锁。</p><p>-d 使账号无口令。</p><p>-f 强迫用户下次登录时修改口令。</p><p>如果默认用户名,则修改当前用户的口令。</p><h1 id="用户组管理"><a href="#用户组管理" class="headerlink" title="用户组管理"></a>用户组管理</h1><p>每个用户都有一个用户组,系统可以对一个用户组中的所有用户进行集中管理。不同Linux 系统对用户组的规定有所不同,如Linux下的用户属于与它同名的用户组,这个用户组在创建用户时同时创建。</p><p>用户组的管理涉及用户组的添加、删除和修改。组的增加、删除和修改实际上就是对/etc/group文件的更新。</p><p><strong>增加一个新的用户组使用groupadd命令</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">groupadd 选项 用户组</span><br></pre></td></tr></table></figure><p>可以使用的选项有:</p><p>-g GID 指定新用户组的组标识号(GID)。</p><p>-o 一般与-g选项同时使用,表示新用户组的GID可以与系统已有用户组的GID相同。</p><p><strong>如果要删除一个已有的用户组,使用groupdel命令</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">groupdel 用户组</span><br></pre></td></tr></table></figure><p><strong>修改用户组的属性使用groupmod命令</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">groupmod 选项 用户组</span><br></pre></td></tr></table></figure><p>常用的选项有:</p><p>-g GID 为用户组指定新的组标识号。</p><p>-o 与-g选项同时使用,用户组的新GID可以与系统已有用户组的GID相同。</p><p>-n新用户组 将用户组的名字改为新名字</p><p><strong>切换组</strong></p><p>如果一个用户同时属于多个用户组,那么用户可以在用户组之间切换,以便具有其他用户组的权限。</p><p>用户可以在登录后,使用命令newgrp切换到其他用户组,这个命令的参数就是目的用户组。例如:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ newgrp root</span><br></pre></td></tr></table></figure><p>这条命令将当前用户切换到root用户组,前提条件是root用户组确实是该用户的主组或附加组。</p><p><strong>/etc/passwd</strong></p><p>完成用户管理的工作有许多种方法,但是每一种方法实际上都是对有关的系统文件进行修改。</p><p>与用户和用户组相关的信息都存放在一些系统文件中,这些文件包括/etc/passwd, /etc/shadow, /etc/group等。</p><p>下面分别介绍这些文件的内容。</p><p>/etc/passwd文件是用户管理工作涉及的最重要的一个文件。</p><p>Linux系统中的每个用户都在/etc/passwd文件中有一个对应的记录行,它记录了这个用户的一些基本属性。</p><p>这个文件对所有用户都是可读的。它的内容类似下面的例子:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"># <span class="built_in">cat</span> /etc/passwd</span><br><span class="line"></span><br><span class="line">root:x:0:0:Superuser:/:</span><br><span class="line">daemon:x:1:1:System daemons:/etc:</span><br><span class="line">bin:x:2:2:Owner of system commands:/bin:</span><br><span class="line">sys:x:3:3:Owner of system files:/usr/sys:</span><br><span class="line">adm:x:4:4:System accounting:/usr/adm:</span><br><span class="line">uucp:x:5:5:UUCP administrator:/usr/lib/uucp:</span><br><span class="line">auth:x:7:21:Authentication administrator:/tcb/files/auth:</span><br><span class="line">cron:x:9:16:Cron daemon:/usr/spool/cron:</span><br><span class="line">listen:x:37:4:Network daemon:/usr/net/nls:</span><br><span class="line">lp:x:71:18:Printer administrator:/usr/spool/lp:</span><br></pre></td></tr></table></figure><p>从上面的例子我们可以看到,/etc/passwd中一行记录对应着一个用户,每行记录又被冒号(:)分隔为7个字段,其格式和具体含义如下:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">用户名:口令:用户标识号:组标识号:注释性描述:主目录:登录Shell</span><br></pre></td></tr></table></figure><p>1)”用户名”是代表用户账号的字符串。</p><p>通常长度不超过8个字符,并且由大小写字母和/或数字组成。登录名中不能有冒号(:),因为冒号在这里是分隔符。</p><p>为了兼容起见,登录名中最好不要包含点字符(.),并且不使用连字符(-)和加号(+)打头。</p><p>2)“口令”一些系统中,存放着加密后的用户口令字。</p><p>虽然这个字段存放的只是用户口令的加密串,不是明文,但是由于/etc/passwd文件对所有用户都可读,所以这仍是一个安全隐患。因此,现在许多Linux 系统(如SVR4)都使用了shadow技术,把真正的加密后的用户口令字存放到/etc/shadow文件中,而在/etc/passwd文件的口令字段中只存放一个特殊的字符,例如“x”或者“*”。</p><p>3)“用户标识号”是一个整数,系统内部用它来标识用户。</p><p>一般情况下它与用户名是一一对应的。如果几个用户名对应的用户标识号是一样的,系统内部将把它们视为同一个用户,但是它们可以有不同的口令、不同的主目录以及不同的登录Shell等。</p><p>通常用户标识号的取值范围是0~65 535。0是超级用户root的标识号,1~99由系统保留,作为管理账号,普通用户的标识号从100开始。在Linux系统中,这个界限是500。</p><p>4)“组标识号”字段记录的是用户所属的用户组。</p><p>它对应着/etc/group文件中的一条记录。</p><p>5)“注释性描述”字段记录着用户的一些个人情况。</p><p>例如用户的真实姓名、电话、地址等,这个字段并没有什么实际的用途。在不同的Linux 系统中,这个字段的格式并没有统一。在许多Linux系统中,这个字段存放的是一段任意的注释性描述文字,用作finger命令的输出。</p><p>6)“主目录”,也就是用户的起始工作目录。</p><p>它是用户在登录到系统之后所处的目录。在大多数系统中,各用户的主目录都被组织在同一个特定的目录下,而用户主目录的名称就是该用户的登录名。各用户对自己的主目录有读、写、执行(搜索)权限,其他用户对此目录的访问权限则根据具体情况设置。</p><p>7)用户登录后,要启动一个进程,负责将用户的操作传给内核,这个进程是用户登录到系统后运行的命令解释器或某个特定的程序,即Shell。</p><p><strong>/etc/group</strong></p><p>用户组的所有信息都存放在/etc/group文件中。</p><p>将用户分组是Linux 系统中对用户进行管理及控制访问权限的一种手段。</p><p>每个用户都属于某个用户组;一个组中可以有多个用户,一个用户也可以属于不同的组。</p><p>当一个用户同时是多个组中的成员时,在/etc/passwd文件中记录的是用户所属的主组,也就是登录时所属的默认组,而其他组称为附加组。</p><p>用户要访问属于附加组的文件时,必须首先使用newgrp命令使自己成为所要访问的组中的成员。</p><p>用户组的所有信息都存放在/etc/group文件中。此文件的格式也类似于/etc/passwd文件,由冒号(:)隔开若干个字段,这些字段有:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">组名:口令:组标识号:组内用户列表</span><br></pre></td></tr></table></figure><ol><li><p>“组名”是用户组的名称,由字母或数字构成。与/etc/passwd中的登录名一样,组名不应重复。</p></li><li><p>“口令”字段存放的是用户组加密后的口令字。一般Linux 系统的用户组都没有口令,即这个字段一般为空,或者是*。</p></li><li><p>“组标识号”与用户标识号类似,也是一个整数,被系统内部用来标识组。</p></li><li><p>“组内用户列表”是属于这个组的所有用户的列表/b],不同用户之间用逗号(,)分隔。这个用户组可能是用户的主组,也可能是附加组。</p></li></ol><h1 id="磁盘管理"><a href="#磁盘管理" class="headerlink" title="磁盘管理"></a>磁盘管理</h1><p>Linux磁盘管理好坏直接关系到整个系统的性能问题。</p><p>Linux磁盘管理常用命令为 df、du。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">df</span> :列出文件系统的整体磁盘使用量</span><br><span class="line"><span class="built_in">du</span>:检查磁盘空间使用量</span><br></pre></td></tr></table></figure><p><strong>df</strong></p><p>df命令参数功能:检查文件系统的磁盘空间占用情况。可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息。</p><p>语法:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">df</span> [-ahikHTm] [目录或文件名]</span><br></pre></td></tr></table></figure><p>选项与参数:</p><p>-a :列出所有的文件系统,包括系统特有的 /proc 等文件系统;</p><p>-k :以 KBytes 的容量显示各文件系统;</p><p>-m :以 MBytes 的容量显示各文件系统;</p><p>-h :以人们较易阅读的 GBytes, MBytes, KBytes 等格式自行显示;</p><p>-H :以 M=1000K 取代 M=1024K 的进位方式;</p><p>-T :显示文件系统类型, 连同该 partition 的 filesystem 名称 (例如 ext3) 也列出;</p><p>-i :不用硬盘容量,而以 inode 的数量来显示</p><p><strong>du</strong></p><p>df命令参数功能:检查文件系统的磁盘空间占用情况。可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息。</p><p>语法:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">df</span> [-ahikHTm] [目录或文件名]</span><br></pre></td></tr></table></figure><p>选项与参数:</p><p>-a :列出所有的文件系统,包括系统特有的 /proc 等文件系统;</p><p>-k :以 KBytes 的容量显示各文件系统;</p><p>-m :以 MBytes 的容量显示各文件系统;</p><p>-h :以人们较易阅读的 GBytes, MBytes, KBytes 等格式自行显示;</p><p>-H :以 M=1000K 取代 M=1024K 的进位方式;</p><p>-T :显示文件系统类型, 连同该 partition 的 filesystem 名称 (例如 ext3) 也列出;</p><p>-i :不用硬盘容量,而以 inode 的数量来显示</p><p><strong>磁盘挂载与卸除</strong></p><p>根文件系统之外的其他文件要想能够被访问,都必须通过“关联”至根文件系统上的某个目录来实现,此关联操作即为“挂载”,此目录即为“挂载点”,解除此关联关系的过程称之为“卸载”</p><p>Linux 的磁盘挂载使用mount命令,卸载使用umount命令。</p><p>磁盘挂载语法:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mount [-t 文件系统] [-L Label名] [-o 额外选项] [-n] 装置文件名 挂载点</span><br></pre></td></tr></table></figure><p>磁盘卸载命令 umount 语法:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">umount [-fn] 装置文件名或挂载点</span><br></pre></td></tr></table></figure><p>选项与参数:</p><p>-f :强制卸除!可用在类似网络文件系统 (NFS) 无法读取到的情况下;</p><p>-n :不升级 /etc/mtab 情况下卸除。</p><h1 id="进程管理"><a href="#进程管理" class="headerlink" title="进程管理"></a>进程管理</h1><blockquote><p>什么是进程</p></blockquote><p>1、在Linux中,每一个程序都是有自己的一个进程,每一个进程都有一个id号!<br>2、每一个进程,都会有一个父进程!<br>3、进程可以有两种存在方式:前台!后台运行!<br>4、一般的话服务都是后台运行的,基本的程序都是前台运行的!</p><blockquote><p>命令</p></blockquote><p><strong>ps 查看当前系统中正在执行的各种进程的信息!</strong></p><ul><li>-a 显示当前终端运行的所有的进程信息-u以用户的信息显示进程</li><li>-×显示后台运行进程的参数!</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># ps -aux 查看所有的进程</span></span><br><span class="line">ps -aux|</span><br><span class="line"><span class="comment"># | 在Linux这个叫做管道符 A|B</span></span><br><span class="line"><span class="comment"># grep查找文件中符合条件的字符串!</span></span><br></pre></td></tr></table></figure><p>目前只需要记住一个命令即可 ps -xx|grep 进程名字!过滤进程信息!</p><p><strong>ps -ef : 可以查看到父进程的信息</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">ps -ef|grep mysq1 <span class="comment">#看父进程我们一般可以通过目录树结构来查看!</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#进程树!</span></span><br><span class="line">pstree -pu</span><br><span class="line"> -p 显示父<span class="built_in">id</span></span><br><span class="line"> -u 显示用户组</span><br></pre></td></tr></table></figure><p>结束进程∶杀掉进程,等价于window结束任务!</p><p>kill -9进程的id</p><p>但是啊,我们平时写的一个Java代码死循环了,可以选择结束进程!杀进程</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">kill</span> -9进程的<span class="built_in">id</span></span><br></pre></td></tr></table></figure><p>表示强制结束该进程!</p><h1 id="防火墙命令"><a href="#防火墙命令" class="headerlink" title="防火墙命令"></a>防火墙命令</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看firewall服务状态</span></span><br><span class="line">systemctl status firewalld</span><br><span class="line"></span><br><span class="line"><span class="comment"># 开启、重启、关闭、firewalld.service服务</span></span><br><span class="line"><span class="comment"># 开启</span></span><br><span class="line">service firewalld start</span><br><span class="line"><span class="comment"># 重启</span></span><br><span class="line">service firewalld restart</span><br><span class="line"><span class="comment"># 关闭</span></span><br><span class="line">service firewalld stop</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看防火墙规则</span></span><br><span class="line">firewall-cmd --list-all <span class="comment"># 查看全部信息</span></span><br><span class="line">firewall-cmd --list-ports <span class="comment"># 只看端口信息</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 开启端口</span></span><br><span class="line">开端口命令:firewall-cmd --zone=public --add-port=80/tcp --permanent</span><br><span class="line">重启防火墙:systemctl restart firewalld.service</span><br><span class="line"></span><br><span class="line">命令含义:</span><br><span class="line">--zone <span class="comment">#作用域</span></span><br><span class="line">--add-port=80/tcp <span class="comment">#添加端口,格式为:端口/通讯协议</span></span><br><span class="line">--permanent <span class="comment">#永久生效,没有此参数重启后失效</span></span><br></pre></td></tr></table></figure>]]></content>
<tags>
<tag> Linux </tag>
</tags>
</entry>
<entry>
<title>Hello World</title>
<link href="/2022/03/25/hello-world/"/>
<url>/2022/03/25/hello-world/</url>
<content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>]]></content>
</entry>
</search>