-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
407 lines (243 loc) · 629 KB
/
atom.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Joynoy's Blog</title>
<subtitle>Learn something</subtitle>
<link href="http://www.jonyonwzj.top/atom.xml" rel="self"/>
<link href="http://www.jonyonwzj.top/"/>
<updated>2021-06-13T10:12:12.236Z</updated>
<id>http://www.jonyonwzj.top/</id>
<author>
<name>Zhengjie Wu</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>SpringCloud</title>
<link href="http://www.jonyonwzj.top/2021/06/10/SpringCloud/"/>
<id>http://www.jonyonwzj.top/2021/06/10/SpringCloud/</id>
<published>2021-06-10T11:56:01.000Z</published>
<updated>2021-06-13T10:12:12.236Z</updated>
<content type="html"><![CDATA[<h1 id="为什么使用Spring-Cloud"><a href="#为什么使用Spring-Cloud" class="headerlink" title="为什么使用Spring Cloud"></a>为什么使用Spring Cloud</h1><p>一个项目中有很多业务,这个项目部署在一台服务器中</p><p>当访问的用户越来越多后,这台服务器支持的并发量到达了上限,为了解决这个问题,可以采用水平拆分的方式,在多个服务器中部署项目,并采用<strong>负载均衡</strong>的方式使几台服务器所占的资源均匀</p><p>这时有一个问题:<strong>在一个项目中有些业务的实际使用效率并不高,而有些业务的实际使用效率又很高,这时就会希望给使用效率高的业务多分配一些服务器资源</strong>。</p><p>为了达到这个目的,可以将原来的整体项目<strong>模块化</strong>,也就是说将不同的业务划分为一个单独的项目,再将划分的业务模块项目放入一个服务器</p><p>这样的架构就叫做<strong>微服务架构</strong></p><p>微服务的核心就是将传统的一站式应用,根据业务拆分成一个一个的服务,彻底的去耦合,每一个微服务提供单个业务功能的服务,一个服务做一件事,从技术角度看,就是一种小而独立的处理过程,类似进程的概念,能够自行单独启动或销毁,拥有自己独立的数据库。</p><a id="more"></a><h1 id="微服务与微服务架构"><a href="#微服务与微服务架构" class="headerlink" title="微服务与微服务架构"></a>微服务与微服务架构</h1><h2 id="微服务"><a href="#微服务" class="headerlink" title="微服务"></a>微服务</h2><p>强调的是服务的大小,关注的是某一个点,是具体解决某一个问题、提供落地对应服务的一个服务应用,狭义的看,可以看做是IDEA中的一个个微服务工程,或者Moudle</p><figure class="highlight plain"><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">IDEA工具中使用Maven开发的一个个独立的小Moudle,它具体是使用SpringBoot开发的一个小模块,专业的事交给专业的模块来做,一个模块就做一件事</span><br><span class="line">强调的是一个个个体,每个个体完成一个具体的任务或功能</span><br></pre></td></tr></table></figure><h2 id="微服务架构"><a href="#微服务架构" class="headerlink" title="微服务架构"></a>微服务架构</h2><p>微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、配合,为用户提供最终价值,每个服务运行在其独立的进程中,服务与服务间采用轻量级的通讯机制相互合作,每个服务都围绕着具体的业务进行构建,并且能够被独立的部署到生产环境中,另外,应尽量避免统一的,集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言,工具进行构建。</p><h2 id="微服务优缺点"><a href="#微服务优缺点" class="headerlink" title="微服务优缺点"></a>微服务优缺点</h2><p>优点</p><ul><li>单一职责原则;</li><li>每个服务足够内聚,足够小,代码容易理解,这样能聚焦一个指定的业务功能或业务需求;</li><li>开发简单,开发效率高,一个服务可能就是专一的只干一件事;</li><li>微服务能够被小团队单独开发,这个团队只需2-5个开发人员组成;</li><li>微服务是松耦合的,是有功能意义的服务,无论是在开发阶段或部署阶段都是独立的;</li><li>微服务能使用不同的语言开发;</li><li>易于和第三方集成,微服务允许容易且灵活的方式集成自动部署,通过持续集成工具,如jenkins,Hudson,bamboo;</li><li>微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果,无需通过合作才能体现价值;</li><li>微服务允许利用和融合最新技术;</li><li>微服务只是业务逻辑的代码,不会和HTML,CSS,或其他的界面混合;</li><li>每个微服务都有自己的存储能力,可以有自己的数据库,也可以有统一的数据库;</li></ul><p>缺点</p><ul><li>开发人员要处理分布式系统的复杂性;</li><li>多服务运维难度,随着服务的增加,运维的压力也在增大;</li><li>系统部署依赖问题;</li><li>服务间通信成本问题;</li><li>数据一致性问题;</li><li>系统集成测试问题;</li><li>性能和监控问题;</li></ul><h1 id="Spring-Cloud"><a href="#Spring-Cloud" class="headerlink" title="Spring Cloud"></a>Spring Cloud</h1><h2 id="微服务架构的4个核心问题"><a href="#微服务架构的4个核心问题" class="headerlink" title="微服务架构的4个核心问题"></a>微服务架构的4个核心问题</h2><ol><li>服务很多,客户端该如何去访问</li><li>服务很多,服务之间如何进行通信</li><li>服务很多,如何治理</li><li><strong>服务挂了怎么办</strong></li></ol><p>产生这四个问题的本质:<strong>网络是不可靠的</strong></p><h2 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h2><p><strong>Spring Cloud,是一个生态,它的出现正是为了解决微服务架构的4个问题,基于这四个问题开发的解决方案也叫Spring Cloud XXXX</strong></p><ul><li>Spring Cloud NetFlix(网飞) 一站式解决方案<ul><li>访问—>API网关,统一服务治理,zuul组件(网飞)</li><li>通信—>Feign(网飞通信组件)–基于HttpClient–基于Http的通信方式,同步并阻塞</li><li>治理–>服务注册与发现,Euraka组件</li><li>熔断–>熔断机制,Hystrix组件</li></ul></li><li>Apache Dubbo Zookeeper 半自动<ul><li>访问—>没有API,找第三方组件</li><li>通信—>Dubbo,一个高性能的基于java实现的RPC框架</li><li>治理–>Zookeeper,服务注册与发现</li><li>熔断—>没有,借助了Hystrix组件</li></ul></li><li>Spring Cloud Alibaba 一站式解决方案<ul><li>访问—>API网关,服务路由</li><li>通信—>HTTP,RPC框架,异步调用</li><li>治理–>服务注册与发现,高可用</li><li>熔断—>熔断机制,服务降级</li></ul></li></ul><h1 id="常见面试题"><a href="#常见面试题" class="headerlink" title="常见面试题"></a>常见面试题</h1><ol><li>什么是微服务</li><li>微服务之间是如何独立通讯的</li><li>SpringCloud和Dubbo有哪些区别</li><li>SpringBoot和SpringCloud,请你谈谈对他们的理解</li><li>什么是服务熔断?什么是服务降级</li><li>微服务的优缺点是分别是什么?说下你在项目开发中遇到的坑</li><li>你所知道的微服务技术栈有哪些,请列举一二</li><li>Eureka和zookeeper都可以提供服务注册和发现功能,请说说两个的区别</li></ol><h1 id="什么是微服务"><a href="#什么是微服务" class="headerlink" title="什么是微服务"></a>什么是微服务</h1><p><a href="https://www.cnblogs.com/liuning8023/p/4493156.html">https://www.cnblogs.com/liuning8023/p/4493156.html</a></p><h1 id="微服务技术栈"><a href="#微服务技术栈" class="headerlink" title="微服务技术栈"></a>微服务技术栈</h1><table><thead><tr><th>微服务条目</th><th>落地技术</th></tr></thead><tbody><tr><td>服务开发</td><td>SpringBoot、SpringMVC、Spring</td></tr><tr><td>服务配置与管理</td><td>NetFlix公司的Archaius、阿里的Diamond等</td></tr><tr><td>服务注册与发现</td><td>Eureka、Consul、Zookeeper</td></tr><tr><td>服务调用</td><td>RPC、gRPC、Rest</td></tr><tr><td>服务熔断器</td><td>Hystrix、Envoy等</td></tr><tr><td>负载均衡</td><td>Ribbon、Nginx</td></tr><tr><td>服务接口调用(客户端调用服务的简化工具)</td><td>Feign等</td></tr><tr><td>消息队列</td><td>Kafka、RabbitMQ、ActiveMQ</td></tr><tr><td>服务配置中心管理</td><td>SpringCloudConfig、Chef等</td></tr><tr><td>服务路由(API网关)</td><td>Zuul等</td></tr><tr><td>服务监控</td><td>Zabbix、Nagios、Metrics、Specatator</td></tr><tr><td>全链路追踪</td><td>Zipzin、Brave、Dapper等</td></tr><tr><td>服务部署</td><td>Docker、OpenStack、Kubernets等</td></tr><tr><td>数据流操作开发包</td><td>SpringCloud Stream(封装与Resdis、Rabbit、Kafka等发送接收消息)</td></tr><tr><td>事件消息总栈</td><td>SpringCloud Bus</td></tr></tbody></table><h1 id="SpringBoot和SpringCloud的关系"><a href="#SpringBoot和SpringCloud的关系" class="headerlink" title="SpringBoot和SpringCloud的关系"></a>SpringBoot和SpringCloud的关系</h1><ul><li>他们是一个渐进式的关系,SpringBoot用来构建微服务,SpringCloud用来协调微服务</li><li>SpringBoot专注于快速方便的开发单个个体微服务</li><li>SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,为各个微服务之间提供:配置管理,服务发现,断路器,路由,微代理,事件总栈,全局锁,决策竞选,分布式会话等等集成微服务</li><li>SpringBoot可以离开SpringCloud单独使用,开发项目,但是SpringCloud离不开SpringBoot,属于依赖关系</li><li>SpringBoot专注于快熟、方便的开发单个个体微服务、SpringCloud关注全局的服务治理框架</li></ul><h1 id="Dubbo和SpringCloud的技术选型"><a href="#Dubbo和SpringCloud的技术选型" class="headerlink" title="Dubbo和SpringCloud的技术选型"></a>Dubbo和SpringCloud的技术选型</h1><h2 id="1-分布式-服务治理Dubbo"><a href="#1-分布式-服务治理Dubbo" class="headerlink" title="1.分布式+服务治理Dubbo"></a>1.分布式+服务治理Dubbo</h2><p>目前成熟的互联网架构:应用服务化拆分+消息中间件</p><p><img src="/2021/06/10/SpringCloud/image-20210130125720457.png" alt="image-20210130125720457"></p><h1 id="建议参考文档"><a href="#建议参考文档" class="headerlink" title="建议参考文档"></a>建议参考文档</h1><ul><li>SpringCloud Netflix 中文文档:<a href="https://springcloud.cc/spring-cloud-netflix.html">https://springcloud.cc/spring-cloud-netflix.html</a></li><li>SpringCloud 中文API文档(官方文档翻译版):<a href="https://springcloud.cc/spring-cloud-dalston.html">https://springcloud.cc/spring-cloud-dalston.html</a></li><li>SpringCloud中国社区:<a href="http://springcloud.cn/">http://springcloud.cn/</a></li><li>SpringCloud中文网:<a href="https://springcloud.cc/">https://springcloud.cc</a></li></ul><figure class="highlight"><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"><!-- SpringCloud依赖--></span><br><span class="line"> <dependencies></span><br><span class="line"> <dependency></span><br><span class="line"> <groupId>org.springframework.cloud</groupId></span><br><span class="line"> <artifactId>spring-cloud-dependencies</artifactId></span><br><span class="line"> <version>Hoxton.SR8</version></span><br><span class="line"> <type>pom</type></span><br><span class="line"> <scope>import</scope></span><br><span class="line"> </dependency></span><br><span class="line"> <!-- SpringBoot依赖--></span><br><span class="line"> <dependency></span><br><span class="line"> <groupId>org.springframework.boot</groupId></span><br><span class="line"> <artifactId>spring-boot-dependencies</artifactId></span><br><span class="line"> <version>2.3.3.RELEASE</version></span><br><span class="line"> </dependency></span><br></pre></td></tr></table></figure><h1 id="Eureka服务注册与发现"><a href="#Eureka服务注册与发现" class="headerlink" title="Eureka服务注册与发现"></a>Eureka服务注册与发现</h1><h2 id="什么是Eureka"><a href="#什么是Eureka" class="headerlink" title="什么是Eureka"></a>什么是Eureka</h2><p>Eureka是Netflix的有个子模块,也是核心模块之一。Eureka是基于REST的服务,用于定位服务,以实现云端中间件层服务发现和故障转移,服务注册与发现对于微服务来说是非常重要的,有了服务注册与发现,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于Dubbo的注册中心,比如Zookeeper.</p><h2 id="Eureka原理"><a href="#Eureka原理" class="headerlink" title="Eureka原理"></a>Eureka原理</h2><ul><li><p>Springcloud 封装了Netflix公司开发的Eureka模块来实现服务注册与发现 (对比Zookeeper).</p></li><li><p>Eureka采用了C-S的架构设计,EurekaServer作为服务注册功能的服务器,他是服务注册中心.</p></li><li><p>而系统中的其他微服务,使用Eureka的客户端连接到EurekaServer并维持心跳连接。这样系统的维护人员就可以通过EurekaServer来监控系统中各个微服务是否正常运行,Springcloud 的一些其他模块 (比如Zuul) 就可以通过EurekaServer来发现系统中的其他微服务,并执行相关的逻辑.<br><img src="/2021/06/10/SpringCloud/image-20210609131509169.png" alt="image-20210609131509169"></p></li><li><p>Eureka 包含两个组件:Eureka Server 和 Eureka Client.</p></li><li><p>Eureka Server 提供服务注册,各个节点启动后,会在EurekaServer中进行注册,这样Eureka Server中的服务注册表中将会储存所有课用服务节点的信息,服务节点的信息可以在界面中直观的看到.</p></li><li><p>Eureka Client 是一个Java客户端,用于简化EurekaServer的交互,客户端同时也具备一个内置的,使用轮询负载算法的负载均衡器。在应用启动后,将会向EurekaServer发送心跳 (默认周期为30秒) 。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除掉 (默认周期为90s).</p></li></ul><p><strong>三大角色</strong></p><ul><li>Eureka Server:提供服务的注册与发现</li><li>Service Provider:服务生产方,将自身服务注册到Eureka中,从而使服务消费方能狗找到</li><li>Service Consumer:服务消费方,从Eureka中获取注册服务列表,从而找到消费服务</li></ul><figure class="highlight yml"><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="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8002</span></span><br><span class="line"><span class="comment">#Eureka配置</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="attr">hostname:</span> <span class="string">localhost</span> <span class="comment">#Eureka服务端的实例名称</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">false</span> <span class="comment">#表示是否向Eureka注册中心注册自己</span></span><br><span class="line"> <span class="attr">fetch-registry:</span> <span class="literal">false</span> <span class="comment">#如果为false则表示自己为注册中心</span></span><br><span class="line"> <span class="attr">service-url:</span> <span class="comment">#监控页面</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">"https://${eureka.instance.hostname}:${server.port}/eureka/"</span></span><br></pre></td></tr></table></figure><h2 id="依赖问题"><a href="#依赖问题" class="headerlink" title="依赖问题"></a>依赖问题</h2><p>Q:启动eureka-server时报错<strong>Error starting Tomcat context</strong></p><p>A:需要去父工程的pom里,把cloud和boot的配置里的scope全改成<scope>import</scope>,系统会自动帮我们选择版本兼容</p><figure class="highlight xml"><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"><span class="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-dependencies<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>Hoxton.SR8<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">type</span>></span>pom<span class="tag"></<span class="name">type</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>import<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="comment"><!-- SpringBoot依赖--></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-dependencies<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.3.3.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">type</span>></span>pom<span class="tag"></<span class="name">type</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>import<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure><h2 id="Eureka自我保护机制"><a href="#Eureka自我保护机制" class="headerlink" title="Eureka自我保护机制"></a>Eureka自我保护机制</h2><p><img src="/2021/06/10/SpringCloud/image-20210609155847649.png" alt="image-20210609155847649"></p><p><strong>某时刻某一个微服务不可用,eureka不会立即清理,依旧会对该微服务的信息进行保存!</strong></p><ul><li>默认情况下,当eureka server在一定时间内没有收到实例的心跳,便会把该实例从注册表中删除(默认是90秒),但是,如果短时间内丢失大量的实例心跳,便会触发eureka server的自我保护机制,比如在开发测试时,需要频繁地重启微服务实例,但是我们很少会把eureka server一起重启(因为在开发过程中不会修改eureka注册中心),当一分钟内收到的心跳数大量减少时,会触发该保护机制。可以在eureka管理界面看到Renews threshold和Renews(last min),当后者(最后一分钟收到的心跳数)小于前者(心跳阈值)的时候,触发保护机制,会出现红色的警告:EMERGENCY!EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT.RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEGING EXPIRED JUST TO BE SAFE.从警告中可以看到,eureka认为虽然收不到实例的心跳,但它认为实例还是健康的,eureka会保护这些实例,不会把它们从注册表中删掉。</li><li>该保护机制的目的是避免网络连接故障,在发生网络故障时,微服务和注册中心之间无法正常通信,但服务本身是健康的,不应该注销该服务,如果eureka因网络故障而把微服务误删了,那即使网络恢复了,该微服务也不会重新注册到eureka server了,因为只有在微服务启动的时候才会发起注册请求,后面只会发送心跳和服务列表请求,这样的话,该实例虽然是运行着,但永远不会被其它服务所感知。所以,eureka server在短时间内丢失过多的客户端心跳时,会进入自我保护模式,该模式下,eureka会保护注册表中的信息,不在注销任何微服务,当网络故障恢复后,eureka会自动退出保护模式。自我保护模式可以让集群更加健壮。</li><li>但是我们在开发测试阶段,需要频繁地重启发布,如果触发了保护机制,则旧的服务实例没有被删除,这时请求有可能跑到旧的实例中,而该实例已经关闭了,这就导致请求错误,影响开发测试。所以,在开发测试阶段,我们可以把自我保护模式关闭,只需在eureka server配置文件中加上如下配置即可:eureka.server.enable-self-preservation=false【不推荐关闭自我保护机制】</li></ul><h2 id="Eureka集群配置"><a href="#Eureka集群配置" class="headerlink" title="Eureka集群配置"></a>Eureka集群配置</h2><p>新建SpringCloud-eureka-server01和SpringCloud-eureka-server02模块</p><p>server-server01-server02为一个集群</p><p>三个模块导入相同的pom.xml依赖</p><p>配置application.yml,集群之间相互关联</p><p>server</p><figure class="highlight yml"><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="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8082</span></span><br><span class="line"><span class="comment">#Eureka配置</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="attr">hostname:</span> <span class="string">eureka</span> <span class="comment">#Eureka服务端的实例名称</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">false</span> <span class="comment">#表示是否向Eureka注册中心注册自己</span></span><br><span class="line"> <span class="attr">fetch-registry:</span> <span class="literal">false</span> <span class="comment">#如果为false则表示自己为注册中心</span></span><br><span class="line"> <span class="attr">service-url:</span> <span class="comment">#监控页面</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka01:8083/eureka/,http://eureka02:8084/eureka/</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>server01</p><figure class="highlight yml"><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="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8083</span></span><br><span class="line"><span class="comment">#Eureka配置</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="attr">hostname:</span> <span class="string">eureka01</span> <span class="comment">#Eureka服务端的实例名称</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">false</span> <span class="comment">#表示是否向Eureka注册中心注册自己</span></span><br><span class="line"> <span class="attr">fetch-registry:</span> <span class="literal">false</span> <span class="comment">#如果为false则表示自己为注册中心</span></span><br><span class="line"> <span class="attr">service-url:</span> <span class="comment">#监控页面</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka:8082/eureka/,http://eureka02:8084/eureka/</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>server02</p><figure class="highlight yml"><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="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8084</span></span><br><span class="line"><span class="comment">#Eureka配置</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="attr">hostname:</span> <span class="string">eureka02</span> <span class="comment">#Eureka服务端的实例名称</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">false</span> <span class="comment">#表示是否向Eureka注册中心注册自己</span></span><br><span class="line"> <span class="attr">fetch-registry:</span> <span class="literal">false</span> <span class="comment">#如果为false则表示自己为注册中心</span></span><br><span class="line"> <span class="attr">service-url:</span> <span class="comment">#监控页面</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka01:8083/eureka/,http://eureka:8082/eureka/</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>同时需修改本机hosts</p><p><img src="/2021/06/10/SpringCloud/image-20210610130644929.png" alt="image-20210610130644929"></p><p>最后修改SpringCloud-provide-dept的<strong>Eureka配置:配置服务注册中心地址</strong></p><figure class="highlight yml"><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="attr">eureka:</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka01:8083/eureka/,http://eureka02:8084/eureka/,http://eureka:8082/eureka/</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="attr">instance-id:</span> <span class="string">springcloud-provider</span></span><br></pre></td></tr></table></figure><p>这样集群就搭建好了,可以把一个项目挂载到三个服务器上</p><p><img src="/2021/06/10/SpringCloud/image-20210610130844099.png" alt="image-20210610130844099"></p><h1 id="eureka和zookeeper"><a href="#eureka和zookeeper" class="headerlink" title="eureka和zookeeper"></a>eureka和zookeeper</h1><ol><li><strong>回顾CAP原则</strong><br>RDBMS (MySQL\Oracle\sqlServer) ===> ACID</li></ol><p>NoSQL (Redis\MongoDB) ===> CAP</p><ol start="2"><li><strong>ACID是什么?</strong><br>A (Atomicity) 原子性<br>C (Consistency) 一致性<br>I (Isolation) 隔离性<br>D (Durability) 持久性</li><li><strong>CAP是什么?</strong><br>C (Consistency) 强一致性<br>A (Availability) 可用性<br>P (Partition tolerance) 分区容错性<br>CAP的三进二:CA、AP、CP</li><li><strong>CAP理论的核心</strong><br>一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求<br>根据CAP原理,将NoSQL数据库分成了满足CA原则,满足CP原则和满足AP原则三大类<br>CA:单点集群,满足一致性,可用性的系统,通常可扩展性较差<br>CP:满足一致性,分区容错的系统,通常性能不是特别高<br>AP:满足可用性,分区容错的系统,通常可能对一致性要求低一些</li><li><strong>作为分布式服务注册中心,Eureka比Zookeeper好在哪里?</strong><br>著名的CAP理论指出,一个分布式系统不可能同时满足C (一致性) 、A (可用性) 、P (容错性),由于分区容错性P再分布式系统中是必须要保证的,因此我们只能再A和C之间进行权衡。</li></ol><p>Zookeeper 保证的是 CP —> 满足一致性,分区容错的系统,通常性能不是特别高<br>Eureka 保证的是 AP —> 满足可用性,分区容错的系统,通常可能对一致性要求低一些<br><strong>Zookeeper保证的是CP</strong></p><p> 当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接收服务直接down掉不可用。也就是说,<strong>服务注册功能对可用性的要求要高于一致性</strong>。但zookeeper会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30-120s,且选举期间整个zookeeper集群是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因为网络问题使得zookeeper集群失去master节点是较大概率发生的事件,虽然服务最终能够恢复,但是,漫长的选举时间导致注册长期不可用,是不可容忍的。</p><p><strong>Eureka保证的是AP</strong></p><p> Eureka看明白了这一点,因此在设计时就优先保证可用性。<strong>Eureka各个节点都是平等的</strong>,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册时,如果发现连接失败,则会自动切换至其他节点,只要有一台Eureka还在,就能保住注册服务的可用性,只不过查到的信息可能不是最新的,除此之外,Eureka还有之中自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:</p><ul><li>Eureka不在从注册列表中移除因为长时间没收到心跳而应该过期的服务</li><li>Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上 (即保证当前节点依然可用)</li><li>当网络稳定时,当前实例新的注册信息会被同步到其他节点中</li></ul><p><strong>因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪</strong></p><h1 id="Ribbon负载均衡-基于客户端"><a href="#Ribbon负载均衡-基于客户端" class="headerlink" title="Ribbon负载均衡(基于客户端)"></a>Ribbon负载均衡(基于客户端)</h1><h2 id="Ribbon是什么"><a href="#Ribbon是什么" class="headerlink" title="Ribbon是什么"></a>Ribbon是什么</h2><ul><li>Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具。</li><li>简单的说,Ribbon 是 Netflix 发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将 Netflix 的中间层服务连接在一起。Ribbon 的客户端组件提供一系列完整的配置项,如:连接超时、重试等。简单的说,就是在配置文件中列出 LoadBalancer (简称LB:负载均衡) 后面所有的及其,Ribbon 会自动的帮助你基于某种规则 (如简单轮询,随机连接等等) 去连接这些机器。我们也容易使用 Ribbon 实现自定义的负载均衡算法!</li></ul><p><img src="/2021/06/10/SpringCloud/image-20210610142531348.png" alt="image-20210610142531348"></p><ul><li>LB,即负载均衡 (LoadBalancer) ,在微服务或分布式集群中经常用的一种应用。</li><li>负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA (高用)。</li><li>常见的负载均衡软件有 Nginx、Lvs 等等。</li><li>Dubbo、SpringCloud 中均给我们提供了负载均衡,SpringCloud 的负载均衡算法可以自定义。</li><li>负载均衡简单分类:<ul><li>集中式LB<ul><li>即在服务的提供方和消费方之间使用独立的LB设施,如Nginx(反向代理服务器),由该设施负责把访问请求通过某种策略转发至服务的提供方!</li></ul></li><li>进程式 LB<ul><li>将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。<br>Ribbon 就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址!</li></ul></li></ul></li></ul><h2 id="集成Ribbon"><a href="#集成Ribbon" class="headerlink" title="集成Ribbon"></a>集成Ribbon</h2><p>消费者consumer添加添加Ribbon和Eureka依赖</p><figure class="highlight xml"><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="comment"><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-ribbon --></span></span><br><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-ribbon<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.2.5.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"><span class="comment"><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client --></span></span><br><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-eureka-client<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.2.5.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure><p>并配置application.yml</p><figure class="highlight yml"><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="attr">eureka:</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">false</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka01:8083/eureka/,http://eureka02:8084/eureka/,http://eureka:8082/eureka/</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>主启动类加上@EnableEurekaClient注解,开启Eureka</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//Ribbon 和 Eureka 整合以后,客户端可以直接调用,不用关心IP地址和端口号</span></span><br><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableEurekaClient</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeptConsuner</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(DeptConsuner.class,args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>自定义Spring配置类:ConfigBean.java 配置负载均衡实现RestTemplate</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConfigBean</span> </span>{</span><br><span class="line"> <span class="comment">//配置负载均衡实现RestTemplate</span></span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="meta">@LoadBalanced</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> RestTemplate <span class="title">getRestTemplate</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> RestTemplate();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>修改conroller中的REST_URL_PRE</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="comment">//private static final String REST_URL_PRE="http://localhost:8081";</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String REST_URL_PRE=<span class="string">"http://SPRINGCLOUD-PROVIDER-DEPT"</span>;</span><br></pre></td></tr></table></figure><p>启动eureka集群和服务提供者后,客户端可以直接从<a href="http://localhost:8080/consumer/dept/get">localhost:8080/consumer/dept/get</a>调用服务</p><p><img src="/2021/06/10/SpringCloud/image-20210610143947881.png" alt="image-20210610143947881"></p><h2 id="使用Ribbon实现负载均衡"><a href="#使用Ribbon实现负载均衡" class="headerlink" title="使用Ribbon实现负载均衡"></a>使用Ribbon实现负载均衡</h2><p>流程</p><p><img src="/2021/06/10/SpringCloud/image-20210610145455691.png" alt="image-20210610145455691"></p><p>参照原数据库SpringCloud新建两个数据库SpringCloud01,SpringCloud02; </p><p>参照DeptProvider新建两个服务提供者模块DeptProvider01,DeptProvider02;</p><p>新建的两个服务提供者除了连接不同的数据库,其它配置不变.</p><p>启动所有服务,访问<a href="http://eureka:8082/">Eureka</a>,获得服务列表</p><p><img src="/2021/06/10/SpringCloud/Snipaste_2021-06-10_15-26-44.png" alt="Snipaste_2021-06-10_15-26-44"></p><p>测试访问<a href="http://localhost:8080/consumer/dept/get">localhost:8080/consumer/dept/get</a></p><p><img src="/2021/06/10/SpringCloud/image-20210610153200618.png" alt="image-20210610153200618"></p><p>第一次查询的是数据库springcloud</p><p><strong>刷新</strong></p><p><img src="/2021/06/10/SpringCloud/image-20210610153309804.png" alt="image-20210610153309804"></p><p>这一次查询的是数据库springcloud01</p><p><strong>再一次刷新</strong></p><p><img src="/2021/06/10/SpringCloud/image-20210610153232950.png" alt="image-20210610153232950"></p><p>这一次查询的是数据库springcloud02</p><p>以上这种每次访问localhost:8080/consumer/dept/get<strong>顺序访问集群中某个服务提供者,这种情况叫做轮询</strong>,轮询算法在SpringCloud中可以自定义。</p><h2 id="自定义规则"><a href="#自定义规则" class="headerlink" title="自定义规则"></a>自定义规则</h2><ul><li>IRule</li><li>RoundRobinRule 轮询策略</li><li>RandomRule 随机策略</li><li>AvailabilityFilteringRule : 会先过滤掉,跳闸,访问故障的服务,对剩下的进行轮询</li><li>RetryRule : 会先按照轮询获取服务~,如果服务获取失败,则会在指定的时间内进行,重试</li></ul><p>在myRule包下自定义一个配置类MyRule.java,注意:<strong>该包不要和主启动类所在的包同级,要跟启动类所在包同级</strong></p><p><img src="/2021/06/10/SpringCloud/image-20210610163907341.png" alt="image-20210610163907341"></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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyRule</span> </span>{</span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> IRule <span class="title">myRule</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> RandomRule();<span class="comment">//默认是轮询RandomRule,现在为随机策略</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>主启动类开启负载均衡并指定自定义的MyRule配置类</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableEurekaClient</span></span><br><span class="line"><span class="meta">@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRule.class)</span><span class="comment">//开启负载均衡,并指定自定义的规则</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeptConsuner</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(DeptConsuner.class,args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="Feign负载均衡-基于服务端"><a href="#Feign负载均衡-基于服务端" class="headerlink" title="Feign负载均衡(基于服务端)"></a>Feign负载均衡(基于服务端)</h1><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>Feign是声明式Web Service客户端,它让微服务之间的调用变得更简单,<strong>类似controller调用service</strong>。SpringCloud集成了Ribbon和Eureka,可以使用Feigin提供负载均衡的http客户端,<strong>只需要创建一个接口,然后添加注解即可</strong></p><p>调用微服务访问两种方法</p><ol><li>微服务名字 【ribbon】</li><li>接口和注解 【feign】</li></ol><h2 id="Feign能干什么?"><a href="#Feign能干什么?" class="headerlink" title="Feign能干什么?"></a>Feign能干什么?</h2><ul><li>Feign旨在使编写Java Http客户端变得更容易</li><li>前面在使用Ribbon + RestTemplate时,利用RestTemplate对Http请求的封装处理,形成了一套模板化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一个客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步的封装,由他来帮助我们定义和实现依赖服务接口的定义,在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置它 (类似以前Dao接口上标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解),即可完成对服务提供方的接口绑定,简化了使用Spring Cloud Ribbon 时,自动封装服务调用客户端的开发量。</li></ul><h2 id="Feign默认集成了Ribbon"><a href="#Feign默认集成了Ribbon" class="headerlink" title="Feign默认集成了Ribbon"></a>Feign默认集成了Ribbon</h2><p>利用Ribbon维护了MicroServiceCloud-Dept的服务列表信息,并且通过轮询实现了客户端的负载均衡,而与Ribbon不同的是,通过Feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用。</p><h2 id="使用Feign"><a href="#使用Feign" class="headerlink" title="使用Feign"></a>使用Feign</h2><ol><li><p>参照SpringCloud-consumer-dept创建SpringCloud-consumer-dept-feign模块</p></li><li><p>在模块SpringCloud-api和SpringCloud-consumer-dept-feign中添加pom.xml依赖</p><figure class="highlight xml"><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="comment"><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign --></span></span><br><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-openfeign<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.2.5.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure></li><li><p>在SpringCloud-api新建service包,创建接口DeptClientService</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="meta">@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">DeptClientService</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping("/dept/find/{id}")</span></span><br><span class="line"> <span class="function">Dept <span class="title">findById</span><span class="params">(<span class="meta">@PathVariable("id")</span> Long id)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping("/dept/find")</span></span><br><span class="line"> <span class="function">List<Dept> <span class="title">findAll</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@PostMapping("/dept/add")</span></span><br><span class="line"> <span class="function">Boolean <span class="title">addDept</span><span class="params">(Dept dept)</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>改造controller</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeptConsumerController</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Autowired</span></span><br><span class="line"> <span class="keyword">private</span> DeptClientService service;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@RequestMapping("/consumer/dept/get/{id}")</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Dept <span class="title">get</span><span class="params">(<span class="meta">@PathVariable("id")</span> Long id)</span></span>{</span><br><span class="line"> <span class="keyword">return</span> service.findById(id);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@RequestMapping("/consumer/dept/get")</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> List<Dept> <span class="title">getAll</span><span class="params">()</span></span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> service.findAll();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@RequestMapping("/consumer/dept/add")</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Boolean <span class="title">add</span><span class="params">(Dept dept)</span></span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> service.addDept(dept);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>在DeptConsumerFeign主配置类上加上注解</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableEurekaClient</span></span><br><span class="line"><span class="comment">// feign客户端注解,并指定要扫描的包以及配置接口DeptClientService</span></span><br><span class="line"><span class="meta">@EnableFeignClients(basePackages = {"com.jonyon.SpringCloud"})</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeptConsumerFeign</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(DeptConsumerFeign.class,args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ol><p>启动eureka集群,启动服务提供者,启动Feign服务消费者,访问Feign中定义的接口地址</p><p><img src="/2021/06/10/SpringCloud/image-20210610180023952.png" alt="image-20210610180023952"></p><h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2><p>Q:测试过程中遇到了一个问题,就是在访问<a href="http://localhost:8087/feign/dept/get">localhost:8087/feign/dept/get</a>时无法访问页面,错误码显示为404</p><p>A:SpringCloud-api中service的请求接口地址与服务提供者的请求地址不一样,请求需保持一致才可以使feign中定义的请求地址成功访问.</p><h1 id="Hystrix"><a href="#Hystrix" class="headerlink" title="Hystrix"></a>Hystrix</h1><p>分布式系统面临的问题:</p><p><strong>复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免失败。</strong></p><h2 id="服务雪崩"><a href="#服务雪崩" class="headerlink" title="服务雪崩"></a>服务雪崩</h2><p>多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的“扇出”,如果扇出的链路上<strong>某个微服务的调用响应时间过长,或者不可用</strong>,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”。</p><p>对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几十秒内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障,这些都表示需要对故障和延迟进行隔离和管理,以达到单个依赖关系的失败而不影响整个应用程序或系统运行。</p><h2 id="什么是Hystrix"><a href="#什么是Hystrix" class="headerlink" title="什么是Hystrix"></a>什么是Hystrix</h2><p>Hystrix是一个应用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等,Hystrix 能够保证在一个依赖出问题的情况下,不会导致整个体系服务失败,避免级联故障,以提高分布式系统的弹性。</p><p> “断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控 (类似熔断保险丝) ,向调用方返回一个服务预期的,可处理的备选响应 (FallBack) ,而不是长时间的等待或者抛出调用方法无法处理的异常,这样就可以保证了服务调用方的线程不会被长时间,不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。</p><h2 id="Hystrix能干什么"><a href="#Hystrix能干什么" class="headerlink" title="Hystrix能干什么"></a>Hystrix能干什么</h2><ul><li>服务降级</li><li>服务熔断</li><li>服务限流</li><li>接近实时的监控</li></ul><p><strong>官网资料</strong>:<a href="https://github.com/Netflix/Hystrix/wiki">https://github.com/Netflix/Hystrix/wiki</a></p><p>当一切正常时,请求流如下所示:</p><p><img src="/2021/06/10/SpringCloud/image-20210611131007046.png" alt="image-20210611131007046"></p><p>当许多后端系统中有一个潜在阻塞服务时,它可以阻止整个用户请求:</p><p><img src="/2021/06/10/SpringCloud/image-20210611131055793.png" alt="image-20210611131055793"></p><p>随着大容量通信量的增加,单个后端依赖项的潜在性会导致所有服务器上的所有资源在几秒钟内饱和。</p><p>应用程序中通过网络或客户端库可能导致网络请求的每个点都是潜在故障的来源。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,从而备份队列、线程和其他系统资源,从而导致更多跨系统的级联故障。</p><p><img src="/2021/06/10/SpringCloud/image-20210611131204655.png" alt="image-20210611131204655"></p><p>当使用Hystrix包装每个基础依赖项时,上面的图表中所示的体系结构会发生类似于以下关系图的变化。每个依赖项是相互隔离的,限制在延迟发生时它可以填充的资源中,并包含在回退逻辑中,该逻辑决定在依赖项中发生任何类型的故障时要做出什么样的响应:</p><p><img src="/2021/06/10/SpringCloud/image-20210611131329788.png" alt="image-20210611131329788"></p><h2 id="服务熔断"><a href="#服务熔断" class="headerlink" title="服务熔断"></a>服务熔断</h2><p>什么是服务熔断?</p><p>当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阀值缺省是5秒内20次调用失败,就会启动熔断机制。熔断机制的注解是:@HystrixCommand。</p><p>服务熔断解决如下问题:</p><ul><li>当所依赖的对象不稳定时,能够起到快速失败的目的;</li><li>快速失败后,能够根据一定的算法动态试探所依赖对象是否恢复。</li></ul><h3 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h3><p>参照SpringCloud-provider-dept创建一个内容相同的模块SpringCloud-provider-dept-hystrix</p><p>导入依赖</p><figure class="highlight xml"><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="comment"><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix --></span></span><br><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-hystrix<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.2.5.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure><p>修改controller</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeptController</span> </span>{</span><br><span class="line"> <span class="meta">@Autowired</span></span><br><span class="line"> DeptService deptService;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@HystrixCommand(fallbackMethod = "hystrixGet")</span></span><br><span class="line"> <span class="meta">@RequestMapping("/dept/find/{id}")</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Dept <span class="title">get</span><span class="params">(<span class="meta">@PathVariable("id")</span> Long id)</span></span>{</span><br><span class="line"> Dept dept = deptService.findById(id);</span><br><span class="line"> <span class="keyword">if</span> (dept==<span class="keyword">null</span>){</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">"此id=>"</span>+id+<span class="string">",不存在"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> dept;</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="comment"> * 根据id查询备选方案(熔断)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Dept <span class="title">hystrixGet</span><span class="params">(<span class="meta">@PathVariable("id")</span> Long id)</span></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Dept(id,<span class="string">"没有该姓名"</span>,<span class="string">"没有该数据库"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>为主启动类添加对熔断的支持注解@EnableCircuitBreaker</strong></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></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableEurekaClient</span></span><br><span class="line"><span class="meta">@EnableCircuitBreaker</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeptProviderHystrix</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(DeptProviderHystrix.class,args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>测试:</strong></p><p>启动eureka集群,并启动适用熔断的服务提供者与feign消费者</p><p><strong>访问存在的id时数据如下:</strong></p><p><img src="/2021/06/10/SpringCloud/image-20210611143505101.png" alt="image-20210611143505101"></p><p><strong>访问不存在的id时数据如下:</strong></p><p><img src="/2021/06/10/SpringCloud/image-20210611143542292.png" alt="image-20210611143542292"></p><p><strong>而使用不适用熔断的服务提供者,会出现以下状况:</strong></p><p><img src="/2021/06/10/SpringCloud/image-20210611143715669.png" alt="image-20210611143715669"></p><p><strong>因此,为了避免因某个微服务后台出现异常或错误而导致整个应用或网页报错,使用熔断是必要的</strong></p><h2 id="服务降级"><a href="#服务降级" class="headerlink" title="服务降级"></a>服务降级</h2><p>什么是服务降级?</p><p>服务降级是指 当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理,或换种简单的方式处理,从而释放服务器资源以保证核心业务正常运作或高效运作。说白了,就是尽可能的把系统资源让给优先级高的服务。</p><p>资源有限,而请求是无限的。如果在并发高峰期,不做服务降级处理,一方面肯定会影响整体服务的性能,严重的话可能会导致宕机某些重要的服务不可用。所以,一般在高峰期,为了保证核心功能服务的可用性,都要对某些服务降级处理。比如当双11活动时,把交易无关的服务统统降级,如查看蚂蚁深林,查看历史订单等等。</p><p>服务降级主要用于什么场景呢?当整个微服务架构整体的负载超出了预设的上限阈值或即将到来的流量预计将会超过预设的阈值时,为了保证重要或基本的服务能正常运行,可以将一些 不重要 或 不紧急 的服务或任务进行服务的延迟使用或暂停使用。</p><p><strong>当某一时间内服务A的访问量暴增,而B和C的访问量较少,为了缓解A服务的压力,这时候需要B和C暂时关闭一些服务功能,去承担A的部分服务,从而为A分担压力,叫做服务降级</strong>。</p><p>服务降级需要考虑的问题</p><ul><li>哪些服务是核心服务,哪些服务是非核心服务</li><li>哪些服务可以支持降级,那些服务不能支持降级,降级策略是什么</li><li>除服务降级之外是否存在更复杂的业务放通场景,策略是什么</li></ul><p>自动降级分类</p><ul><li>超时降级:主要配置好超时时间和超时重试次数和机制,并使用异步机制探测回复情况</li><li>失败次数降级:主要是一些不稳定的api,当失败调用次数达到一定阀值自动降级,同样要使用异步机制探测回复情况</li><li>故障降级:比如要调用的远程服务挂掉了(网络故障、DNS故障、http服务返回错误的状态码、rpc服务抛出异常),则可以直接降级。降级后的处理方案有:默认值(比如库存服务挂了,返回默认现货)、兜底数据(比如广告挂了,返回提前准备好的一些静态页面)、缓存(之前暂存的一些缓存数据)</li><li>限流降级:秒杀或者抢购一些限购商品时,此时可能会因为访问量太大而导致系统崩溃,此时会使用限流来进行限制访问量,当达到限流阀值,后续请求会被降级;降级后的处理方案可以是:排队页面(将用户导流到排队页面等一会重试)、无货(直接告知用户没货了)、错误页(如活动太火爆了,稍后重试)</li></ul><h3 id="案例-1"><a href="#案例-1" class="headerlink" title="案例"></a>案例</h3><p>在SpringCloud-api模块下的service包中新建降级配置类DeptClientServiceFallBackFactory.java</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeptClientServiceFallBackFactory</span> <span class="keyword">implements</span> <span class="title">FallbackFactory</span> </span>{</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Object <span class="title">create</span><span class="params">(Throwable throwable)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> DeptClientService() {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Dept <span class="title">findById</span><span class="params">(Long id)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Dept(id,<span class="string">"客户端提供了服务降级,这个服务已被关闭"</span>,<span class="string">"服务已被关闭"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> List<Dept> <span class="title">findAll</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Boolean <span class="title">addDept</span><span class="params">(Dept dept)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在DeptClientService中指定降级配置类DeptClientServiceFallBackFactory</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallBackFactory.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">DeptClientService</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping("/dept/find/{id}")</span></span><br><span class="line"> <span class="function">Dept <span class="title">findById</span><span class="params">(<span class="meta">@PathVariable("id")</span> Long id)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@GetMapping("/dept/find")</span></span><br><span class="line"> <span class="function">List<Dept> <span class="title">findAll</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@PostMapping("/dept/add")</span></span><br><span class="line"> <span class="function">Boolean <span class="title">addDept</span><span class="params">(Dept dept)</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在SpringCloud-consumer-dept-feign模块配置中开启降级:</p><figure class="highlight xml"><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"># 开启降级feign.hystrix</span><br><span class="line">feign:</span><br><span class="line"> hystrix:</span><br><span class="line"> enabled: true</span><br></pre></td></tr></table></figure><p><strong>测试:</strong></p><p>启动eureka集群,启动服务提供者与feign消费者</p><p>可以正常访问数据:</p><p><img src="/2021/06/10/SpringCloud/image-20210611155058981.png" alt="image-20210611155058981"></p><p>如果此时停掉服务提供者的服务,再次访问数据如下:</p><p><img src="/2021/06/10/SpringCloud/image-20210611155216246.png" alt="image-20210611155216246"></p><h2 id="服务熔断和降级的区别"><a href="#服务熔断和降级的区别" class="headerlink" title="服务熔断和降级的区别"></a>服务熔断和降级的区别</h2><ul><li>服务熔断—>服务端:某个服务超时或异常,引起熔断~,类似于保险丝(自我熔断)</li><li>服务降级—>客户端:从整体网站请求负载考虑,当某个服务熔断或者关闭之后,服务将不再被调用,此时在客户端,我们可以准备一个 FallBackFactory ,返回一个默认的值(缺省值)。会导致整体的服务下降,但是好歹能用,比直接挂掉强。</li><li>触发原因不太一样,服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;管理目标的层次不太一样,熔断其实是一个框架级的处理,每个微服务都需要(无层级之分),而降级一般需要对业务有层级之分(比如降级一般是从最外围服务开始)</li><li>实现方式不太一样,服务降级具有代码侵入性(由控制器完成/或自动降级),熔断一般称为自我熔断。</li></ul><p><strong>熔断,降级,限流</strong>:</p><p>限流:限制并发的请求访问量,超过阈值则拒绝;</p><p>降级:服务分优先级,牺牲非核心服务(不可用),保证核心服务稳定;从整体负荷考虑;</p><p>熔断:依赖的下游服务故障触发熔断,避免引发本系统崩溃;系统自动执行和恢复</p><h2 id="Dashboard流监控"><a href="#Dashboard流监控" class="headerlink" title="Dashboard流监控"></a>Dashboard流监控</h2><p>新建SpringCloud-consumer-hystrix-dashboard模块</p><p>新增依赖</p><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>com.jonyon<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>SpringCloud-api<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.0-SNAPSHOT<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-actuator<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.3.3.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-devtools<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.3.5.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="comment"><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-ribbon --></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-ribbon<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.2.5.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="comment"><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client --></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-eureka-client<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.2.5.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="comment"><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix --></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-hystrix<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.2.5.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="comment"><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix-dashboard --></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-hystrix-dashboard<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.2.5.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependencies</span>></span></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></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableHystrixDashboard</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeptConsumerDashBoard</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(DeptConsumerDashBoard.class,args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>给SpringCloud-provider-dept-hystrix模块下的主启动类添加如下代码,添加监控</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableEurekaClient</span></span><br><span class="line"><span class="meta">@EnableCircuitBreaker</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeptProviderHystrix</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(DeptProviderHystrix.class,args);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//增加一个servlet</span></span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> ServletRegistrationBean <span class="title">hystrixMetricsStreamServlet</span><span class="params">()</span></span>{</span><br><span class="line"> ServletRegistrationBean registrationBean = <span class="keyword">new</span> ServletRegistrationBean(<span class="keyword">new</span> HystrixMetricsStreamServlet());</span><br><span class="line"> <span class="comment">//访问该页面就是监控页面</span></span><br><span class="line"> registrationBean.addUrlMappings(<span class="string">"/actuator/hystrix.stream"</span>);</span><br><span class="line"> <span class="keyword">return</span> registrationBean;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>访问<a href="http://localhost:8081/actuator/hystrix.stream">localhost:8081/actuator/hystrix.stream</a>,检查是否可以ping通</p><p><img src="/2021/06/10/SpringCloud/image-20210611173439407.png" alt="image-20210611173439407"></p><p>访问<a href="http://localhost:8088/hystrix">Hystrix Dashboard</a></p><p><img src="/2021/06/10/SpringCloud/image-20210611173518517.png" alt="image-20210611173518517"></p><p>并进入监控页面</p><p><img src="/2021/06/10/SpringCloud/image-20210611173541587.png" alt="image-20210611173541587"></p><p>一直向<a href="http://localhost:8087/feign/dept/get/2">localhost:8087/feign/dept/get/2</a>发送请求,数据显示如下:</p><p><img src="/2021/06/10/SpringCloud/image-20210611174112132.png" alt="image-20210611174112132"></p><p>访问<a href="http://localhost:8087/feign/dept/get/10">localhost:8087/feign/dept/get/10</a>不存在的id,导致服务熔断,会出现以下数据:</p><p><img src="/2021/06/10/SpringCloud/image-20210611174205281.png" alt="image-20210611174205281"></p><p>参数意义</p><p><img src="/2021/06/10/SpringCloud/image-20210611174426485.png" alt="image-20210611174426485"></p><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><p>1.记住导包</p><figure class="highlight xml"><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="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-actuator<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure><p>才可以进行监控</p><p>2.要想在dashboard里监控某个服务 这个服务本身得先 主启动类上@EnableCircuitBreaker 开启熔断开关 然后注入ServletBean,同时这个服务的控制器里面的接口 必须有@HystrixCommand的注解,用来标识要把哪些接口方法展示在dashboard上</p><p>3.访问监视页面报错<strong>Unable to connect to Command Metric Stream</strong>. 可以在监视项目的application.yml中添加配置</p><figure class="highlight yml"><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="attr">hystrix:</span></span><br><span class="line"> <span class="attr">dashboard:</span></span><br><span class="line"> <span class="attr">proxy-stream-allow-list:</span> <span class="string">"localhost"</span></span><br></pre></td></tr></table></figure><p>4.需要ping和监控的地址是服务提供者端,不是消费者端。</p><h1 id="Zuul路由网关"><a href="#Zuul路由网关" class="headerlink" title="Zuul路由网关"></a>Zuul路由网关</h1><h2 id="什么是zuul"><a href="#什么是zuul" class="headerlink" title="什么是zuul?"></a>什么是zuul?</h2><p> Zull包含了对请求的路由(用来跳转的)和过滤两个最主要功能:</p><p>其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础,而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础。Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得。</p><p><strong>注意</strong>:Zuul 服务最终还是会注册进 Eureka</p><p><strong>提供</strong>:代理 + 路由 + 过滤 三大功能</p><h2 id="zuul能干什么"><a href="#zuul能干什么" class="headerlink" title="zuul能干什么"></a>zuul能干什么</h2><ul><li>路由</li><li>过滤</li></ul><p>官方文档:<a href="https://github.com/Netflix/zuul/">https://github.com/Netflix/zuul/</a></p><h2 id="案例-2"><a href="#案例-2" class="headerlink" title="案例"></a>案例</h2><p>新建springcloud-zuul模块,并导入依赖</p><figure class="highlight xml"><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="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>com.jonyon<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>SpringCloud-api<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.0-SNAPSHOT<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-actuator<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.3.3.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-devtools<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.3.5.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="comment"><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-ribbon --></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-ribbon<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.2.5.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="comment"><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client --></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-eureka-client<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.2.5.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="comment"><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix --></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-hystrix<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.2.5.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="comment"><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix-dashboard --></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-hystrix-dashboard<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.2.5.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="comment"><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-zuul --></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-netflix-zuul<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.2.5.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"></<span class="name">dependencies</span>></span></span><br></pre></td></tr></table></figure><p>配置文件</p><figure class="highlight yml"><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"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8089</span></span><br><span class="line"></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">springcloud-zuul-gateway</span></span><br><span class="line"></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka01:8083/eureka/,http://eureka02:8084/eureka/,http://eureka:8082/eureka/</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="attr">instance-id:</span> <span class="string">gateway</span></span><br><span class="line"> <span class="attr">prefer-ip-address:</span> <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="attr">info:</span></span><br><span class="line"> <span class="attr">app.name:</span> <span class="string">springcloud学习项目</span></span><br><span class="line"> <span class="attr">company.name:</span> <span class="string">Jonyon</span></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></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableZuulProxy</span><span class="comment">//开启zuul</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ZullApplication</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(ZullApplication.class,args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>测试</strong></p><p>开启Eureka注册中心集群,开启适用熔断的提供者,开启zuul</p><p><img src="/2021/06/10/SpringCloud/image-20210612133320210.png" alt="image-20210612133320210"></p><p>可以看到现在路由网关已经被注册到eureka注册中心中了</p><p><img src="/2021/06/10/SpringCloud/image-20210612133450059.png" alt="image-20210612133450059"></p><p>访问<a href="http://www.jonyon.com:8089/springcloud-provider-dept-hystrix/dept/find/1">www.jonyon.com:8089/springcloud-provider-dept-hystrix/dept/find/1</a>(ip地址:zuul端口号/服务名称/服务接口)</p><p><img src="/2021/06/10/SpringCloud/image-20210612133430627.png" alt="image-20210612133430627"></p><p>上图是没有经过Zull路由网关配置时,服务接口访问的路由,可以看出直接用微服务(服务提供方)名称去访问,这样不安全,不能将微服务名称暴露</p><p><strong>于是添加修改配置文件</strong></p><figure class="highlight yml"><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="attr">zuul:</span></span><br><span class="line"> <span class="comment"># 路由相关配置</span></span><br><span class="line"> <span class="comment"># 原来访问路由 eg:http://www.jonyon.com:8089/springcloud-provider-dept-hystrix/dept/find/1</span></span><br><span class="line"> <span class="comment"># zull路由配置后访问路由 eg:http://www.jonyon.com:8089/hm/provider/dept/find/1</span></span><br><span class="line"> <span class="attr">routes:</span></span><br><span class="line"> <span class="attr">mydept.serviceId:</span> <span class="string">springcloud-provider-dept-hystrix</span> <span class="comment">#eureka注册中心的服务提供方路由名称</span></span><br><span class="line"> <span class="attr">mydept.path:</span> <span class="string">/provider/**</span> <span class="comment">#将eureka注册中心的服务提供方路由名称 改为自定义路由名称</span></span><br><span class="line"> <span class="attr">ignored-services:</span> <span class="string">"*"</span> <span class="comment">#不能再使用这个路径访问了;*: 忽略,隐藏全部的服务名称</span></span><br><span class="line"> <span class="attr">prefix:</span> <span class="string">/hm</span> <span class="comment">#设置公共的前缀</span></span><br></pre></td></tr></table></figure><p>经过Zull路由网关配置后,访问的路由为:</p><p><img src="/2021/06/10/SpringCloud/image-20210612135328066.png" alt="image-20210612135328066"></p><h1 id="Spring-Cloud-Config-分布式配置"><a href="#Spring-Cloud-Config-分布式配置" class="headerlink" title="Spring Cloud Config 分布式配置"></a>Spring Cloud Config 分布式配置</h1><p>Spring Cloud Config为分布式系统中的外部配置提供服务器和客户端支持。使用Config Server,您可以在所有环境中管理应用程序的外部属性。客户端和服务器上的概念映射与Spring Environment和PropertySource抽象相同,因此它们与Spring应用程序非常契合,但可以与任何以任何语言运行的应用程序一起使用。随着应用程序通过从开发人员到测试和生产的部署流程,您可以管理这些环境之间的配置,并确定应用程序具有迁移时需要运行的一切。服务器存储后端的默认实现使用git,因此它轻松支持标签版本的配置环境,以及可以访问用于管理内容的各种工具。很容易添加替代实现,并使用Spring配置将其插入。</p><h2 id="分布式系统面临的–配置文件问题"><a href="#分布式系统面临的–配置文件问题" class="headerlink" title="分布式系统面临的–配置文件问题"></a>分布式系统面临的–配置文件问题</h2><p>微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务,由于每个服务都需要必要的配置信息才能运行,所以一套集中式的,动态的配置管理设施是必不可少的。spring cloud提供了configServer来解决这个问题<br>spring cloud config 为微服务架构中的微服务提供集中化的外部支持,配置服务器为各个不同微服务应用的所有环节提供了一个<strong>中心化的外部配置</strong>。</p><p>spring cloud config 分为服务端和客户端两部分。</p><p> 服务端也称为 分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密,解密信息等访问接口。</p><p> 客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。配置服务器默认采用git来存储配置信息,这样就有助于对环境配置进行版本管理。并且可用通过git客户端工具来方便的管理和访问配置内容。</p><h2 id="spring-cloud-config-分布式配置中心能干什么?"><a href="#spring-cloud-config-分布式配置中心能干什么?" class="headerlink" title="spring cloud config 分布式配置中心能干什么?"></a>spring cloud config 分布式配置中心能干什么?</h2><ul><li>集中式管理配置文件</li><li>不同环境,不同配置,动态化的配置更新,分环境部署,比如 /dev /test /prod /beta /release</li><li>运行期间动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息</li><li>当配置发生变动时,服务不需要重启,即可感知到配置的变化,并应用新的配置</li><li>将配置信息以REST接口的形式暴露</li></ul><p><img src="/2021/06/10/SpringCloud/image-20210613122714837.png" alt="image-20210613122714837"></p><h2 id="spring-cloud-config-分布式配置中心与GitHub整合"><a href="#spring-cloud-config-分布式配置中心与GitHub整合" class="headerlink" title="spring cloud config 分布式配置中心与GitHub整合"></a>spring cloud config 分布式配置中心与GitHub整合</h2><p> 由于spring cloud config 默认使用git来存储配置文件 (也有其他方式,比如自持SVN 和本地文件),但是最推荐的还是git ,而且使用的是 http / https 访问的形式。</p><h2 id="案例-3"><a href="#案例-3" class="headerlink" title="案例"></a>案例</h2><h3 id="服务端"><a href="#服务端" class="headerlink" title="服务端"></a>服务端</h3><p>新建模块springcloud-config-server,导入依赖</p><figure class="highlight xml"><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="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-config-server<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure><p>配置文件</p><figure class="highlight yml"><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"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">springcloud-config-server</span></span><br><span class="line"> <span class="attr">cloud:</span></span><br><span class="line"> <span class="attr">config:</span></span><br><span class="line"> <span class="attr">label:</span> <span class="string">master</span></span><br><span class="line"> <span class="attr">server:</span></span><br><span class="line"> <span class="attr">git:</span></span><br><span class="line"> <span class="attr">uri:</span> <span class="string">https://gitee.com/AdgerJay518/springcloud-config-test.git</span></span><br><span class="line"> <span class="attr">force-pull:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">skip-ssl-validation:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">timeout:</span> <span class="number">10</span></span><br><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8090</span></span><br></pre></td></tr></table></figure><p>主启动类</p><figure class="highlight xml"><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">@SpringBootApplication</span><br><span class="line">@EnableConfigServer// 开启spring cloud config server服务</span><br><span class="line">public class SpringCloudConfServer {</span><br><span class="line"> public static void main(String[] args) {</span><br><span class="line"> SpringApplication.run(SpringCloudConfServer.class,args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>将本地git仓库springcloud-config-test文件夹下新建的application.yml提交到码云仓库(问题:我用github仓库无法连接访问,cannot open git-upload-pack)</p><p><img src="/2021/06/10/SpringCloud/image-20210612204042656.png" alt="image-20210612204042656"></p><figure class="highlight yml"><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="attr">spring:</span></span><br><span class="line"> <span class="attr">profiles:</span></span><br><span class="line"> <span class="attr">active:</span> <span class="string">dev</span></span><br><span class="line"></span><br><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">profiles:</span> <span class="string">dev</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">springcloud-config-dev</span></span><br><span class="line"> </span><br><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">profiles:</span> <span class="string">proc</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">springcloud-config-proc</span></span><br></pre></td></tr></table></figure><p>HTTP服务具有以下格式的资源:</p><figure class="highlight plain"><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">/{application}/{profile}[/{label}]</span><br><span class="line">/{application}-{profile}.yml</span><br><span class="line">/{label}/{application}-{profile}.yml</span><br><span class="line">/{application}-{profile}.properties</span><br><span class="line">/{label}/{application}-{profile}.properties</span><br></pre></td></tr></table></figure><p>测试访问<a href="http://localhost:8090/application/dev/master">localhost:8090/application/dev/master</a></p><p><img src="/2021/06/10/SpringCloud/image-20210613120742959.png" alt="image-20210613120742959"></p><p>测试访问<a href="http://localhost:8090/application-dev.yml">localhost:8090/application-dev.yml</a></p><p><img src="/2021/06/10/SpringCloud/image-20210612204133769.png" alt="image-20210612204133769"></p><p>测试访问<a href="http://localhost:8090/master/application-dev.yml">localhost:8090/master/application-dev.yml</a></p><p><img src="/2021/06/10/SpringCloud/image-20210613120824928.png" alt="image-20210613120824928"></p><p>测试访问<a href="http://localhost:8090/application-dev.properties">localhost:8090/application-dev.properties</a></p><p><img src="/2021/06/10/SpringCloud/image-20210613120856716.png" alt="image-20210613120856716"></p><p>测试访问<a href="http://localhost:8090/master/application-dev.properties">localhost:8090/master/application-dev.properties</a></p><p><img src="/2021/06/10/SpringCloud/image-20210613120921292.png" alt="image-20210613120921292"></p><h3 id="客户端"><a href="#客户端" class="headerlink" title="客户端"></a>客户端</h3><p>创建模块SpringCloud-config-client</p><p>导入依赖</p><figure class="highlight xml"><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="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-config<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependencies</span>></span></span><br></pre></td></tr></table></figure><p>配置文件bootstrap.yml</p><figure class="highlight yml"><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="attr">spring:</span></span><br><span class="line"> <span class="attr">cloud:</span></span><br><span class="line"> <span class="attr">config:</span></span><br><span class="line"> <span class="comment">#http://localhost:8090/master/config-client-dev.yml 连接客户端</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">config-client</span> <span class="comment">#需要从git上读取的资源名称,不需要后缀</span></span><br><span class="line"> <span class="attr">uri:</span> <span class="string">http://localhost:8090</span></span><br><span class="line"> <span class="attr">profile:</span> <span class="string">proc</span></span><br><span class="line"> <span class="attr">label:</span> <span class="string">master</span></span><br></pre></td></tr></table></figure><p>注意:bootstrap.yml是系统级别的配置;application.yml是用户级别的配置</p><p>controller</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConfigClientController</span> </span>{</span><br><span class="line"> <span class="meta">@Value("${spring.application.name}")</span></span><br><span class="line"> <span class="keyword">private</span> String applicationName; <span class="comment">//获取微服务名称</span></span><br><span class="line"></span><br><span class="line"> <span class="meta">@Value("${eureka.client.service-url.defaultZone}")</span></span><br><span class="line"> <span class="keyword">private</span> String eurekaServer; <span class="comment">//获取Eureka服务</span></span><br><span class="line"></span><br><span class="line"> <span class="meta">@Value("${server.port}")</span></span><br><span class="line"> <span class="keyword">private</span> String port; <span class="comment">//获取服务端的端口号</span></span><br><span class="line"></span><br><span class="line"> <span class="meta">@RequestMapping("/config")</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getConfig</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"applicationName:"</span>+applicationName +</span><br><span class="line"> <span class="string">"eurekaServer:"</span>+eurekaServer +</span><br><span class="line"> <span class="string">"port:"</span>+port;</span><br><span class="line"> }</span><br><span class="line">}</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SpringCloudConfClient</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> SpringApplication.run(SpringCloudConfClient.class,args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>本地新建config-client.yml;提交到码云仓库</p><figure class="highlight yml"><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></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">profiles:</span></span><br><span class="line"> <span class="attr">active:</span> <span class="string">dev</span></span><br><span class="line"></span><br><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8091</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">profiles:</span> <span class="string">dev</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">SpringCloud-provider-dept</span></span><br><span class="line"> </span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka01:8083/eureka/,http://eureka02:8084/eureka/,http://eureka:8082/eureka/</span></span><br><span class="line"></span><br><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8092</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">profiles:</span> <span class="string">proc</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">SpringCloud-provider-dept</span></span><br><span class="line"> </span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka01:8083/eureka/,http://eureka02:8084/eureka/,http://eureka:8082/eureka/</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="/2021/06/10/SpringCloud/image-20210613125211582.png" alt="image-20210613125211582"></p><p><strong>测试</strong></p><p>启动客户端:</p><p><img src="/2021/06/10/SpringCloud/image-20210613125310667.png" alt="image-20210613125310667"></p><p>可以看到,这时客户端的端口号是8092,因为我在bootstrap.yml中配置的profile是proc,所以客户端会连接<a href="http://localhost:8090/master/config-client-proc.yml%E8%8E%B7%E5%8F%96%E9%85%8D%E7%BD%AE%EF%BC%8C%E5%B9%B6%E4%B8%94%E6%88%91%E5%9C%A8config-client.yml%E4%B8%AD%E7%9A%84%E9%85%8D%E7%BD%AE%E4%B8%BA">http://localhost:8090/master/config-client-proc.yml获取配置,并且我在config-client.yml中的配置为</a></p><p><img src="/2021/06/10/SpringCloud/image-20210613125643570.png" alt="image-20210613125643570"></p><p>所以端口号为8092</p><p>测试访问<a href="http://localhost:8092/config">localhost:8092/config</a></p><p><img src="/2021/06/10/SpringCloud/image-20210613125827830.png" alt="image-20210613125827830"></p><p>此时,如果把bootstrap.yml中配置的profile变为dev</p><p><img src="/2021/06/10/SpringCloud/image-20210613125933833.png" alt="image-20210613125933833"></p><p>再次启动客户端:</p><p><img src="/2021/06/10/SpringCloud/image-20210613130001641.png" alt="image-20210613130001641"></p><h3 id="远程配置测试"><a href="#远程配置测试" class="headerlink" title="远程配置测试"></a>远程配置测试</h3><p>本地新建config-eurekat.yml,config-provider.yml;提交到码云仓库</p><figure class="highlight yml"><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="attr">spring:</span></span><br><span class="line"> <span class="attr">profile:</span></span><br><span class="line"> <span class="attr">active:</span> <span class="string">dev</span></span><br><span class="line"></span><br><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8082</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">proflie:</span> <span class="string">dev</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">springcloud-config-eureka-dev</span></span><br><span class="line"><span class="comment">#Eureka配置</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="attr">hostname:</span> <span class="string">eureka</span> <span class="comment">#Eureka服务端的实例名称</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">false</span> <span class="comment">#表示是否向Eureka注册中心注册自己</span></span><br><span class="line"> <span class="attr">fetch-registry:</span> <span class="literal">false</span> <span class="comment">#如果为false则表示自己为注册中心</span></span><br><span class="line"> <span class="attr">service-url:</span> <span class="comment">#监控页面</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka01:8083/eureka/,http://eureka02:8084/eureka/</span></span><br><span class="line"> </span><br><span class="line"><span class="meta">---</span></span><br><span class="line"></span><br><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8082</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">proflie:</span> <span class="string">proc</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">springcloud-config-eureka-proc</span></span><br><span class="line"><span class="comment">#Eureka配置</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="attr">hostname:</span> <span class="string">eureka</span> <span class="comment">#Eureka服务端的实例名称</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">register-with-eureka:</span> <span class="literal">false</span> <span class="comment">#表示是否向Eureka注册中心注册自己</span></span><br><span class="line"> <span class="attr">fetch-registry:</span> <span class="literal">false</span> <span class="comment">#如果为false则表示自己为注册中心</span></span><br><span class="line"> <span class="attr">service-url:</span> <span class="comment">#监控页面</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka01:8083/eureka/,http://eureka02:8084/eureka/</span></span><br></pre></td></tr></table></figure><figure class="highlight yml"><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></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">profile:</span></span><br><span class="line"> <span class="attr">active:</span> <span class="string">dev</span></span><br><span class="line"></span><br><span class="line"><span class="meta">---</span></span><br><span class="line"></span><br><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8081</span></span><br><span class="line"></span><br><span class="line"><span class="attr">mybatis:</span></span><br><span class="line"> <span class="attr">type-aliases-package:</span> <span class="string">com.jonyon.SpringCloud.pojo</span></span><br><span class="line"> <span class="attr">mapper-locations:</span> <span class="string">classpath:mapper/*.xml</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">profile:</span> <span class="string">dev</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">SpringCloud-provider-dept-dev</span></span><br><span class="line"> <span class="attr">datasource:</span></span><br><span class="line"> <span class="attr">type:</span> <span class="string">com.alibaba.druid.pool.DruidDataSource</span></span><br><span class="line"> <span class="attr">driver-class-name:</span> <span class="string">org.gjt.mm.mysql.Driver</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">jdbc:mysql://localhost:3306/SpringCloud?useUnicode=true&characterEncoding=utf-8</span></span><br><span class="line"> <span class="attr">username:</span> <span class="string">root</span></span><br><span class="line"> <span class="attr">password:</span> <span class="string">root</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka01:8083/eureka/,http://eureka02:8084/eureka/,http://eureka:8082/eureka/</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="attr">instance-id:</span> <span class="string">springcloud-provider</span></span><br><span class="line"></span><br><span class="line"><span class="attr">info:</span></span><br><span class="line"> <span class="attr">app.name:</span> <span class="string">springcloud学习项目</span></span><br><span class="line"> <span class="attr">company.name:</span> <span class="string">Jonyon</span></span><br><span class="line"> </span><br><span class="line"><span class="meta">---</span></span><br><span class="line"></span><br><span class="line"><span class="attr">server:</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">8081</span></span><br><span class="line"></span><br><span class="line"><span class="attr">mybatis:</span></span><br><span class="line"> <span class="attr">type-aliases-package:</span> <span class="string">com.jonyon.SpringCloud.pojo</span></span><br><span class="line"> <span class="attr">mapper-locations:</span> <span class="string">classpath:mapper/*.xml</span></span><br><span class="line"><span class="attr">spring:</span></span><br><span class="line"> <span class="attr">profile:</span> <span class="string">proc</span></span><br><span class="line"> <span class="attr">application:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">SpringCloud-provider-dept-proc</span></span><br><span class="line"> <span class="attr">datasource:</span></span><br><span class="line"> <span class="attr">type:</span> <span class="string">com.alibaba.druid.pool.DruidDataSource</span></span><br><span class="line"> <span class="attr">driver-class-name:</span> <span class="string">org.gjt.mm.mysql.Driver</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">jdbc:mysql://localhost:3306/SpringCloud01?useUnicode=true&characterEncoding=utf-8</span></span><br><span class="line"> <span class="attr">username:</span> <span class="string">root</span></span><br><span class="line"> <span class="attr">password:</span> <span class="string">root</span></span><br><span class="line"><span class="attr">eureka:</span></span><br><span class="line"> <span class="attr">client:</span></span><br><span class="line"> <span class="attr">service-url:</span></span><br><span class="line"> <span class="attr">defaultZone:</span> <span class="string">http://eureka01:8083/eureka/,http://eureka02:8084/eureka/,http://eureka:8082/eureka/</span></span><br><span class="line"> <span class="attr">instance:</span></span><br><span class="line"> <span class="attr">instance-id:</span> <span class="string">springcloud-provider</span></span><br><span class="line"></span><br><span class="line"><span class="attr">info:</span></span><br><span class="line"> <span class="attr">app.name:</span> <span class="string">springcloud学习项目</span></span><br><span class="line"> <span class="attr">company.name:</span> <span class="string">Jonyon</span></span><br></pre></td></tr></table></figure><p><img src="/2021/06/10/SpringCloud/image-20210613135206519.png" alt="image-20210613135206519"></p><p>根据SpringCloud-eureka-server、SpringCloud-provider-dept创建模块SpringCloud-config-eureka、SpringCloud-config-provider。</p><p>并在新创建的模块中新增依赖</p><figure class="highlight xml"><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="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-config<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure><p>清空新创建的模块中的application.yml,新建bootstrap.yml</p><p>eureka</p><figure class="highlight yml"><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="attr">spring:</span></span><br><span class="line"> <span class="attr">cloud:</span></span><br><span class="line"> <span class="attr">config:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">config-eureka</span></span><br><span class="line"> <span class="attr">uri:</span> <span class="string">http://localhost:8090</span></span><br><span class="line"> <span class="attr">profile:</span> <span class="string">dev</span></span><br><span class="line"> <span class="attr">label:</span> <span class="string">master</span></span><br></pre></td></tr></table></figure><p>provider</p><figure class="highlight yml"><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="attr">spring:</span></span><br><span class="line"> <span class="attr">cloud:</span></span><br><span class="line"> <span class="attr">config:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">config-provider</span></span><br><span class="line"> <span class="attr">uri:</span> <span class="string">http://localhost:8090</span></span><br><span class="line"> <span class="attr">profile:</span> <span class="string">dev</span></span><br><span class="line"> <span class="attr">label:</span> <span class="string">master</span></span><br></pre></td></tr></table></figure><p>启动项目</p><p><img src="/2021/06/10/SpringCloud/image-20210613135655038.png" alt="image-20210613135655038"></p><p>访问<a href="http://localhost:8082/">Eureka</a></p><p><img src="/2021/06/10/SpringCloud/image-20210613135746328.png" alt="image-20210613135746328"></p><p>访问<a href="http://localhost:8081/dept/find/1">localhost:8081/dept/find/1</a></p><p><img src="/2021/06/10/SpringCloud/image-20210613135800255.png" alt="image-20210613135800255"></p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p><img src="/2021/06/10/SpringCloud/image-20210613150119026.png" alt="image-20210613150119026"></p><p>参考别人画的SpringCloud流程图</p><p><img src="/2021/06/10/SpringCloud/image-20210613155751999.png" alt="image-20210613155751999"></p><p><strong>自己的一些理解</strong></p><p><img src="/2021/06/10/SpringCloud/image-20210613161237372.png" alt="image-20210613161237372"></p><h2 id="Eureka"><a href="#Eureka" class="headerlink" title="Eureka"></a>Eureka</h2><p><img src="/2021/06/10/SpringCloud/image-20210613161711131.png" alt="image-20210613161711131"></p><blockquote><p>Eureka分为服务端和客户端。</p><p>服务端作为注册中心存在,提供服务的注册与发现。可以通过监控客户端的“心跳”来监控系统中的各个微服务是否在正常运行。为了安全考虑,Eureka注册中心常以集群的方式搭建在多个服务器上。</p><p>客户端一般是服务提供者和消费者,服务提供者向注册中心提供服务,将自身服务注册到Eureka中,从而使服务消费方能够找到;消费者从Eureka中获取注册服务列表,从而找到要消费的服务</p></blockquote><h2 id="Feign"><a href="#Feign" class="headerlink" title="Feign"></a>Feign</h2><p><img src="/2021/06/10/SpringCloud/image-20210613164001119.png" alt="image-20210613164001119"></p><blockquote><p>Feign是集成Ribbon的</p><p><strong>Feign的一个机制是动态代理</strong></p><p>如果对某个接口定义了@FeignClient注解,Feign就会针对这个接口创建一个动态代理。要是调用这个接口,本质就是会调用 Feign创建的动态代理。Feign的动态代理会根据在接口上的@RequestMapping等注解,来动态构造出请求的服务的地址,最后针对这个地址,发起请求、解析响应。</p><p><strong>如果一个服务部署在了多台服务器上,这时候Feign应该请求哪一台服务器呢?</strong></p><p>Ribbon就可以解决这个问题,Ribbon可以实现客户端负载均衡,将用户的请求平摊的分配到多个服务器上。</p><p>Ribbon会从 Eureka Client里面获取到对应的服务注册列表,也就知道了所有的服务都部署在了哪台机器上,在监听哪些端口,</p><p>Ribbon使用默认的Round Robin轮询算法,从中选择一台机器,</p><p>Feigin就会针对这些机器构造并发送请求.</p></blockquote><h2 id="Hystrix-1"><a href="#Hystrix-1" class="headerlink" title="Hystrix"></a>Hystrix</h2><p><img src="/2021/06/10/SpringCloud/image-20210613165434006.png" alt="image-20210613165434006"></p><blockquote><p>Hystrix主要用于应对服务雪崩的场景。</p><p>比如说订单服务在一个业务流程里需要调用三个服务,且订单服务最多自有一百个线程可以处理请求。这时一个充值服务挂了,那每次订单服务在调用这个充值服务都会卡住几秒钟,然后抛出—个超时异常。如果这时候有大量的请求涌过来,订单服务的一百个线程都会卡在充值服务这一块,导致订单服务不再有线程可以处理请求,导致再有别的请求订单服务时会发现服务挂掉。</p><p>如果多服务间的调用不做任何的保护机制,会导致某一个服务挂掉而引起连锁反应,导致别的服务也挂掉。</p><p>为了解决这个问题就需要使用Hystrix</p><p>当某个微服务不可用或者响应时间太长时,快速返回错误的响应信息,这就是<strong>服务熔断</strong>。</p><p>当某一时间内服务A的访问量暴增,而B和C的访问量较少,为了缓解A服务的压力,这时候需要B和C暂时关闭一些服务功能,去承担A的部分服务,从而为A分担压力,叫做<strong>服务降级</strong>。</p></blockquote><h2 id="Zuul"><a href="#Zuul" class="headerlink" title="Zuul"></a>Zuul</h2><p><img src="/2021/06/10/SpringCloud/image-20210613180412730.png" alt="image-20210613180412730"></p><blockquote><p>负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础,而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础。</p></blockquote><h1 id="相关项目地址"><a href="#相关项目地址" class="headerlink" title="相关项目地址"></a>相关项目地址</h1><p><a href="https://github.com/AdgerJay518/SpringCloud">https://github.com/AdgerJay518/SpringCloud</a></p>]]></content>
<summary type="html"><h1 id="为什么使用Spring-Cloud"><a href="#为什么使用Spring-Cloud" class="headerlink" title="为什么使用Spring Cloud"></a>为什么使用Spring Cloud</h1><p>一个项目中有很多业务,这个项目部署在一台服务器中</p>
<p>当访问的用户越来越多后,这台服务器支持的并发量到达了上限,为了解决这个问题,可以采用水平拆分的方式,在多个服务器中部署项目,并采用<strong>负载均衡</strong>的方式使几台服务器所占的资源均匀</p>
<p>这时有一个问题:<strong>在一个项目中有些业务的实际使用效率并不高,而有些业务的实际使用效率又很高,这时就会希望给使用效率高的业务多分配一些服务器资源</strong>。</p>
<p>为了达到这个目的,可以将原来的整体项目<strong>模块化</strong>,也就是说将不同的业务划分为一个单独的项目,再将划分的业务模块项目放入一个服务器</p>
<p>这样的架构就叫做<strong>微服务架构</strong></p>
<p>微服务的核心就是将传统的一站式应用,根据业务拆分成一个一个的服务,彻底的去耦合,每一个微服务提供单个业务功能的服务,一个服务做一件事,从技术角度看,就是一种小而独立的处理过程,类似进程的概念,能够自行单独启动或销毁,拥有自己独立的数据库。</p></summary>
<category term="SpringCloud" scheme="http://www.jonyonwzj.top/categories/SpringCloud/"/>
<category term="Spring" scheme="http://www.jonyonwzj.top/tags/Spring/"/>
</entry>
<entry>
<title>Elasticsearch</title>
<link href="http://www.jonyonwzj.top/2021/06/07/Elasticsearch/"/>
<id>http://www.jonyonwzj.top/2021/06/07/Elasticsearch/</id>
<published>2021-06-07T04:28:21.000Z</published>
<updated>2021-06-13T10:12:30.538Z</updated>
<content type="html"><![CDATA[<h1 id="Elasticsearch概述"><a href="#Elasticsearch概述" class="headerlink" title="Elasticsearch概述"></a>Elasticsearch概述</h1><p>Elasticsearch 是一个分布式可扩展的实时搜索和分析引擎,一个建立在全文搜索引擎 Apache Lucene(TM) 基础上的搜索引擎.基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。Luncene是单节点的API,ElasticSearch是分布式的。当然 Elasticsearch 并不仅仅是 Lucene 那么简单,它不仅包括了全文搜索功能,还可以进行以下工作:分布式实时文件存储,并将每一个字段都编入索引,使其可以被搜索。实时分析的分布式搜索引擎。可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。其实只要知道这几个关键字:<strong>分布式</strong> <strong>实时</strong> <strong>搜索引擎</strong></p><p>总的来说Elasticsearch不是什么新技术,主要是将全文检索、数据分析以及分布式技术整合在了一起,可以作为一个大型分布式集群(数百台服务器),对PB级的数据进行检索和分析,而且开箱即用,上手非常简单。</p><a id="more"></a><h1 id="为什么使用Elasticsearch"><a href="#为什么使用Elasticsearch" class="headerlink" title="为什么使用Elasticsearch"></a>为什么使用Elasticsearch</h1><p>在引入elasticsearch前,我们的数据一般都存储在mysql上,所有的检索都是直接在数据库的查询,当数据库的数据量达到一定量时,数据库的检索效率就会很低,对此我们或许会有很多解决方案,比如对数据库采用分库分表(主从设置),数据库分库分表的确可以解决大部分数据量性能问题,但是同样还是会有两个问题无法避免</p><ul><li>分表多表的关联查询难度很大,不易实现(目前市场上主流的集中分库分表插件都没有很好的解决)</li><li>没有建立索引的字段查询效率依旧不高 </li></ul><p>也有人说可以采用Hbase,的确Hbase能够支持的数据量确实大(一个表可以有数十亿行,上百万列),但是它的检索是都是行级或者range,并不支持复杂的查询,一般可以用于数据挖掘(统计报表类的比较合适); 于是基于以上场景,我们去分析elasticsearch的几个特点</p><ul><li><strong>分布式</strong>(多shard的方式保证数据安全,也会提供自动resharding),一般不会因为数据量有性能问题,</li><li><strong>实时</strong>:elasticsearch的检索速度非常快,接近实时(注意刚刚存储的数据) </li><li><strong>搜索引擎</strong>:相比Hbase,es的定位就是搜索索引,支持全文检索; </li></ul><p>总的来说ElasticSearch 产生背景是海量数据组合条件查询,毫秒级或者秒级返回数据</p><h1 id="Elasticsearch与Solr"><a href="#Elasticsearch与Solr" class="headerlink" title="Elasticsearch与Solr"></a>Elasticsearch与Solr</h1><h2 id="Elasticsearch"><a href="#Elasticsearch" class="headerlink" title="Elasticsearch"></a>Elasticsearch</h2><p>优点</p><ol><li>Elasticsearch是分布式的。不需要其他组件,分发是实时的,被叫做”Push replication”。</li><li>Elasticsearch 完全支持 Apache Lucene 的接近实时的搜索。</li><li>处理多租户(multitenancy)不需要特殊配置,而Solr则需要更多的高级设置。</li><li>Elasticsearch 采用 Gateway 的概念,使得完备份更加简单。</li><li>各节点组成对等的网络结构,某些节点出现故障时会自动分配其他节点代替其进行工作。</li></ol><p>缺点</p><ol><li>只有一名开发者(当前Elasticsearch GitHub组织已经不只如此,已经有了相当活跃的维护者)</li><li>还不够自动(不适合当前新的Index Warmup API)</li></ol><h2 id="Solr"><a href="#Solr" class="headerlink" title="Solr"></a>Solr</h2><p>Solr(读作”solar”)是Apache Lucene项目的开源企业搜索平台。其主要功能包括全文检索、命中标示、分面搜索、动态聚类、数据库集成, 以及富文本(如Word、PDF)的处理。Solr是高度可扩展的, 并提供了分布式搜索和索引复制。Solr是最流行的企业级搜索引擎, Solr4 还增加了NoSQL支持。</p><p>Solr是用Java编写、运行在Servlet容器(如 Apache Tomcat 或Jetty)的一个独立的全文搜索服务器。 Solr采用了 Lucene Java 搜索库为核心的全文索引和搜索, 并具有类似REST的HTTP/XML和JSON的API。Solr强大的外部配置功能使得无需进行Java编码, 便可对 其进行调整以适应多种类型的应用程序。Solr有一个插件架构, 以支持更多的高级定制。</p><p>因为2010年 Apache Lucene 和 Apache Solr 项目合并, 两个项目是由同一个Apache软件基金会开发团队制作实现的。提到技术或产品时, Lucene/Solr或Solr/Lucene是一样的。</p><p>优点</p><ol><li>Solr有一个更大、更成熟的用户、开发和贡献者社区。</li><li>支持添加多种格式的索引,如:HTML、PDF、微软 Office 系列软件格式以及 JSON、XML、CSV 等纯文本格式。</li><li>Solr比较成熟、稳定。</li><li>不考虑建索引的同时进行搜索,速度更快。</li></ol><p>缺点</p><ol><li>建立索引时,搜索效率下降,实时索引搜索效率不高。</li></ol><h2 id="Elasticsearch与Solr的比较"><a href="#Elasticsearch与Solr的比较" class="headerlink" title="Elasticsearch与Solr的比较"></a>Elasticsearch与Solr的比较</h2><p><img src="/2021/06/07/Elasticsearch/image-20210605140224970.png" alt="image-20210605140224970"></p><p><img src="/2021/06/07/Elasticsearch/image-20210605140240496.png" alt="image-20210605140240496"></p><p><img src="/2021/06/07/Elasticsearch/image-20210605140254769.png" alt="image-20210605140254769"></p><p><img src="/2021/06/07/Elasticsearch/image-20210605140307352.png" alt="image-20210605140307352"></p><p><strong>综上所述,Solr的架构不适合实时搜索的应用。</strong></p><ul><li>Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能;</li><li>Solr 支持更多格式的数据,而 Elasticsearch 仅支持json文件格式;</li><li>Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高级功能多有第三方插件提供;</li><li>Solr 在传统的搜索应用中表现好于 Elasticsearch,但在处理实时搜索应用时效率明显低于 Elasticsearch。</li></ul><h1 id="Elasticsearch安装"><a href="#Elasticsearch安装" class="headerlink" title="Elasticsearch安装"></a>Elasticsearch安装</h1><p>Elasticsearch是基于java开发的,安装Elasticsearch需要JDK1.8及其以上</p><figure class="highlight plain"><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">bin 启动目录</span><br><span class="line">config 配置文件</span><br><span class="line"> log4j2 日志配置文件</span><br><span class="line"> jvm.options java虚拟机相关配置</span><br><span class="line"> elasticsearch.yml elasticsearch配置文件 默认9200端口</span><br><span class="line"> lib 相关jar包</span><br><span class="line"> modules 功能模块</span><br><span class="line"> plugins 功能插件 ik</span><br></pre></td></tr></table></figure><p><strong>启动乱码问题</strong></p><p>修改jvm.options</p><p>添加到24行-Dfile.encoding=GCK</p><p><img src="/2021/06/07/Elasticsearch/image-20210605142704604.png" alt="image-20210605142704604"></p><p>1.在bin目录下双击elasticsearch.bat成功启动</p><p><img src="/2021/06/07/Elasticsearch/image-20210605142715943.png" alt="image-20210605142715943"></p><p>2.访问<a href="http://127.0.0.1:9200/">127.0.0.1:9200</a></p><p><img src="/2021/06/07/Elasticsearch/image-20210605143014966.png" alt="image-20210605143014966"></p><h2 id="安装可视化界面elasticsearch-head的插件"><a href="#安装可视化界面elasticsearch-head的插件" class="headerlink" title="安装可视化界面elasticsearch-head的插件"></a>安装可视化界面elasticsearch-head的插件</h2><p>注意:安装前需提前安装过Node.js、npm</p><p>下载地址:<a href="https://github.com/mobz/elasticsearch-head">https://github.com/mobz/elasticsearch-head</a></p><p>1.进入目录,cnpm install</p><p><img src="/2021/06/07/Elasticsearch/image-20210605143951919.png" alt="image-20210605143951919"></p><p>2.npm run start</p><p><img src="/2021/06/07/Elasticsearch/image-20210605144124192.png" alt="image-20210605144124192"></p><p>3.进入<a href="http://127.0.0.1:9100/">elasticsearch-head</a></p><p><img src="/2021/06/07/Elasticsearch/image-20210605144316459.png" alt="image-20210605144316459"></p><p><strong>此时还无法连接9200端口的elasticsearch,因为存在跨域问题</strong></p><p>解决方法:</p><p>进入elasticsearch config目录下elasticsearch.yml添加跨域配置</p><p><img src="/2021/06/07/Elasticsearch/image-20210605145437378.png" alt="image-20210605145437378"></p><p>4.重启elasticsearch ,连接成功</p><p><img src="/2021/06/07/Elasticsearch/image-20210605145534582.png" alt="image-20210605145534582"></p><p>es就相当于一个数据库,可以建立索引(库),文档(库中的数据 )</p><p>head只是一个数据展示的工具,查询需要用kibana来做</p><h2 id="Kibana"><a href="#Kibana" class="headerlink" title="Kibana"></a>Kibana</h2><p>kibana可以将elasticsearch的数据通过友好的页面展示出来,提供实时分析的功能</p><p>Kibana是一个开源的分析与可视化平台,设计出来用于和Elasticsearch一起使用的。你可以用kibana搜索、查看存放在Elasticsearch中的数据。Kibana与Elasticsearch的交互方式是各种不同的图表、表格、地图等,直观的展示数据,从而达到高级的数据分析与可视化的目的。<br> Elasticsearch、Logstash和Kibana这三个技术就是我们常说的ELK技术栈,可以说这三个技术的组合是大数据领域中一个很巧妙的设计。一种很典型的MVC思想,模型持久层,视图层和控制层。Logstash担任控制层的角色,负责搜集和过滤数据。Elasticsearch担任数据持久层的角色,负责储存数据。而我们这章的主题Kibana担任视图层角色,拥有各种维度的查询和分析,并使用图形化的界面展示存放在Elasticsearch中的数据。</p><p>安装时要注意,kibana版本要和elasticsearch版本一致</p><p>1.启动kibana.bat</p><p><img src="/2021/06/07/Elasticsearch/image-20210605151938587.png" alt="image-20210605151938587"></p><p>2.访问<a href="http://localhost:5601/">Kibana</a></p><p><img src="/2021/06/07/Elasticsearch/image-20210605151959343.png" alt="image-20210605151959343"></p><p>3.开发工具</p><p><img src="/2021/06/07/Elasticsearch/image-20210605152158309.png" alt="image-20210605152158309"></p><p>所有操作都在这里进行编写</p><p>4.修改kibana语言为中文(config的ymal文件下进行修改)</p><p><img src="/2021/06/07/Elasticsearch/image-20210605152521633.png" alt="image-20210605152521633"></p><h1 id="Elasticsearch核心概念"><a href="#Elasticsearch核心概念" class="headerlink" title="Elasticsearch核心概念"></a>Elasticsearch核心概念</h1><ul><li>索引</li><li>字段类型(mapping)</li><li>文档(documents)</li><li>分片(倒排索引)</li></ul><p>elasticsearch是面向文档的,一切都是JSON</p><h1 id="IK分词器插件"><a href="#IK分词器插件" class="headerlink" title="IK分词器插件"></a>IK分词器插件</h1><h2 id="什么是IK分词器"><a href="#什么是IK分词器" class="headerlink" title="什么是IK分词器"></a>什么是IK分词器</h2><p>分词:把一段话分成一个一个的关键字,在搜索的时候会把自己的信息进行分词,会把数据库中的数据进行分词,然后进行一个匹配操作</p><p>下载地址:<a href="https://github.com/medcl/elasticsearch-analysis-ik">https://github.com/medcl/elasticsearch-analysis-ik</a></p><h2 id="查看不同的分词器效果"><a href="#查看不同的分词器效果" class="headerlink" title="查看不同的分词器效果"></a>查看不同的分词器效果</h2><p>ik_smart最小切分</p><p><img src="/2021/06/07/Elasticsearch/image-20210605160916736.png" alt="image-20210605160916736"></p><p>ik_max_word最细粒度划分</p><p><img src="/2021/06/07/Elasticsearch/image-20210605160926643.png" alt="image-20210605160926643"></p><p><img src="/2021/06/07/Elasticsearch/image-20210605161515118.png" alt="image-20210605161515118"></p><p>这里有一个问题:我想要阿杰是一个词,而不能分开成两个字</p><p>进入config目录下的IKAnalyzer.cfg.xml</p><p><img src="/2021/06/07/Elasticsearch/image-20210605161724681.png" alt="image-20210605161724681"></p><p>定义一个my.dic作为自己的自定义词典</p><p>在my.dic中编写自己词</p><p><img src="/2021/06/07/Elasticsearch/image-20210605161827222.png" alt="image-20210605161827222"></p><p>再次执行</p><p><img src="/2021/06/07/Elasticsearch/image-20210605162800649.png" alt="image-20210605162800649"></p><p>成功</p><h1 id="Restful"><a href="#Restful" class="headerlink" title="Restful"></a>Restful</h1><p><img src="/2021/06/07/Elasticsearch/image-20210605170739892.png" alt="image-20210605170739892"></p><p>1.创建一个索引</p><figure class="highlight plain"><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">PUT /索引名/类型名/文档ID</span><br><span class="line">{请求体}</span><br></pre></td></tr></table></figure><p><img src="/2021/06/07/Elasticsearch/image-20210605170956648.png" alt="image-20210605170956648"></p><p>2.建立索引规则</p><p><img src="/2021/06/07/Elasticsearch/image-20210605171756092.png" alt="image-20210605171756092"></p><p>3.得到索引规则,可以通过get请求获得具体的信息</p><p><img src="/2021/06/07/Elasticsearch/image-20210605171916956.png" alt="image-20210605171916956"></p><p><img src="/2021/06/07/Elasticsearch/image-20210605172036069.png" alt="image-20210605172036069"></p><p>GET _cat/indices?v</p><p><img src="/2021/06/07/Elasticsearch/image-20210605172621743.png" alt="image-20210605172621743"></p><p>通过_cat可以获得es的当前的很多信息</p><p>修改 </p><p>1.使用put覆盖值</p><p>2.post</p><p><img src="/2021/06/07/Elasticsearch/image-20210605173520140.png" alt="image-20210605173520140"></p><p>删除索引 delete test1</p><h1 id="复杂搜索"><a href="#复杂搜索" class="headerlink" title="复杂搜索"></a>复杂搜索</h1><p><img src="/2021/06/07/Elasticsearch/image-20210606130754757.png" alt="image-20210606130754757"></p><h2 id="查询"><a href="#查询" class="headerlink" title="查询"></a>查询</h2><p>根据条件查询</p><p><img src="/2021/06/07/Elasticsearch/image-20210606130823863.png" alt="image-20210606130823863"></p><figure class="highlight plain"><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">hits: 索引和文档的信息{</span><br><span class="line">total:{</span><br><span class="line">value 查询出来的结果总数</span><br><span class="line">},</span><br><span class="line">max_score 最大分数,匹配度最高的数据的分数</span><br><span class="line">hits: 查询出来的具体文档{</span><br><span class="line">_score 分数,相当于匹配度,分数越大,匹配度越高,查询出来的结果就越靠前面</span><br><span class="line">...</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>结果过滤</p><p><img src="/2021/06/07/Elasticsearch/image-20210606131736184.png" alt="image-20210606131736184"></p><p>通过字段进行排序</p><p><img src="/2021/06/07/Elasticsearch/image-20210606132604418.png" alt="image-20210606132604418"></p><p>分页查询</p><p><img src="/2021/06/07/Elasticsearch/image-20210606132755454.png" alt="image-20210606132755454"></p><p>布尔查询</p><p>must(and),所有的条件都要符合where id= 1 and name=xxx</p><p>should(or),所有的条件都要符合where id= 1 or name=xxx</p><p>must_not(not)</p><p><img src="/2021/06/07/Elasticsearch/image-20210606133329803.png" alt="image-20210606133329803"></p><p><img src="/2021/06/07/Elasticsearch/image-20210606133713134.png" alt="image-20210606133713134"></p><p><img src="/2021/06/07/Elasticsearch/image-20210606133930058.png" alt="image-20210606133930058"></p><p>过滤条件</p><p>gt 大于</p><p>gte 大于等于</p><p>lt 小于</p><p>ite 小于等于</p><p><img src="/2021/06/07/Elasticsearch/image-20210606134433133.png" alt="image-20210606134433133"></p><p>匹配多个条件</p><p><img src="/2021/06/07/Elasticsearch/image-20210606134856805.png" alt="image-20210606134856805"></p><p><img src="/2021/06/07/Elasticsearch/image-20210606135059303.png" alt="image-20210606135059303"></p><p>多个条件用空格隔开</p><p>精确查询</p><p>tern查询是直接通过倒排索引指定的词条进行精确的查找</p><p><strong>关于分词:</strong></p><ul><li>term:直接查询精确的</li><li>match:会使用分词器解析(先分析文档,然后通过分析的文档进行查询)</li></ul><p><strong>两个类型:</strong></p><ul><li>text:可以被分词器解析</li><li>keyword:无法被分词器解析</li></ul><p>高亮查询</p><p><img src="/2021/06/07/Elasticsearch/image-20210606141055419.png" alt="image-20210606141055419"></p><p>自定义搜索高亮条件</p><p><img src="/2021/06/07/Elasticsearch/image-20210606141354580.png" alt="image-20210606141354580"></p><h1 id="相关项目地址"><a href="#相关项目地址" class="headerlink" title="相关项目地址"></a>相关项目地址</h1><p><a href="https://github.com/AdgerJay518/es-api">https://github.com/AdgerJay518/es-api</a> </p>]]></content>
<summary type="html"><h1 id="Elasticsearch概述"><a href="#Elasticsearch概述" class="headerlink" title="Elasticsearch概述"></a>Elasticsearch概述</h1><p>Elasticsearch 是一个分布式可扩展的实时搜索和分析引擎,一个建立在全文搜索引擎 Apache Lucene(TM) 基础上的搜索引擎.基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。Luncene是单节点的API,ElasticSearch是分布式的。当然 Elasticsearch 并不仅仅是 Lucene 那么简单,它不仅包括了全文搜索功能,还可以进行以下工作:分布式实时文件存储,并将每一个字段都编入索引,使其可以被搜索。实时分析的分布式搜索引擎。可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。其实只要知道这几个关键字:<strong>分布式</strong> <strong>实时</strong> <strong>搜索引擎</strong></p>
<p>总的来说Elasticsearch不是什么新技术,主要是将全文检索、数据分析以及分布式技术整合在了一起,可以作为一个大型分布式集群(数百台服务器),对PB级的数据进行检索和分析,而且开箱即用,上手非常简单。</p></summary>
<category term="中间件" scheme="http://www.jonyonwzj.top/categories/%E4%B8%AD%E9%97%B4%E4%BB%B6/"/>
<category term="搜索引擎" scheme="http://www.jonyonwzj.top/tags/%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E/"/>
</entry>
<entry>
<title>十大经典排序算法</title>
<link href="http://www.jonyonwzj.top/2021/05/17/%E5%8D%81%E5%A4%A7%E7%BB%8F%E5%85%B8%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/"/>
<id>http://www.jonyonwzj.top/2021/05/17/%E5%8D%81%E5%A4%A7%E7%BB%8F%E5%85%B8%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/</id>
<published>2021-05-17T12:11:17.000Z</published>
<updated>2021-08-31T05:39:29.626Z</updated>
<content type="html"><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>十大排序算法是每个程序员都必须掌握的,目前自己熟悉的算法有冒泡排序,快速排序,选择排序,归并排序。从今天起开始从头学习排序算法,把学习过的复习一遍,加深印象;没有学习过的争取一次学会。</p><h1 id="术语"><a href="#术语" class="headerlink" title="术语"></a>术语</h1><p>排序算法中也有“术语”,想要学习排序算法首先需要理解这些术语的意思。</p><ul><li>稳定排序:有两个相同的数a和b,在排序之前a在b的前面,排序之后a仍然在b的前面,则为稳定排序。</li><li>非稳定排序:有两个相同的数a和b,在排序之前a在b的前面,排序之后a可能不在b的前面,则为非稳定排序。</li><li>原地排序:排序过程中不申请多余的空间,只利用原来存储待排数据的存储空间进行比较和交换。</li><li>非原地排序:需要利用额外的空间来辅助排序。</li></ul><a id="more"></a><h1 id="十大排序算法"><a href="#十大排序算法" class="headerlink" title="十大排序算法"></a>十大排序算法</h1><h2 id="冒泡排序"><a href="#冒泡排序" class="headerlink" title="冒泡排序"></a>冒泡排序</h2><p>算法步骤</p><ol><li>从左到右比较相邻的两个元素,如果第一个比第二个大,就交换它们两个;如果第二个比第三个大,就交换它们两个……</li><li>重复第一步,这样从左到右一轮比较结束后最后一个元素一定是最大的一个元素。</li><li>开始下一轮比较,依旧重复第一步,不同的是前一轮排序结束后的最后一个元素不再进行比较。</li><li>持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。</li></ol><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span>[] bubbleSort(<span class="keyword">int</span>[] arr){</span><br><span class="line"> <span class="keyword">int</span> length=arr.length;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i<length;i++){</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j=<span class="number">0</span>;j<length-i-<span class="number">1</span>;j++){</span><br><span class="line"> <span class="keyword">if</span> (arr[j]>arr[j+<span class="number">1</span>]){</span><br><span class="line"> <span class="keyword">int</span> temp=arr[j];</span><br><span class="line"> arr[j]=arr[j+<span class="number">1</span>];</span><br><span class="line"> arr[j+<span class="number">1</span>]=temp;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> arr;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>不难发现这种算法需要遍历数组两次,最好的情况也要遍历一次,且如果两个元素相同则不会进行交换,也没有申请额外的内存空间。</p><p>性质:</p><p>平均时间复杂度:O(n^2)</p><p>最好情况时间复杂度:O(n)</p><p>最坏情况时间复杂度:O(n^2)</p><p>稳定排序</p><p>原地排序</p></blockquote><h2 id="选择排序"><a href="#选择排序" class="headerlink" title="选择排序"></a>选择排序</h2><p>算法步骤</p><ol><li>在未排序数组中找到最小的那个元素,将它和数组第一个元素交换位置(如果第一个元素就是最小元素那么它就和自己交换)。</li><li>在剩下的元素中找到最小元素,和数组第二个元素交换位置。</li><li>重复步骤,直到将整个数组排序。</li></ol><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span>[] selectSort(<span class="keyword">int</span>[] arr){</span><br><span class="line"> <span class="keyword">int</span> length=arr.length;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i=<span class="number">0</span>;i<length-<span class="number">1</span>;i++){</span><br><span class="line"> <span class="keyword">int</span> min=i;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j=i+<span class="number">1</span>;j<length;j++){</span><br><span class="line"> <span class="keyword">if</span> (arr[min]>arr[j]){</span><br><span class="line"> min=j;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">int</span> temp=arr[i];</span><br><span class="line"> arr[i]=arr[min];</span><br><span class="line"> arr[min]=temp;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> arr;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>代码执行的时间都花费在内层for循环中的比较语句和外层for循环里的交换语句。由于选择元素之后会发生交换操作,所以有可能把前面的元素交换到后面,不是稳定的排序。</p><p>性质:</p><p>平均时间复杂度:O(n^2)</p><p>最好情况时间复杂度:O(n^2)</p><p>最坏情况时间复杂度:O(n^2)</p><p>非稳定排序</p><p>原地排序</p></blockquote><h2 id="插入排序"><a href="#插入排序" class="headerlink" title="插入排序"></a>插入排序</h2><p>插入排序类似于打牌时整理牌的顺序,</p><p>算法步骤</p><ol><li>从数组第二个元素开始抽取。</li><li>把它与左边第一个元素比较,如果左边第一个元素比它大,则继续与左边第二个元素比较下去,直到遇到不比它大的元素,然后插到这个元素的右边。</li><li>继续选取第3,4,….n个元素,重复步骤 2 ,选择适当的位置插入</li></ol><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span>[] insertSort(<span class="keyword">int</span>[] arr){</span><br><span class="line"> <span class="keyword">int</span> length=arr.length;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i=<span class="number">1</span>;i<length;i++){</span><br><span class="line"> <span class="keyword">int</span> temp=arr[i];</span><br><span class="line"> <span class="keyword">int</span> k=i-<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span> (k>=<span class="number">0</span>&&arr[k]>temp){</span><br><span class="line"> k--;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">int</span> j = i ; j > k + <span class="number">1</span>; j--) {</span><br><span class="line"> arr[j] = arr[j-<span class="number">1</span>];</span><br><span class="line"> }</span><br><span class="line"> arr[k+<span class="number">1</span>]=temp;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> arr;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>在比较的时候,如果两个数相等,不会进行移动,所以是稳定的</p><p>性质:</p><p>平均时间复杂度:O(n^2)</p><p>最好情况时间复杂度:O(n)</p><p>最坏情况时间复杂度:O(n^2)</p><p>稳定排序</p><p>原地排序</p></blockquote><h2 id="归并排序"><a href="#归并排序" class="headerlink" title="归并排序"></a>归并排序</h2><p>学习归并排序,我们需要理解分治的思想,那什么是分治呢—<strong>分而治之</strong></p><blockquote><p>一个公司有几百、几千人,全部归老板一个人管理肯定不行,那就需要把那么多号人分开来管理。</p><p>每个部门选出一个部长,管理他们部门的所有人;部门里面再选出几个小组长,管理小组成员。</p><p>这样老板把部长管理好,部长把小组长管理好,这不就把全部员工管理好了吗。</p></blockquote><p>再说回算法,所谓归并就是将待排数组分成前后两半排好序,再把排好序的序列合并成一个有序序列。</p><p>先是分,对数组不断的分,一直分到只有一个元素的时候,这个时候就不治而治了(一个元素认为它有序)</p><p>对于合并,只需要不断通过比较取出两个数组中比较小的那一个,放在一个辅助数组中,直到把两个有序数组中的元素取完。</p><p>算法步骤:</p><p>通过递归的方法将大的数组一直分割,直到数组的大小为1,此时只有一个元素,那么该数组就是有序的,之后再把两个数组大小为1的合并成一个大小为2的,两个数组大小为2的合并成一个大小为4的….. 直到全部小的数组合并起来。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span>[] sort(<span class="keyword">int</span>[] arr,<span class="keyword">int</span> left,<span class="keyword">int</span> right){</span><br><span class="line"> <span class="keyword">if</span>(left<right){</span><br><span class="line"> <span class="keyword">int</span> mid=(left+right)/<span class="number">2</span>;</span><br><span class="line"> arr=sort(arr,left,mid);</span><br><span class="line"> arr=sort(arr,mid+<span class="number">1</span>,right);</span><br><span class="line"> mergeSort(arr,left,mid,right);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> arr;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">mergeSort</span><span class="params">(<span class="keyword">int</span>[] arr,<span class="keyword">int</span> left,<span class="keyword">int</span> mid,<span class="keyword">int</span> right)</span></span>{</span><br><span class="line"> <span class="keyword">int</span>[] temp=<span class="keyword">new</span> <span class="keyword">int</span>[right - left + <span class="number">1</span>];</span><br><span class="line"> <span class="keyword">int</span> i=left;</span><br><span class="line"> <span class="keyword">int</span> j=mid+<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">int</span> k=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span>(i<=mid&&j<=right){</span><br><span class="line"> <span class="keyword">if</span> (arr[i]<arr[j]){</span><br><span class="line"> temp[k++]=arr[i++];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> temp[k++]=arr[j++];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span>(i<=mid){</span><br><span class="line"> temp[k++]=arr[i++];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">while</span> (j<=right){</span><br><span class="line"> temp[k++]=arr[j++];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (i=<span class="number">0</span>;i<k;i++){</span><br><span class="line"> arr[left++]=temp[i];</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><blockquote><p>性质:</p><p>平均时间复杂度:O(nlogn)</p><p>最好情况时间复杂度:O(nlogn)</p><p>最坏情况时间复杂度:O(nlogn)</p><p>稳定排序</p><p>非原地排序</p></blockquote><h2 id="堆排序"><a href="#堆排序" class="headerlink" title="堆排序"></a>堆排序</h2><p>在学习<strong>堆排序</strong>之前,我们首先要知道什么是<strong>堆</strong>。</p><p>堆的特点是堆顶的元素是一个最值,大顶堆的堆顶是最大值,小顶堆则是最小值。</p><p>算法步骤</p><ol><li>把未排序数组构建成大顶堆(如果想要是从大到小排列就构建小顶堆)。</li><li>把第堆顶的元素与最后一个元素交换,因为交换之后破坏了堆的特性,再把剩余的元素再次构成一个大顶堆。</li><li>重复第2步直到剩余的元素只有一个的时候,此时的数组就是有序的了。</li></ol><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">static</span> <span class="keyword">int</span>[] heapSort(<span class="keyword">int</span>[] arr){</span><br><span class="line"> <span class="keyword">int</span> length=arr.length;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i=(length-<span class="number">2</span>)/<span class="number">2</span>;i>=<span class="number">0</span>;i--){</span><br><span class="line"> downAdjust(arr,i,length-<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i=length-<span class="number">1</span>;i><span class="number">0</span>;i--){</span><br><span class="line"> <span class="keyword">int</span> temp=arr[i];</span><br><span class="line"> arr[i]=arr[<span class="number">0</span>];</span><br><span class="line"> arr[<span class="number">0</span>]=temp;</span><br><span class="line"> downAdjust(arr,<span class="number">0</span>,i-<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> arr;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">downAdjust</span><span class="params">(<span class="keyword">int</span>[] arr,<span class="keyword">int</span> parent,<span class="keyword">int</span> length)</span></span>{</span><br><span class="line"> <span class="keyword">int</span> temp=arr[parent];</span><br><span class="line"> <span class="keyword">int</span> child=parent*<span class="number">2</span>+<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">while</span>(child<=length){</span><br><span class="line"> <span class="keyword">if</span> (child+<span class="number">1</span><=length&&arr[child]<arr[child+<span class="number">1</span>]){</span><br><span class="line"> child++;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (arr[child]<=temp){</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> arr[parent]=arr[child];</span><br><span class="line"> parent=child;</span><br><span class="line"> child=parent*<span class="number">2</span>+<span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> arr[parent]=temp;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><blockquote><p>性质:</p><p>平均时间复杂度:O(nlogn)</p><p>最好情况时间复杂度:O(nlogn)</p><p>最坏情况时间复杂度:O(nlogn)</p><p>非稳定排序</p><p>原地排序</p></blockquote><h2 id="快速排序"><a href="#快速排序" class="headerlink" title="快速排序"></a>快速排序</h2><ul><li>用第一个元素充当主元</li><li>i = left + 1,j = right。然后让 i 和 j 从数组的两边向中间扫描</li><li>i 向右遍历的过程中,如果遇到大于或等于主元的元素时,则停止移动,j向左遍历的过程中,如果遇到小于或等于主元的元素则停止移动。</li><li>当i和j都停止移动时,如果这时i < j,则交换 i, j 所指向的元素。此时 i < j,交换8和3</li><li>然后继续向中间遍历,直到i >= j。</li><li>此时i >= j,分割结束。最后在把主元与 j 指向的元素交换(当然,与i指向的交换也行)、</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></pre></td><td class="code"><pre><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span>[] quickSort(<span class="keyword">int</span>[] arr, <span class="keyword">int</span> left, <span class="keyword">int</span> right) {</span><br><span class="line"> <span class="keyword">if</span> (left < right) {</span><br><span class="line"> <span class="comment">//获取中轴元素所处的位置</span></span><br><span class="line"> <span class="keyword">int</span> mid = partition(arr, left, right);</span><br><span class="line"> <span class="comment">//进行分割</span></span><br><span class="line"> arr = quickSort(arr, left, mid - <span class="number">1</span>);</span><br><span class="line"> arr = quickSort(arr, mid + <span class="number">1</span>, right);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> arr;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">方法二:双向扫描</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">partition</span><span class="params">( <span class="keyword">int</span>[] arr, <span class="keyword">int</span> left, <span class="keyword">int</span> right)</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="keyword">int</span> pivot = arr[left];</span><br><span class="line"> <span class="keyword">int</span> i = left + <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">int</span> j = right;</span><br><span class="line"> <span class="keyword">while</span>(<span class="keyword">true</span>)</span><br><span class="line"> { </span><br><span class="line"> <span class="comment">//向右遍历扫描</span></span><br><span class="line"> <span class="keyword">while</span>(i <= j && arr[i] <= pivot) i++;</span><br><span class="line"> <span class="comment">//向左遍历扫描</span></span><br><span class="line"> <span class="keyword">while</span>(i <= j && arr[j] => pivot) j--;</span><br><span class="line"> <span class="keyword">if</span>(i >= j)</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="comment">//交换</span></span><br><span class="line"> <span class="keyword">int</span> temp = arr[i];</span><br><span class="line"> arr[i] = arr[j];</span><br><span class="line"> arr[j] = temp;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//把arr[j]和主元交换</span></span><br><span class="line"> arr[left] = arr[j];</span><br><span class="line"> arr[j] = povit;</span><br><span class="line"> <span class="keyword">return</span> j;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>最坏时间复杂度是O(n2)</p><p>最好时间复杂度是O(nlogn)</p><p>平均时间复杂度O(nlogn)</p><p>空间复杂度:O(logn)</p><p>之所以说它快,是因为它不像归并排序那样,需要额外的辅助空间,而且在分割调整的时候,不像归并排序那样,元素还要在辅助数组与源数组之间来回复制。</p>]]></content>
<summary type="html"><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>十大排序算法是每个程序员都必须掌握的,目前自己熟悉的算法有冒泡排序,快速排序,选择排序,归并排序。从今天起开始从头学习排序算法,把学习过的复习一遍,加深印象;没有学习过的争取一次学会。</p>
<h1 id="术语"><a href="#术语" class="headerlink" title="术语"></a>术语</h1><p>排序算法中也有“术语”,想要学习排序算法首先需要理解这些术语的意思。</p>
<ul>
<li>稳定排序:有两个相同的数a和b,在排序之前a在b的前面,排序之后a仍然在b的前面,则为稳定排序。</li>
<li>非稳定排序:有两个相同的数a和b,在排序之前a在b的前面,排序之后a可能不在b的前面,则为非稳定排序。</li>
<li>原地排序:排序过程中不申请多余的空间,只利用原来存储待排数据的存储空间进行比较和交换。</li>
<li>非原地排序:需要利用额外的空间来辅助排序。</li>
</ul></summary>
<category term="算法" scheme="http://www.jonyonwzj.top/categories/%E7%AE%97%E6%B3%95/"/>
<category term="算法" scheme="http://www.jonyonwzj.top/tags/%E7%AE%97%E6%B3%95/"/>
</entry>
<entry>
<title>JMM</title>
<link href="http://www.jonyonwzj.top/2021/04/22/JMM/"/>
<id>http://www.jonyonwzj.top/2021/04/22/JMM/</id>
<published>2021-04-22T11:44:34.000Z</published>
<updated>2021-05-26T13:05:01.101Z</updated>
<content type="html"><![CDATA[<h1 id="JMM-JavaMemoryModle"><a href="#JMM-JavaMemoryModle" class="headerlink" title="JMM(JavaMemoryModle)"></a>JMM(JavaMemoryModle)</h1><p>JMM:Java内存模型,是Java虚拟机规范中所定义的一种的内存模型,Java内存模型是标准化的,屏蔽掉了底层不同计算机的区别。</p><a id="more"></a><p>在了解JMM之前先了解现代计算机内存模型:</p><p>我们的计算机在执行程序时,指令是在CPU中执行的,而数据需要存储在内存中,而执行一个程序就需要指令和数据打交道。</p><p>在早期,CPU和内存的的速度是差不多的。但随着时代的发展,CPU的指令速度越来越快,而内存的存取速度却几乎没有改变,这就导致在现代计算机中,CPU的指令速度远超内存的存取速度。为了解决这个问题,现代计算机系统不得不加入一层读写速度尽可能接近CPU运算速度的高速缓存(cache)来作为内存和CPU之间的缓冲。</p><p>将需要处理的数据复制到缓存中,让运算能够快速进行,当运算结束后再从缓存同步回内存中,这样处理器就无需等待缓慢的内存读写了。</p><p>基于高速缓存的内存交互很好的解决了CPU与内存的速度矛盾,但同时也带来了一个新的问题:<strong>缓存一致性</strong>。</p><p>在多处理器系统中,每个处理器都有自己的高速缓存,而他们又共享同一内存。</p><p><img src="/2021/04/22/JMM/image-20210422210331526.png" alt="image-20210422210331526"></p><h1 id="JMM"><a href="#JMM" class="headerlink" title="JMM"></a>JMM</h1><p>Java内存模型,描述了Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存,和从内存中读取变量这样的底层细节。</p><p>JMM有以下规定:</p><ul><li>所有的共享变量都是基于主内存的,这里所说的变量是实例变量和类变量,不包含局部变量,因为局部变量是线程私有的,因此不存在竞争问题。</li><li>每一个线程还存在自己的工作内存,线程的工作内存,保留了被线程使用的变量的工作副本。</li><li>线程对变量的所有操作都必须在工作内存中完成,而不能直接读写主内存中的变量。</li><li>不同线程之间也不能直接访问对方工作内存中的变量,线程间变量的值的传递需要通过主内存中转来完成。</li></ul><p><img src="/2021/04/22/JMM/image-20210422210339295.png" alt="image-20210422210339295"></p><p>多个线程访问进程中的某个共享内存,且这个多线程分别在不同的CPU上执行,则每个CPU都会在各自的Cache中保留一份共享内存的缓存。由于多CPU是可以并行的,可能会出现多个线程同时写各自缓存的情况,而各自的Cache之间的数据就有可能不一样。</p><p>了解了JMM的这些问题,再来看看一段Demo的代码</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">test14</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> A a = <span class="keyword">new</span> A();</span><br><span class="line"> a.start();</span><br><span class="line"> <span class="keyword">for</span> (;;){</span><br><span class="line"> <span class="keyword">if</span> (a.isFlag()){</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><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span> <span class="keyword">extends</span> <span class="title">Thread</span></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">boolean</span> flag=<span class="keyword">false</span>;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isFlag</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> flag;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> flag=<span class="keyword">true</span>;</span><br><span class="line"> System.out.println(<span class="string">"flag="</span>+flag);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>运行这段代码会发现,永久都不会输出<strong>我出来了!!!</strong>,这是因为可见性问题的存在。</p><p>可见性问题的解释:</p><blockquote><p>首先要将变量从主内存拷贝进自己的工作空间,然后对变量进行操作,操作完成再将变量写进主内存,不能直接操作主内存的变量,各个线程中的工作内存存储着主内存中的变量拷贝副本,因此不同的线程无法访问对方的工作内存。</p><p>简单来说就是,多个线程操作一个变量时,当一个先执行的线程改动了这个变量的值时,应当通知其他线程变量的值已经被改动了,原来的值将不可用。</p><p>在这个Demo中,有一个线程先修改了flag的值,可是主线程并不知道flag的值已经被修改了,这时就需要有一个机制来即使通知其他线程flag值已经被修改过,通知完后,其他线程就从主内存中重新去拿值,再在自己的工作内存空间去修改值。</p></blockquote><h1 id="可见性的解决方案"><a href="#可见性的解决方案" class="headerlink" title="可见性的解决方案"></a>可见性的解决方案</h1><h2 id="加锁"><a href="#加锁" class="headerlink" title="加锁"></a>加锁</h2><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">synchronized</span>(a){</span><br><span class="line"> <span class="keyword">for</span> (;;){</span><br><span class="line"> <span class="keyword">if</span> (a.isFlag()){</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></pre></td></tr></table></figure><p>为什么加锁可以解决可见性问题呢?</p><p>因为某一个线程进入synchronized代码块前后,线程会获得锁,清空工作内存,从主内存拷贝最新的变量到工作内存成为副本,执行代码后会将修改后的副本的值刷新到主内存中,线程才会释放锁。</p><p>而获取不到锁的线程会循环等待,所以变量的值一直都是最新的。</p><h2 id="volatile修饰共享变量"><a href="#volatile修饰共享变量" class="headerlink" title="volatile修饰共享变量"></a>volatile修饰共享变量</h2><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span> <span class="keyword">extends</span> <span class="title">Thread</span></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">volatile</span> <span class="keyword">boolean</span> flag=<span class="keyword">false</span>;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isFlag</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> flag;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> flag=<span class="keyword">true</span>;</span><br><span class="line"> System.out.println(<span class="string">"flag="</span>+flag);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>volatile做了什么?</p><blockquote><p>每个线程操作数据的时候会把数据从主内存读取到自己的工作内存,如果他操作了数据并且写回了,其它线程已经读取的变量副本就会失效了,需要的数据又要从主内存中去读取了。</p><p>volatile保证不同的线程对共享变量操作的可见性,也就是说一个线程修改了volatile修饰的变量,当修改写回主内存时,另一个线程能立即看到变量的最新值。</p></blockquote><p>但这里又会出现一个问题,当多个CPU的运算任务都涉及到同一块主内存区域时,将可能导致各自的缓存数据不一致,如果发生了这种情况,同步回主内存时以谁的缓存数据为准呢?</p><p>为了解决<strong>一致性</strong>的问题,需要各个处理器访问缓存时都遵守一些协议,在读写时要根据协议来进行操作。</p><h1 id="MES-缓存一致性协议"><a href="#MES-缓存一致性协议" class="headerlink" title="MES(缓存一致性协议)"></a>MES(缓存一致性协议)</h1><p>当CPU写数据时,如果发现操作的变量是共享变量,会发出信号通知其它CPU将该变量的缓存设置为无效状态,因此当其它CPU读取这个变量时,会发现自己缓存中该变量是无效的,那么他就会从内存中重新读取。</p><p>如何发现数据是否失效?</p><p><strong>嗅探</strong></p><blockquote><p>每个处理器通过嗅探在总线上传播的数据来检查⾃⼰缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存里。</p></blockquote><p>但嗅探也有缺点。</p><p><strong>总线风暴</strong></p><blockquote><p>由于Volatile的MESI缓存⼀致性协议,需要不断的从主内存嗅探和cas不断循环,无效交互会导致总线带宽达到峰值。</p><p>所以不要大量使用Volatile,至于什么时候去使用Volatile什么时候使用锁,根据场景区分。</p></blockquote><h1 id="禁止指令重排"><a href="#禁止指令重排" class="headerlink" title="禁止指令重排"></a>禁止指令重排</h1><p>为了提高性能,编译器和处理器常常会对既定的代码执行顺序进行指令重排。</p><p>一般重排序可分为以下三种:</p><ul><li><p>编译器优化的重排序。编译器在不改变单线程语义的前提下,可以重新安排语句的执行顺序;</p></li><li><p>指令级并行的重排序。现代处理器采用了指令级并行技术来将多条指令重叠执行。如果不存在数据</p><p>依赖性,处理器可以改变语句对应机器指令的执行顺序</p><p>内存系统的重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱</p><p>执行的</p></li></ul><h2 id="a-if-serial"><a href="#a-if-serial" class="headerlink" title="a-if-serial"></a>a-if-serial</h2><p>不管怎么重排序,单线程下的执行结果不能被改变。</p><h2 id="内存屏障"><a href="#内存屏障" class="headerlink" title="内存屏障"></a>内存屏障</h2><p>为了保证volatile不会被执行重排序,java编译器会在生成指令系列时在适当的位置会插入内存屏障指令来禁止特定类型的处理器重排序</p><p>需要注意的是:volatile的写是在前面和后面分别插入内存屏障,而volatile读是在后面插入两个内存屏障。</p><h1 id="无法保证原子性"><a href="#无法保证原子性" class="headerlink" title="无法保证原子性"></a>无法保证原子性</h1><p>volatile无法保证原子性,原子性就是:要么完全成功,要么完全失败。</p><p>假设现在有N个线程对同⼀个变量进行累加也是没办法保证结果是对的,因为读写这个过程并不是原子性的</p><p>要解决也简单,要么用原子类,比如AtomicInteger,要么加锁</p><h1 id="volatile与synchronized的区别"><a href="#volatile与synchronized的区别" class="headerlink" title="volatile与synchronized的区别"></a>volatile与synchronized的区别</h1><ul><li>volatile只能修饰实例变量和类变量,synchronized可以修饰方法,代码块。</li><li>volatile保证数据可见性,但是不保证原子性(多线程进行写操作,不保证线程安全)。而synchronized是一种互斥、排他机制。volatile用于禁止指令重排,可以解决单例双重检查对象初始化代码执行乱序的问题。</li><li>volatile可以看做是轻量版的synchronized,volatile不保证原子性,但是如果是对⼀个共享变量进行多个线程的赋值,而没有其他的操作,那么就可以用volatile来代替synchronized,因为赋值本身是有原子性的,而volatile又保证了可见性,所以就可以保证线程安全了。</li></ul>]]></content>
<summary type="html"><h1 id="JMM-JavaMemoryModle"><a href="#JMM-JavaMemoryModle" class="headerlink" title="JMM(JavaMemoryModle)"></a>JMM(JavaMemoryModle)</h1><p>JMM:Java内存模型,是Java虚拟机规范中所定义的一种的内存模型,Java内存模型是标准化的,屏蔽掉了底层不同计算机的区别。</p></summary>
<category term="多线程" scheme="http://www.jonyonwzj.top/categories/%E5%A4%9A%E7%BA%BF%E7%A8%8B/"/>
<category term="JAVA基础" scheme="http://www.jonyonwzj.top/tags/JAVA%E5%9F%BA%E7%A1%80/"/>
</entry>
<entry>
<title>锁</title>
<link href="http://www.jonyonwzj.top/2021/04/11/%E9%94%81/"/>
<id>http://www.jonyonwzj.top/2021/04/11/%E9%94%81/</id>
<published>2021-04-11T05:59:41.000Z</published>
<updated>2021-05-20T06:08:03.468Z</updated>
<content type="html"><![CDATA[<h1 id="锁"><a href="#锁" class="headerlink" title="锁"></a>锁</h1><h2 id="什么是锁?"><a href="#什么是锁?" class="headerlink" title="什么是锁?"></a>什么是锁?</h2><p>在计算机科学中,锁或互斥是一种同步机制,用于在有许多线程执行的情况下强制对资源进行访问限制。锁旨在强制实施互斥排他、并发控制策略。</p><p>锁通常需要硬件支持才能有效实施。这种支持通常采用一个或多个原子指令的形式,如“test-and-set”、“fetch-and-add”、“compare-and-swap”。这些指令允许单个进程测试锁是否空闲,如果空闲,则通过单个原子操作获取锁。</p><a id="more"></a><h1 id="Java锁的种类"><a href="#Java锁的种类" class="headerlink" title="Java锁的种类"></a>Java锁的种类</h1><ul><li>乐观锁/悲观锁</li><li>独享锁/共享锁</li><li>互斥锁/读写锁</li><li>可重入锁</li><li>公平锁/非公平锁</li><li>分段所</li><li>偏向锁/轻量级锁/重量级锁</li><li>自旋锁</li></ul><p><strong>以上这些分类并不全是指锁的状态,有的指锁的特性,有的指锁的设计</strong></p><h2 id="乐观锁-悲观锁"><a href="#乐观锁-悲观锁" class="headerlink" title="乐观锁/悲观锁"></a>乐观锁/悲观锁</h2><p>乐观锁和悲观锁并不特指两种类型的锁,是一种广义上的概念,体现了看待线程的不同角度。在Java和数据库中都有此概念对应的实际应用。</p><h3 id="乐观锁"><a href="#乐观锁" class="headerlink" title="乐观锁"></a>乐观锁</h3><p>乐观锁:一种非常乐观的锁,他认为自己在使用数据的时候不会有别的线程来修改,于是每次都不加锁,但是在更新的时候会判断一下在此期间有没有别的线程更新了这个数据(一般使用数据版本机制和CAS操作)。如果这个数据没有被更新,则将当前线程的数据成功写入;如果数据已被其他线程更新,一般会选择报错或重试3-5次。Java中,java.util.concurrent.atomic包下的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。</p><h4 id="数据版本机制"><a href="#数据版本机制" class="headerlink" title="数据版本机制"></a>数据版本机制</h4><p>数据版本机制</p><p>实现数据版本机制一般有两种,一种是使用版本号,一种是使用时间戳。以版本号方式为例。</p><p>在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version+1.当线程要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,如刚才读取到的version值与当前的version值相同才能完成更新,否则重试直到成功。</p><h4 id="CAS"><a href="#CAS" class="headerlink" title="CAS"></a>CAS</h4><p>CAS(compare and swap–比较并交换)</p><p>是一种无锁算法,在不使用锁的情况下实现线程之间的变量同步。</p><p>CAS算法涉及到三个操作数:</p><ul><li>V:需要读写的内存值</li><li>A:进行比较的值</li><li>B:要写入的新值</li></ul><p>当且仅当 V 的值等于 A 时,CAS通过原子方式用新值B来更新V的值(“比较+更新”整体是一个原子操作),否则不会执行任何操作。一般情况下,“更新”是一个不断重试的操作。</p><blockquote><p>举个例子:现在一个线程要修改数据库的name,修改前会先去数据库查name的值,这时name=“jonyon”,拿到值后准备修改成name=“wzj”,在修改之前我们先判断一下,原来的name是不是等于“jonyon”,如果被其它的线程修改就会发现name不等于“jonyon”了,我们就不进行操作,如果原来的值还是“jonyon”,我们就把name修改为“wzj”</p></blockquote><p>CAS缺点:ABA问题、CPU开销问题、只能保证一个共享变量原子操作问题</p><p>ABA问题:狸猫换太子,内存中的值虽然和进行比较的值一样,但他已经被修改过一次并且又修改了回来。(可以通过加版本号的方式解决)</p><p>CPU开销问题:如果CAS操作长时间不成功,会导致一直自旋,相当于死循环,CPU压力会很大</p><p>只能保证一个共享变量原子操作问题:CAS操作单个共享变量的时候可以保证原⼦的操作,多个变量就不行了,JDK 5之后 AtomicReference可以⽤来保证对象之间的原⼦性,就可以把多个对象放⼊CAS中操作。</p><h3 id="悲观锁"><a href="#悲观锁" class="headerlink" title="悲观锁"></a>悲观锁</h3><p>悲观锁:一种非常悲观的锁,他总是假设最坏的情况,认为自己在使用数据的时候一定会有别的线程来修改,于是在获取数据时都会先加锁。Java中,Synchronized关键字和Lock的实现类都是悲观锁。</p><h3 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h3><blockquote><p>乐观锁在Java中的使用,就是无锁编程,采用的是CAS算法,典型的例子就是原子类,通过CAS自旋实现原子操作的更新。</p><p>悲观锁在Java中的使用,就是利用各种锁。</p></blockquote><p>使用场景</p><ul><li>乐观锁适合读操作多的场景,不加锁能够使其读操作性能大幅提升。</li><li>悲观锁适合写操作多的场景,先加锁能够保证写操作时的数据正确。</li></ul><h2 id="独享锁-共享锁"><a href="#独享锁-共享锁" class="headerlink" title="独享锁/共享锁"></a>独享锁/共享锁</h2><p>独享锁和共享锁同样是一种概念,是通过AQS来实现的,通过实现不同的方法,来实现独享或者共享。</p><h3 id="独享锁"><a href="#独享锁" class="headerlink" title="独享锁"></a>独享锁</h3><p>独享锁也叫排他锁,是指锁一次只能被一个线程所持有。如果线程T对数据A加上排他锁后,则其他线程不能再对A加任何类型的锁。获得排他锁的线程即能读数据也能修改数据。</p><h3 id="共享锁"><a href="#共享锁" class="headerlink" title="共享锁"></a>共享锁</h3><p>共享锁是指该锁能被多个线程所持有。如果线程T对数据A加上共享锁后,其他线程只能对A再加共享锁,不能加排他锁。只能读数据,不能修改数据。</p><h2 id="互斥锁-读写锁"><a href="#互斥锁-读写锁" class="headerlink" title="互斥锁/读写锁"></a>互斥锁/读写锁</h2><p>互斥锁/读写锁就是独享锁/共享锁具体的实现</p><p>互斥锁在java中具体的实现就是ReentrantLock</p><p>读写锁在java中具体的实现就是ReadWriteLock</p><h2 id="可重入锁"><a href="#可重入锁" class="headerlink" title="可重入锁"></a>可重入锁</h2><p>可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁。</p><p>ReentrantLock和Synchronized都是可重入锁。</p><p>可重入锁的优点是可一定程度避免死锁。</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">A</span><span class="params">()</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"方法A执行"</span>);</span><br><span class="line"> B();</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">B</span><span class="params">()</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"方法B执行"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> A();</span><br><span class="line"> }</span><br><span class="line">输出结果:</span><br><span class="line">方法A执行</span><br><span class="line">方法B执行 </span><br></pre></td></tr></table></figure><p>在上面的例子中,两个方法都是被synchronized关键字修饰的,A中调用B方法。因为synchronized是可重入锁,所以同一个线程在调用B方法时可以直接获得当前对象的锁,进入B方法进行操作。</p><p>如果是不可重入锁,那么当前线程在调用B方法前,需要将执行A方法时获取的锁释放掉,但实际上该对象锁已被当前线程所持有,无法释放,所以会出现死锁。</p><h2 id="公平锁-非公平锁"><a href="#公平锁-非公平锁" class="headerlink" title="公平锁/非公平锁"></a>公平锁/非公平锁</h2><p>ReentrantLock:默认是非公平锁。通过AQS实现线程调度(可以通过构造函数指定该锁是否是公平锁),优点在于吞吐量比公平锁大。</p><p>Synchronized:非公平锁。由于不是通过AQS实现线程调度,所以无法变成公平锁。</p><h3 id="公平锁"><a href="#公平锁" class="headerlink" title="公平锁"></a>公平锁</h3><p>公平锁是指多个线程按照申请锁的顺序来依次获取锁。</p><p>线程直接进入队列排队,队列中的第一个线程才能获得锁。</p><p>优点:</p><ul><li>等待锁的线程不会饿死</li></ul><p>缺点:</p><ul><li>吞吐效率低于非公平锁</li><li>等待队列中除第一个线程以外的所有线程都会阻塞</li><li>CPU唤醒阻塞线程的开销比非公平锁大</li></ul><h3 id="非公平锁"><a href="#非公平锁" class="headerlink" title="非公平锁"></a>非公平锁</h3><p>非公平锁是指多个线程获取锁的顺序并不是按照锁申请的顺序来的。有可能造成优先级反转或者饥饿现象。</p><p>多个线程加锁时直接尝试获取锁,获取不到才会到等待队列的队尾等待。如果此时锁刚好可用,那么这个线程可以无阻塞直接获取到锁,所以非公平锁有可能会出现后申请锁的线程先得到锁的场景。</p><p>优点:</p><ul><li>减少唤醒线程的开销</li><li>整体吞吐效率高</li></ul><p>缺点</p><ul><li>处于等待队列中的线程可能会饿死,或者等很久才获得锁。</li></ul><h2 id="分段锁"><a href="#分段锁" class="headerlink" title="分段锁"></a>分段锁</h2><p>分段锁是一种锁的设计,并不是具体的一种锁。</p><p>对于JDK1.8之前的ConcurrentHashMap来说,其并发的实现就是通过分段锁的形式来实现高效的并发操作。</p><h2 id="无锁-偏向锁-轻量级锁-重量级锁"><a href="#无锁-偏向锁-轻量级锁-重量级锁" class="headerlink" title="无锁/偏向锁/轻量级锁/重量级锁"></a>无锁/偏向锁/轻量级锁/重量级锁</h2><p>这四种锁是指锁的状态,专门针对synchronized的。</p><p>在Java5通过锁升级的机制来实现高效synchronized,这几种锁的状态是通过对象监视器在对象头中的字段来表明的。 </p><h3 id="无锁"><a href="#无锁" class="headerlink" title="无锁"></a>无锁</h3><p>没有对资源进行加锁,所有线程都能访问并修改同一个资源,但只有一个线程能够成功。</p><h3 id="偏向锁"><a href="#偏向锁" class="headerlink" title="偏向锁"></a>偏向锁</h3><p>一段同步代码一直被一个线程所访问,那么该线程就会自动获取锁,降低获取锁的代价。</p><h3 id="轻量级锁"><a href="#轻量级锁" class="headerlink" title="轻量级锁"></a>轻量级锁</h3><p>当锁是偏向锁的时候,被另外的线程所访问,偏向锁就会升级成轻量级锁。其他线程会通过自旋的形式尝试获取锁,不会阻塞从而提高性能。</p><h3 id="重量级锁"><a href="#重量级锁" class="headerlink" title="重量级锁"></a>重量级锁</h3><p>当锁是轻量级锁的时候,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数还没有获得锁的时候就会进入阻塞,该锁膨胀为重量级锁,让其它申请的线程进入阻塞,性能降低</p><h2 id="自旋锁"><a href="#自旋锁" class="headerlink" title="自旋锁"></a>自旋锁</h2><p>当一个线程在获取锁的时候,如果该锁已经被其他线程获取,那么该线程将循环等待,然后不断判断该锁是否能被成功获取,直到获取到锁才会退出循环。这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU。</p>]]></content>
<summary type="html"><h1 id="锁"><a href="#锁" class="headerlink" title="锁"></a>锁</h1><h2 id="什么是锁?"><a href="#什么是锁?" class="headerlink" title="什么是锁?"></a>什么是锁?</h2><p>在计算机科学中,锁或互斥是一种同步机制,用于在有许多线程执行的情况下强制对资源进行访问限制。锁旨在强制实施互斥排他、并发控制策略。</p>
<p>锁通常需要硬件支持才能有效实施。这种支持通常采用一个或多个原子指令的形式,如“test-and-set”、“fetch-and-add”、“compare-and-swap”。这些指令允许单个进程测试锁是否空闲,如果空闲,则通过单个原子操作获取锁。</p></summary>
<category term="多线程" scheme="http://www.jonyonwzj.top/categories/%E5%A4%9A%E7%BA%BF%E7%A8%8B/"/>
<category term="JAVA基础" scheme="http://www.jonyonwzj.top/tags/JAVA%E5%9F%BA%E7%A1%80/"/>
</entry>
<entry>
<title>ThreadLocal</title>
<link href="http://www.jonyonwzj.top/2021/04/09/ThreadLocal/"/>
<id>http://www.jonyonwzj.top/2021/04/09/ThreadLocal/</id>
<published>2021-04-09T06:29:37.000Z</published>
<updated>2021-04-11T05:54:11.468Z</updated>
<content type="html"><![CDATA[<h1 id="ThreadLocal"><a href="#ThreadLocal" class="headerlink" title="ThreadLocal"></a>ThreadLocal</h1><p>多线程访问同一个共享变量的时候容易出现并发问题,为了保证线程安全,使用者在访问共享变量的时候需要进行额外的同步措施。</p><p>我们都知道<strong>加锁</strong>这种同步方式,<strong>ThreadLocal</strong>是除了加锁之外的一种规避多线程访问出现线程不安全的方法。</p><a id="more"></a><h2 id="ThreadLocal简介"><a href="#ThreadLocal简介" class="headerlink" title="ThreadLocal简介"></a>ThreadLocal简介</h2><p>ThreadLocal类主要解决的就是让每个线程都绑定自己的值,在创建一个变量后,如果每个线程对其进行访问的时候都是访问的线程自己的变量,就不会存在线程不安全问题。</p><p>ThreadLocal类是由JDK包提供的,它提供线程本地变量,如果创建一个ThreadLocal变量,那么访问这个变量的每一个线程都会有这个变量的本地副本,在实际进行多线程操作的时候,操作的是自己本地内存中的变量,从而规避了线程安全问题。</p><h2 id="ThreadLocal示例"><a href="#ThreadLocal示例" class="headerlink" title="ThreadLocal示例"></a>ThreadLocal示例</h2><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> dxc;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">test03</span> </span>{</span><br><span class="line"> <span class="keyword">static</span> ThreadLocal<String> local=<span class="keyword">new</span> ThreadLocal<>();</span><br><span class="line"> <span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">print</span><span class="params">(String s)</span></span>{</span><br><span class="line"> System.out.println(s+<span class="string">":"</span>+local.get());</span><br><span class="line"> local.remove();</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> local.set(<span class="string">"local1"</span>);</span><br><span class="line"> print(<span class="string">"T1"</span>);</span><br><span class="line"> System.out.println(<span class="string">"after remove:"</span>+local.get());</span><br><span class="line"> }</span><br><span class="line"> }).start();</span><br><span class="line"> <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> local.set(<span class="string">"local2"</span>);</span><br><span class="line"> print(<span class="string">"T2"</span>);</span><br><span class="line"> System.out.println(<span class="string">"after remove:"</span>+local.get());</span><br><span class="line"> }</span><br><span class="line"> }).start();</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">T1:local1</span><br><span class="line">after remove:<span class="keyword">null</span></span><br><span class="line">T2:local2</span><br><span class="line">after remove:<span class="keyword">null</span></span><br></pre></td></tr></table></figure><h2 id="ThreadLocal原理"><a href="#ThreadLocal原理" class="headerlink" title="ThreadLocal原理"></a>ThreadLocal原理</h2><blockquote><p>Thread类源码</p></blockquote><p><img src="/2021/04/09/ThreadLocal/image-20210409154143633.png" alt="image-20210409154143633"></p><p>从源码可以看出ThreadLocal有一个threadLocals和inheritableThreadLocals变量,他们都是ThreadLocalMap类型的变量。</p><p>ThreadLocalMap实际上类似于一个HashMap,默认情况下两个变量都为null,只有当线程调用ThreadLocal的set和get才会创建它们。</p><p>实际上调用这两个方法时,我们调用的是ThreadLocalMap类的get和set方法</p><p><img src="/2021/04/09/ThreadLocal/image-20210409155137602.png" alt="image-20210409155137602"></p><p><img src="/2021/04/09/ThreadLocal/image-20210409155155228.png" alt="image-20210409155155228"></p><blockquote><p>结论:</p><p><strong>最终变量是放在了当前线程的ThreadLocalMap中,而不是ThreadLocal上,ThreadLocal可以理解为ThreadLocalMap的封装,传递了变量值。</strong></p><p>ThreadLocal类中可以通过Thread.currentThread()获取到当前线程对象后,直接通过getMap(Thread t)访问到该线程的ThreadLocalMap对象。</p><p><strong>ThreadLocal内部维护一个类似Map的ThreadLocalMap数据结构,Key为当前对象的Thread对象,值为Object对象。</strong></p><p><img src="/2021/04/09/ThreadLocal/image-20210409160120946.png" alt="image-20210409160120946"></p></blockquote><h2 id="ThreadLocal内存泄露问题"><a href="#ThreadLocal内存泄露问题" class="headerlink" title="ThreadLocal内存泄露问题"></a>ThreadLocal内存泄露问题</h2><ul><li>内存泄漏Memory leak:程序中<strong>已经动态分配的堆内存</strong>由于某种原因,<strong>程序未释放或者无法释放,造成系统内部的浪费</strong>,导致程序运行速度减缓甚至系统崩溃等严重后果,<strong>内存泄漏的堆积终将导致内存溢出</strong></li><li>内存溢出out of Memory:<strong>没有足够的内存</strong>提供申请者使用</li></ul><p><img src="/2021/04/09/ThreadLocal/image-20210409161351660.png" alt="image-20210409161351660"></p><p>ThreadLocalMap中使用的key为ThreadLocal的弱引用,而value是强引用。所以,如果ThreadLocal没有被外部强引用的情况下,在垃圾回收的时候,key会被清理掉。这样,ThreadLocalMap中就会出现key为null的Entry,如果不做任何措施,value永远无法被GC回收,这就可能会产生内存泄漏。</p><h3 id="如果key是强引用"><a href="#如果key是强引用" class="headerlink" title="如果key是强引用"></a>如果key是强引用</h3><ol><li>在业务代码中使用完ThreadLocal,ThreadLocal被回收</li><li>因为key是强引用,所以ThreadLocal无法被回收</li><li>在没有手动删除Entry并且当前线程依然在运行的前提下,Entry不会被回收</li></ol><p><strong>也就是说,ThreadLocal中的key使用了强引用是无法完全避免内存溢出的</strong></p><h3 id="如果key是弱引用"><a href="#如果key是弱引用" class="headerlink" title="如果key是弱引用"></a>如果key是弱引用</h3><ol><li>在业务代码中使用完ThreadLocal,ThreadLocal被回收</li><li>因为key是弱引用,所以ThreadLocal可以顺利被GC回收,key=null</li><li>在没有手动删除Entry并且当前线程依然在运行的前提下,value不会被回收,并且这个value永远不会被访问到</li></ol><p><strong>也就是说,ThreadLocal中的key使用了弱引用是无法完全避免内存溢出的</strong></p><h3 id="内存泄漏的真实原因"><a href="#内存泄漏的真实原因" class="headerlink" title="内存泄漏的真实原因"></a>内存泄漏的真实原因</h3><p>比较以上两种情况,我们可以发现,内存泄漏的发生跟ThreadLocal中的key是否使用弱引用没有关系</p><p>在内存泄漏的情况中,都有两个前提</p><ol><li>没有手动删除这个Entry</li><li>当前线程依旧在运行</li></ol><p><strong>ThreadLocal内存泄漏的根源是:由于ThreadLocalMap的的生命周期跟Thread一样长,如果没有手动删除(remove())对应的key,就会导致内存泄漏</strong></p><p>于是避免内存泄漏有两种方式:</p><ol><li>使用完ThreadLocal,手动调用remove(),方法删除对应的Entry</li><li>使用完ThreadLocal,当前的Thread也随之结束运行</li></ol><p>推荐使用第一种方式,第二种不好控制,特别是在使用线程池的时候,线程结束是不会销毁的</p>]]></content>
<summary type="html"><h1 id="ThreadLocal"><a href="#ThreadLocal" class="headerlink" title="ThreadLocal"></a>ThreadLocal</h1><p>多线程访问同一个共享变量的时候容易出现并发问题,为了保证线程安全,使用者在访问共享变量的时候需要进行额外的同步措施。</p>
<p>我们都知道<strong>加锁</strong>这种同步方式,<strong>ThreadLocal</strong>是除了加锁之外的一种规避多线程访问出现线程不安全的方法。</p></summary>
<category term="多线程" scheme="http://www.jonyonwzj.top/categories/%E5%A4%9A%E7%BA%BF%E7%A8%8B/"/>
<category term="JAVA基础" scheme="http://www.jonyonwzj.top/tags/JAVA%E5%9F%BA%E7%A1%80/"/>
</entry>
<entry>
<title>redis</title>
<link href="http://www.jonyonwzj.top/2021/02/10/redis/"/>
<id>http://www.jonyonwzj.top/2021/02/10/redis/</id>
<published>2021-02-10T15:08:15.000Z</published>
<updated>2021-04-02T08:53:30.733Z</updated>
<content type="html"><![CDATA[<h1 id="NoSQL概述"><a href="#NoSQL概述" class="headerlink" title="NoSQL概述"></a>NoSQL概述</h1><h2 id="为什么要用NoSQL"><a href="#为什么要用NoSQL" class="headerlink" title="为什么要用NoSQL"></a>为什么要用NoSQL</h2><p>现在是大数据时代,一般的数据库无法进行分析处理</p><ol><li><p>单机MySQL年代</p><p><img src="/2021/02/10/redis/image-20210130134059341.png" alt="image-20210130134059341"></p><p>90年代,一个基本的网站访问量一般不会太大,单个数据库完全足够</p><p>那个时候更多的是去使用静态网页html,服务器更本没有太大的压力</p><p>在这种情况下,整个网站的瓶颈是什么</p><p>1.数据量如果太大,一个机器放不下</p><p>2.数据的索引,300万条数据,一定需要创建索引(B+Tree),一个机器内存放不下</p><p>3.访问量,读写混合,一个服务器承受不了</p><p>只要出现以上三个情况之一,那么就需要升级</p><a id="more"></a></li><li><p>Memcached(缓存)+MySQL+垂直拆分(读写分离)</p><p>网站80%都是在读,每次到要去查寻数据库的话就十分麻烦,所以说我们希望减轻数据的压力,我们可以用缓存来保证效率</p><p>发展过程:优化数据结构和索引—>文件缓存(IO)—>Memcahed(当时最热门的技术)</p><p><img src="/2021/02/10/redis/image-20210130135120890.png" alt="image-20210130135120890"></p></li><li><p>分库分表+水平拆分+MySQL集群</p><p><img src="/2021/02/10/redis/image-20210130135926650.png" alt="image-20210130135926650"></p></li><li><p>如今(定位、热榜也是一种数据)</p><p>MySQL等关系型数据库不够用了,数据量很多,变化很快</p><p>MySQL有点使用他来存储一些比较大的文件、博客、图片,数据库表很大,效率就很低,如果有一种数据库来专门处理这种数据,MySQL压力就变得十分小(研究如何处理这种问题)大数据的IO压力下,表几乎没法更改</p></li><li><p>目前一个基本的互联网架构</p><p><img src="/2021/02/10/redis/image-20210130142003701.png" alt="image-20210130142003701"></p></li><li><p>所以为什么要用NoSQL</p><p>用户的个人信息、社交网络、地理位置、用户自己产生的数据,用户日志等等爆发式增长</p><p>这时候使用NoSQL数据库可以很好的解决以上情况</p></li></ol><h2 id="什么是NoSQL"><a href="#什么是NoSQL" class="headerlink" title="什么是NoSQL"></a>什么是NoSQL</h2><p><strong>NoSQL</strong></p><p>NoSQL=not only sql(不仅仅是SQL) 泛指非关系型数据库</p><p>关系型数据库:表格、行、列</p><p>随着web2.0互联网的诞生,传统的关系型数据库很难对付web2.0时代,尤其是超大规模、高并发的社区,暴露出来很多难以克服的问题,NoSQL在当今大数据环境下发展十分迅速,Redis是发展最快的,当下必须掌握的一门技术</p><p>很多数据库类型,用户的个人信息,社交网络,地理位置。这些数据的存储类型不需要一个固定的格式,不需要多余的操作就可以横向扩展(用多台机器实现—>集群)Map<String,Object>使用键值对来控制</p><p><strong>NoSQL的特点</strong></p><ol><li>方便扩展(数据之间没有关系,很好扩展)</li><li>大数据量高性能(Redis一秒可以写八万次,可以读取十一万次,NoSQL的缓存记录是一种细粒度的缓存,性能比较高)</li><li>数据类型是多样型的(不需要事先设计数据库,随取随用)</li><li>传统的RDBMS和NoSQL<ol><li>传统的RDBMS<ol><li>结构化组织</li><li>SQL</li><li>数据和组织都存在单独的表中</li><li>操作,数据库定义语言</li><li>严格的一致性</li><li>基础的事务</li></ol></li><li>NoSQL<ol><li>不仅仅是数据</li><li>没有固定的查询语言</li><li>键值对存储,列存储,文档存储,图形数据库(社交关系)</li><li>最终一致性</li><li>CAP定理和BASE(异地多活)</li><li>高新能,高可用,高可扩展</li></ol></li></ol></li></ol><h2 id="网页的数据放在哪里"><a href="#网页的数据放在哪里" class="headerlink" title="网页的数据放在哪里"></a>网页的数据放在哪里</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">#1.商品的基本信息</span></span><br><span class="line"> 名称、价格、商家信息</span><br><span class="line"> 使用关系型数据库 MySQL/Oracle</span><br><span class="line"></span><br><span class="line"><span class="comment">#2.商品的描述、评论(文字比较多)</span></span><br><span class="line"> 文档型数据库,MongoDB</span><br><span class="line"> </span><br><span class="line"><span class="comment">#3.图片</span></span><br><span class="line"> 分布式文件系统 FastDFS</span><br><span class="line"> 淘宝自己的 TFS</span><br><span class="line"> Google的 GFS</span><br><span class="line"> Hadoop HDFS</span><br><span class="line"> 阿里云的 OSS</span><br><span class="line"> </span><br><span class="line"><span class="comment">#4.商品的关键字</span></span><br><span class="line"> 搜索引擎 solr elasticsearch</span><br><span class="line"> ISearch</span><br><span class="line"> </span><br><span class="line"><span class="comment">#5.商品热门的波段信息</span></span><br><span class="line"> 内存数据库</span><br><span class="line"> Redis</span><br><span class="line"> </span><br><span class="line"><span class="comment">#6.商品的交易,外部的支付接口</span></span><br><span class="line"> 三方应用</span><br></pre></td></tr></table></figure><h2 id="NoSQL的四大分类"><a href="#NoSQL的四大分类" class="headerlink" title="NoSQL的四大分类"></a>NoSQL的四大分类</h2><p><strong>KV键值对:</strong></p><ul><li>新浪:Redis</li><li>美团:Redis+Tair</li><li>阿里、百度:Redis+Memcache</li></ul><p><strong>文档型数据库(bson格式 和json一样):</strong></p><ul><li>MongoDB(一般必须要掌握)<ul><li>MongoDB是一个基于分布式文件存储的数据库,C++编写,主要用来处理大量的文档</li><li>MongoDB是一个介于关系型数据库和非关系数据库中间的产品。MongoDB是非关系型数据库中功能最丰富、最像关系型数据库的</li></ul></li><li>CouchDB</li></ul><p><strong>列存储数据库:</strong></p><ul><li>HBase</li><li>分布式文件系统</li></ul><p><strong>图关系数据库:</strong></p><ul><li>它不是存图形的,存的是关系。比如:朋友圈、社交网络、广告推荐</li><li>Neo4j、InfoGrid</li></ul><p><img src="/2021/02/10/redis/image-20210130173653296.png" alt="image-20210130173653296"></p><h1 id="Redis入门"><a href="#Redis入门" class="headerlink" title="Redis入门"></a>Redis入门</h1><h2 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h2><p><strong>Redis是什么?</strong></p><p><em>Redis</em>(<strong>Re</strong>mote <strong>Di</strong>ctionary <strong>S</strong>erver ),即远程字典服务</p><p>是一个开源的使用ANSI <a href="https://baike.baidu.com/item/C%E8%AF%AD%E8%A8%80">C语言</a>编写、支持网络、可基于内存亦可持久化的日志型、Key-Value<a href="https://baike.baidu.com/item/%E6%95%B0%E6%8D%AE%E5%BA%93/103728">数据库</a>,并提供多种语言的API。</p><p><strong>Redis能干嘛?</strong></p><ul><li>内存存储、持久化(内存是断电即失的。所以说持久化很重要(rdb、aof))</li><li>效率高,可以用于高速缓存</li><li>发布订阅系统</li><li>地图信息分析</li><li>计数器(微信、微博浏览量)</li></ul><p><strong>Redis特性</strong></p><ul><li>多样的数据类型</li><li>持久化</li><li>集群</li><li>事务</li></ul><p><strong>学习中需要用到的东西</strong></p><ul><li>官网:<a href="http://www.redis.cn/">http://www.redis.cn/</a></li></ul><p><strong>Redis推荐在Linux服务器上搭建</strong></p><h2 id="Linux安装"><a href="#Linux安装" class="headerlink" title="Linux安装"></a>Linux安装</h2><h3 id="使用docker安装"><a href="#使用docker安装" class="headerlink" title="使用docker安装"></a>使用docker安装</h3><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">[root@iz2ze3x4is8pvdy0vb4x4kz ~]<span class="comment"># docker pull redis</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]<span class="comment"># docker run -d -p 6666:6379 redis #映射到6666端口</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]<span class="comment"># redis-cli -p 6666 #使用redis客户端进行连接</span></span><br><span class="line">127.0.0.1:6666> keys *</span><br><span class="line">(empty array)</span><br><span class="line">127.0.0.1:6666> ping</span><br><span class="line">PONG <span class="comment">#连接成功</span></span><br><span class="line">127.0.0.1:6666> <span class="built_in">set</span> name jonyon</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> get name</span><br><span class="line"><span class="string">"jonyon"</span></span><br></pre></td></tr></table></figure><h2 id="测试性能"><a href="#测试性能" class="headerlink" title="测试性能"></a>测试性能</h2><p><strong>redis-benchmark是</strong>一个压力测试工具</p><p>官方自带的性能测试工具</p><p>redis-benchmark命令参数</p><p><img src="/2021/02/10/redis/image-20210130182208507.png" alt="image-20210130182208507"></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"><span class="comment">#测试 100个并发、100000请求</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]<span class="comment"># redis-benchmark -h localhost -p 6666 -c 100 -n 100000 #不使用docker用这条命令</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]<span class="comment"># docker exec -it 6ede1840c0b9 redis-benchmark -h 39.97.212.128 -p 6666 -c 100 -n 100000 #使用docker</span></span><br></pre></td></tr></table></figure><p><img src="/2021/02/10/redis/image-20210130183743125.png" alt="image-20210130183743125"></p><h1 id="Redis基础知识"><a href="#Redis基础知识" class="headerlink" title="Redis基础知识"></a>Redis基础知识</h1><p>Redis默认有16个数据库,默认使用第0个数据库,可以使用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><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">[root@iz2ze3x4is8pvdy0vb4x4kz ~]<span class="comment"># redis-cli -p 6666</span></span><br><span class="line">127.0.0.1:6666> dbsize <span class="comment">#查看db大小</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> select 5 <span class="comment">#切换数据库</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666[5]> select 0</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> keys * <span class="comment">#查看数据库所有的key</span></span><br><span class="line">1) <span class="string">"name"</span></span><br><span class="line">127.0.0.1:6666> get name <span class="comment">#获得key的value</span></span><br><span class="line"><span class="string">"jonyon"</span></span><br><span class="line">127.0.0.1:6666> flushdb <span class="comment">#清空当前数据库</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> keys *</span><br><span class="line">(empty array)</span><br><span class="line">127.0.0.1:6666> flushdb <span class="comment">#清空全部数据库</span></span><br></pre></td></tr></table></figure><p>0edis为什么是6379:粉丝效应</p><h2 id="Redis是单线程的"><a href="#Redis是单线程的" class="headerlink" title="Redis是单线程的"></a>Redis是单线程的</h2><p>Redis是很快的,基于内存操作,CPU不是Redis的性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来使用,所以就使用了单线程</p><h2 id="Redis为什么单线程海那么块"><a href="#Redis为什么单线程海那么块" class="headerlink" title="Redis为什么单线程海那么块"></a>Redis为什么单线程海那么块</h2><p>Redis是c语言写的,官方提供的数据为100000+QPS,完全不比同样是使用k-v的Memcache差</p><p>误区一:高性能的服务器一定是多线程的</p><p>误区二:多线程(CPU上下文切换)一定比单线程效率高</p><p>速度:CPU>内存>硬盘</p><p>和兴:Redis是将所有的数据放在内存中的,所以说使用单线程去操作效率就是最高的,因为多线程之间会造成CPU之间上下文切换,这时一个耗时的操作。对于内存系统来说,如果没有上下文切换,效率就是最高的,多次读写都是在一个CPU上的,所以说在内存情况下,这个就是最佳方案</p><h1 id="五大数据类型"><a href="#五大数据类型" class="headerlink" title="五大数据类型"></a>五大数据类型</h1><p>Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作<strong>数据库</strong>、<strong>缓存</strong>和<strong>消息中间件</strong>。 它支持多种类型的数据结构,如 <a href="http://www.redis.cn/topics/data-types-intro.html#strings">字符串(strings)</a>, <a href="http://www.redis.cn/topics/data-types-intro.html#hashes">散列(hashes)</a>, <a href="http://www.redis.cn/topics/data-types-intro.html#lists">列表(lists)</a>, <a href="http://www.redis.cn/topics/data-types-intro.html#sets">集合(sets)</a>, <a href="http://www.redis.cn/topics/data-types-intro.html#sorted-sets">有序集合(sorted sets)</a> 与范围查询, <a href="http://www.redis.cn/topics/data-types-intro.html#bitmaps">bitmaps</a>, <a href="http://www.redis.cn/topics/data-types-intro.html#hyperloglogs">hyperloglogs</a> 和 <a href="http://www.redis.cn/commands/geoadd.html">地理空间(geospatial)</a> 索引半径查询。 Redis 内置了 <a href="http://www.redis.cn/topics/replication.html">复制(replication)</a>,<a href="http://www.redis.cn/commands/eval.html">LUA脚本(Lua scripting)</a>, <a href="http://www.redis.cn/topics/lru-cache.html">LRU驱动事件(LRU eviction)</a>,<a href="http://www.redis.cn/topics/transactions.html">事务(transactions)</a> 和不同级别的 <a href="http://www.redis.cn/topics/persistence.html">磁盘持久化(persistence)</a>, 并通过 <a href="http://www.redis.cn/topics/sentinel.html">Redis哨兵(Sentinel)</a>和自动 <a href="http://www.redis.cn/topics/cluster-tutorial.html">分区(Cluster)</a>提供高可用性(high availability)。</p><h2 id="Redis-Key"><a href="#Redis-Key" class="headerlink" title="Redis-Key"></a>Redis-Key</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><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">127.0.0.1:6666> <span class="built_in">set</span> name jonyon</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> <span class="built_in">set</span> age 21</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> keys *</span><br><span class="line">1) <span class="string">"name"</span></span><br><span class="line">2) <span class="string">"age"</span></span><br><span class="line">127.0.0.1:6666> 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:6666> ttl name <span class="comment">#查看当前key的剩余时间</span></span><br><span class="line">(<span class="built_in">integer</span>) 7</span><br><span class="line">127.0.0.1:6666> ttl name</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> ttl name</span><br><span class="line">(<span class="built_in">integer</span>) -2</span><br><span class="line">127.0.0.1:6666> ttl name</span><br><span class="line">(<span class="built_in">integer</span>) -2</span><br><span class="line">127.0.0.1:6666> keys *</span><br><span class="line">1) <span class="string">"age"</span></span><br><span class="line">127.0.0.1:6666> exists name <span class="comment">#判断当前key是否存在</span></span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line">127.0.0.1:6666> exists age</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> <span class="built_in">type</span> age <span class="comment">#查看当前key的类型</span></span><br><span class="line">string</span><br><span class="line"></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><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><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6666> <span class="built_in">set</span> k1 v1</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> get k1</span><br><span class="line"><span class="string">"v1"</span></span><br><span class="line">127.0.0.1:6666> keys *</span><br><span class="line">1) <span class="string">"k1"</span></span><br><span class="line">127.0.0.1:6666> append k1 <span class="string">"hello"</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:6666> get k1 </span><br><span class="line"><span class="string">"v1hello"</span> </span><br><span class="line">127.0.0.1:6666> strlen k1 <span class="comment">#获取字符串的长度</span></span><br><span class="line">(<span class="built_in">integer</span>) 7</span><br><span class="line"><span class="comment">########################################################################################################</span></span><br><span class="line">步长(i++)</span><br><span class="line">127.0.0.1:6666> <span class="built_in">set</span> views 0 <span class="comment">#初始浏览量为0</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> get views</span><br><span class="line"><span class="string">"0"</span></span><br><span class="line">127.0.0.1:6666> INCR views <span class="comment">#自增1,浏览量+1</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> get views</span><br><span class="line"><span class="string">"1"</span></span><br><span class="line">127.0.0.1:6666> INCR views</span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br><span class="line">127.0.0.1:6666> get views</span><br><span class="line"><span class="string">"2"</span></span><br><span class="line">127.0.0.1:6666> DECR views <span class="comment">#自减1,浏览量-1</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> get views</span><br><span class="line"><span class="string">"1"</span> </span><br><span class="line">127.0.0.1:6666> INCRBY views 5 <span class="comment">#可以设置步长,指定增量5</span></span><br><span class="line">(<span class="built_in">integer</span>) 6</span><br><span class="line">127.0.0.1:6666> get views</span><br><span class="line"><span class="string">"6"</span></span><br><span class="line">127.0.0.1:6666> DECRBY views 3 <span class="comment">#可以设置步长,指定减量3</span></span><br><span class="line">(<span class="built_in">integer</span>) 3</span><br><span class="line">127.0.0.1:6666> get views</span><br><span class="line"><span class="string">"3"</span></span><br><span class="line"><span class="comment">########################################################################################################</span></span><br><span class="line"><span class="comment">#字符串范围 range</span></span><br><span class="line">127.0.0.1:6666> <span class="built_in">set</span> k1 hello,jonyon</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> get k1</span><br><span class="line"><span class="string">"hello,jonyon"</span></span><br><span class="line">127.0.0.1:6666> getrange k1 0 3 <span class="comment">#截取字符串【0,3】</span></span><br><span class="line"><span class="string">"hell"</span></span><br><span class="line">127.0.0.1:6666> getrange k1 0 -1 <span class="comment">#获取全部字符串,相当于get k1</span></span><br><span class="line"><span class="string">"hello,jonyon"</span></span><br><span class="line">127.0.0.1:6666> <span class="built_in">set</span> k2 <span class="built_in">bye</span>,jonyon</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> get k2</span><br><span class="line"><span class="string">"bye,jonyon"</span></span><br><span class="line">127.0.0.1:6666> setrange k2 0 xxx <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:6666> get k2</span><br><span class="line"><span class="string">"xxx,jonyon"</span></span><br><span class="line"><span class="comment">######################################################################################################### # setex(set with expire) #设置过期时间</span></span><br><span class="line"><span class="comment"># setnx(set if no expire) #不存在再设置 (在分布式锁中会常常使用)</span></span><br><span class="line">127.0.0.1:6666> setex k3 30 <span class="string">"hello"</span> <span class="comment">#设置k3的值为hello,30秒后过期</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> keys *</span><br><span class="line">1) <span class="string">"k3"</span></span><br><span class="line">2) <span class="string">"k2"</span></span><br><span class="line">3) <span class="string">"k1"</span></span><br><span class="line">127.0.0.1:6666> setnx k4 <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:6666> keys *</span><br><span class="line">1) <span class="string">"k4"</span></span><br><span class="line">2) <span class="string">"k2"</span></span><br><span class="line">3) <span class="string">"k1"</span></span><br><span class="line">127.0.0.1:6666> get k4</span><br><span class="line"><span class="string">"redis"</span></span><br><span class="line">127.0.0.1:6666> setnx k4 <span class="string">"mongodb"</span> <span class="comment">#如果mykey存在,则创建失败</span></span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line">127.0.0.1:6666> get k4</span><br><span class="line"><span class="string">"redis"</span></span><br><span class="line"><span class="comment">######################################################################################################### </span></span><br><span class="line"><span class="comment"># mset mget</span></span><br><span class="line">127.0.0.1:6666> 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:6666> keys *</span><br><span class="line">1) <span class="string">"k3"</span></span><br><span class="line">2) <span class="string">"k2"</span></span><br><span class="line">3) <span class="string">"k1"</span> </span><br><span class="line">127.0.0.1:6666> 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:6666> msetnx k1 v1 k4 v4 <span class="comment">#msetnx是一个原子性的操作,要么一起成功,要么一起失败</span></span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line">127.0.0.1:6666> keys *</span><br><span class="line">1) <span class="string">"k3"</span></span><br><span class="line">2) <span class="string">"k2"</span></span><br><span class="line">3) <span class="string">"k1"</span></span><br><span class="line"><span class="comment">########################################################################################################## 对象</span></span><br><span class="line"><span class="built_in">set</span> user:1{name:zhangsan,age:2} <span class="comment">#设置一个user:1对象,值为json字符串来保存一个对象</span></span><br><span class="line"><span class="comment"># 这里的keys是一个巧妙的设计,user:{id}:{filed}</span></span><br><span class="line">127.0.0.1:6666> mset user:1:name jonyon user:1:age 21</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> mget user:1:name user:1:age</span><br><span class="line">1) <span class="string">"jonyon"</span></span><br><span class="line">2) <span class="string">"21"</span></span><br><span class="line"><span class="comment">######################################################################################################### getset #先get再set</span></span><br></pre></td></tr></table></figure><p>数据结构是相同的</p><p>String类似的使用场景</p><ul><li>计数器</li><li>统计多单位的数量</li><li>粉丝数</li><li>对象缓存存储</li></ul><h2 id="List-列表"><a href="#List-列表" class="headerlink" title="List(列表)"></a>List(列表)</h2><p>基本的数据类型,列表</p><p><img src="/2021/02/10/redis/image-20210131154319198.png" alt="image-20210131154319198"></p><p>在redis里面,可以使用list实现栈、队列、阻塞队列</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><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><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#所有的list命令都是l开头的</span></span><br><span class="line">127.0.0.1:6666> lpush list one <span class="comment">#将一个或多个值插入到列表的头部 lpush-->left push 从队列左边插入</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> lpush list two</span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br><span class="line">127.0.0.1:6666> lpush list three</span><br><span class="line">(<span class="built_in">integer</span>) 3</span><br><span class="line">127.0.0.1:6666> 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">127.0.0.1:6666> 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:6666> rpush list four <span class="comment">#将一个或多个值插入到列表的尾部 rpush-->right push 从队列右边插入</span></span><br><span class="line">(<span class="built_in">integer</span>) 4</span><br><span class="line">127.0.0.1:6666> 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">"four"</span></span><br><span class="line"><span class="comment">#########################################################################################################</span></span><br><span class="line">127.0.0.1:6666> lpop list <span class="comment">#移除列表最左边的元素(第一个元素)</span></span><br><span class="line"><span class="string">"three"</span></span><br><span class="line">127.0.0.1:6666> rpop list <span class="comment">#移除列表最右边的元素(最后一个)</span></span><br><span class="line"><span class="string">"four"</span></span><br><span class="line">127.0.0.1:6666> 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"><span class="comment">#########################################################################################################</span></span><br><span class="line">127.0.0.1:6666> lindex list 0 <span class="comment">#通过下表获得list中某一个值</span></span><br><span class="line"><span class="string">"two"</span></span><br><span class="line">127.0.0.1:6666> lindex list 1</span><br><span class="line"><span class="string">"one"</span></span><br><span class="line"><span class="comment">######################################################################################################### # llen</span></span><br><span class="line">127.0.0.1:6666> llen list <span class="comment">#返回列表的长度</span></span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br><span class="line"><span class="comment">######################################################################################################### </span></span><br><span class="line"><span class="comment"># 移除指定的值</span></span><br><span class="line">127.0.0.1:6666> rpush list one</span><br><span class="line">(<span class="built_in">integer</span>) 3</span><br><span class="line">127.0.0.1:6666> 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">3) <span class="string">"one"</span></span><br><span class="line">127.0.0.1:6666> lrem list 1 one <span class="comment">#移除list集合中指定个数的value,精确匹配</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> 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"><span class="comment">############################################################################################################ trim 修剪、截断</span></span><br><span class="line">127.0.0.1:6666> rpush mylist <span class="string">"hello0"</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> 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:6666> 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:6666> 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:6666> lrange mylist 0 -1</span><br><span class="line">1) <span class="string">"hello0"</span></span><br><span class="line">2) <span class="string">"hello1"</span></span><br><span class="line">3) <span class="string">"hello2"</span></span><br><span class="line">4) <span class="string">"hello3"</span></span><br><span class="line">127.0.0.1:6666> ltrim mylist 1 2 <span class="comment">#通过下表截取指定的长度</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> lrange mylist 0 -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><span class="line"><span class="comment">############################################################################################################ rpoplpush #移除列表最右边(最后一个)元素,并将它移动到新列表的最左边(第一个)</span></span><br><span class="line">127.0.0.1:6666> rpush list one</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> rpush list two</span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br><span class="line">127.0.0.1:6666> rpush list three</span><br><span class="line">(<span class="built_in">integer</span>) 3</span><br><span class="line">127.0.0.1:6666> lrange list 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><span class="line">127.0.0.1:6666> rpoplpush list otherlist</span><br><span class="line"><span class="string">"three"</span></span><br><span class="line">127.0.0.1:6666> lrange list 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">127.0.0.1:6666> lrange otherlist 0 -1</span><br><span class="line">1) <span class="string">"three"</span></span><br><span class="line"><span class="comment">############################################################################################################### lset #将列表中指定下标的值替换为另外一个值</span></span><br><span class="line">127.0.0.1:6666> lpush list k</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> lrange list 0 -1</span><br><span class="line">1) <span class="string">"k"</span></span><br><span class="line">127.0.0.1:6666> lset list 0 key</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> lrange list 0 -1</span><br><span class="line">1) <span class="string">"key"</span></span><br><span class="line"><span class="comment">########################################################################################################## insert #将某个具体的value插入到列表中某个元素的前面或者后面</span></span><br><span class="line">127.0.0.1:6666> rpush list <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:6666> rpush list <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:6666> linsert list 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:6666> lrange list 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:6666> linsert list after <span class="string">"world"</span> <span class="string">"new"</span></span><br><span class="line">(<span class="built_in">integer</span>) 4</span><br><span class="line">127.0.0.1:6666> lrange list 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">4) <span class="string">"new"</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p><strong>小结:它实际上是一个链表(before node after)</strong></p><ul><li>如果key不存在,创建新的链表</li><li>如果key存在,新增内容</li><li>如果移除了所有值,空链表</li><li>两边插入或改动效率最高,中间元素插入或改动效率低</li></ul><p>消息队列(lpush rpop)、栈(lpush rpop)</p><h2 id="Set-集合"><a href="#Set-集合" class="headerlink" title="Set(集合)"></a>Set(集合)</h2><p>set中的值不能重复,set中存储的数据是无序的</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><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></pre></td><td class="code"><pre><span class="line">127.0.0.1:6666> sadd <span class="built_in">set</span> <span class="string">"jonyon"</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:6666> sadd <span class="built_in">set</span> <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:6666> sadd <span class="built_in">set</span> <span class="string">"ok"</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> SMEMBERS <span class="built_in">set</span> <span class="comment">#查看指定set的所有值</span></span><br><span class="line">1) <span class="string">"ok"</span></span><br><span class="line">2) <span class="string">"hello"</span></span><br><span class="line">3) <span class="string">"jonyon"</span></span><br><span class="line">127.0.0.1:6666> SISMEMBER <span class="built_in">set</span> hello <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:6666> SISMEMBER <span class="built_in">set</span> hell</span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line"><span class="comment">#############################################################################################################</span></span><br><span class="line">127.0.0.1:6666> sadd <span class="built_in">set</span> <span class="string">"ok"</span> <span class="comment">#不能添加重复的值</span></span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line">127.0.0.1:6666> scard <span class="built_in">set</span> <span class="comment">#获取set集合中的内容元素个数</span></span><br><span class="line">(<span class="built_in">integer</span>) 3</span><br><span class="line"><span class="comment">##############################################################################################################</span></span><br><span class="line">127.0.0.1:6666> srem <span class="built_in">set</span> <span class="string">"ok"</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:6666> SMEMBERS <span class="built_in">set</span></span><br><span class="line">1) <span class="string">"hello"</span></span><br><span class="line">2) <span class="string">"jonyon"</span></span><br><span class="line"><span class="comment">############################################################################################################## set无序不重复集合</span></span><br><span class="line">127.0.0.1:6666> SRANDMEMBER <span class="built_in">set</span> <span class="comment">#随机抽选出一个元素</span></span><br><span class="line"><span class="string">"jonyon"</span></span><br><span class="line">127.0.0.1:6666> SRANDMEMBER <span class="built_in">set</span></span><br><span class="line"><span class="string">"ok"</span></span><br><span class="line">127.0.0.1:6666> SRANDMEMBER <span class="built_in">set</span> 2 <span class="comment">#随机抽选出指定个数的元素</span></span><br><span class="line">1) <span class="string">"hello"</span></span><br><span class="line">2) <span class="string">"ok"</span></span><br><span class="line"><span class="comment">###############################################################################################################</span></span><br><span class="line">127.0.0.1:6666> spop <span class="built_in">set</span> <span class="comment">#随机移除元素</span></span><br><span class="line"><span class="string">"hello"</span></span><br><span class="line">127.0.0.1:6666> spop <span class="built_in">set</span></span><br><span class="line"><span class="string">"jonyon"</span></span><br><span class="line">127.0.0.1:6666> SMEMBERS <span class="built_in">set</span></span><br><span class="line">1) <span class="string">"ok"</span></span><br><span class="line"><span class="comment">############################################################################################################### 将一个指定的值,移动到另外一个集合中</span></span><br><span class="line">127.0.0.1:6666> sadd <span class="built_in">set</span> <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:6666> sadd <span class="built_in">set</span> <span class="string">"world"</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> sadd <span class="built_in">set</span> <span class="string">"jonyon"</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> smove <span class="built_in">set</span> set2 <span class="string">"jonyon"</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:6666> SMEMBERS <span class="built_in">set</span> </span><br><span class="line">1) <span class="string">"hello"</span></span><br><span class="line">2) <span class="string">"world"</span></span><br><span class="line">127.0.0.1:6666> SMEMBERS set2</span><br><span class="line">1) <span class="string">"jonyon"</span></span><br><span class="line"><span class="comment">############################################################################################################### 集合</span></span><br><span class="line">127.0.0.1:6666> sadd k1 <span class="string">"a"</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> sadd k1 <span class="string">"b"</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> sadd k1 <span class="string">"c"</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> sadd k2 <span class="string">"c"</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> sadd k2 <span class="string">"d"</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> sadd k2 <span class="string">"e"</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> sdiff k1 k2 <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:6666> sinter k1 k2 <span class="comment">#交集</span></span><br><span class="line">1) <span class="string">"c"</span></span><br><span class="line">127.0.0.1:6666> sunion k1 k2 <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">"a"</span></span><br><span class="line">4) <span class="string">"e"</span></span><br><span class="line">5) <span class="string">"d"</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="Hash-哈希"><a href="#Hash-哈希" class="headerlink" title="Hash(哈希)"></a>Hash(哈希)</h2><p>Map集合,key-value集合</p><p>这时候这个值是一个map集合,本质和String类型没有太大区别,还是一个简单的k-v</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><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">127.0.0.1:6666> hset <span class="built_in">hash</span> field1 jonyon <span class="comment">#set一个具体的key-value</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> hget <span class="built_in">hash</span> field1 <span class="comment">#获取一个字段值</span></span><br><span class="line"><span class="string">"jonyon"</span></span><br><span class="line">127.0.0.1:6666> hmset <span class="built_in">hash</span> field1 hello field2 jonyon <span class="comment">#set多个key-value</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> hmget <span class="built_in">hash</span> field1 field2 <span class="comment">#获取多个字段值</span></span><br><span class="line">1) <span class="string">"hello"</span></span><br><span class="line">2) <span class="string">"jonyon"</span></span><br><span class="line">127.0.0.1:6666> hgetall <span class="built_in">hash</span> <span class="comment">#获取全部数据</span></span><br><span class="line">1) <span class="string">"field1"</span></span><br><span class="line">2) <span class="string">"hello"</span></span><br><span class="line">3) <span class="string">"field2"</span></span><br><span class="line">4) <span class="string">"jonyon"</span></span><br><span class="line"><span class="comment">###########################################################################################################</span></span><br><span class="line">127.0.0.1:6666> hdel <span class="built_in">hash</span> 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:6666> hgetall <span class="built_in">hash</span></span><br><span class="line">1) <span class="string">"field2"</span></span><br><span class="line">2) <span class="string">"jonyon"</span></span><br><span class="line"><span class="comment">###########################################################################################################</span></span><br><span class="line">127.0.0.1:6666> hlen <span class="built_in">hash</span> <span class="comment">#获取hash表的字段数量</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line"><span class="comment">###########################################################################################################</span></span><br><span class="line">127.0.0.1:6666> HEXISTS <span class="built_in">hash</span> field1 <span class="comment">#判断hash中的指定字段是否存在</span></span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line">127.0.0.1:6666> HEXISTS <span class="built_in">hash</span> field2</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line"><span class="comment">########################################################################################################### 只获得所有的key或所有的value</span></span><br><span class="line">127.0.0.1:6666> hkeys <span class="built_in">hash</span></span><br><span class="line">1) <span class="string">"field2"</span></span><br><span class="line">127.0.0.1:6666> hvals <span class="built_in">hash</span></span><br><span class="line">1) <span class="string">"jonyon"</span></span><br><span class="line"><span class="comment">########################################################################################################### 自增和自减</span></span><br><span class="line">127.0.0.1:6666> hset <span class="built_in">hash</span> field1 1</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> HINCRBY <span class="built_in">hash</span> field1 3</span><br><span class="line">(<span class="built_in">integer</span>) 4</span><br><span class="line">127.0.0.1:6666> HINCRBY <span class="built_in">hash</span> field1 -2</span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br><span class="line">127.0.0.1:6666> hgetall <span class="built_in">hash</span></span><br><span class="line">1) <span class="string">"field1"</span></span><br><span class="line">2) <span class="string">"2"</span></span><br><span class="line"><span class="comment">########################################################################################################### 如果存在则可以设置</span></span><br><span class="line">127.0.0.1:6666> hsetnx <span class="built_in">hash</span> field4 hello <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:6666> hsetnx <span class="built_in">hash</span> field4 ok <span class="comment">#如果存在则不可以设置</span></span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>hash变更的数据user name age,尤其是用户信息之类的,经常变动的信息</p><p>hash更适合于对象的存储、String更适合字符串的存储</p><h2 id="Zset-有序集合"><a href="#Zset-有序集合" class="headerlink" title="Zset(有序集合)"></a>Zset(有序集合)</h2><p>在set的基础上增加了一个值</p><ul><li>set k1 v1</li><li>zset k1 score1 v1</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><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></pre></td><td class="code"><pre><span class="line">127.0.0.1:6666> zadd myzset 1 one 3 three 2 two <span class="comment">#添加</span></span><br><span class="line">(<span class="built_in">integer</span>) 3</span><br><span class="line">127.0.0.1:6666> zrange myzset 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><span class="line"><span class="comment">############################################################################################################ 排序如何实现</span></span><br><span class="line">127.0.0.1:6666> zadd salary 1200 jonyon 2500 adger 10000 wzj</span><br><span class="line">(<span class="built_in">integer</span>) 3</span><br><span class="line">127.0.0.1:6666> zrange salary 0 -1</span><br><span class="line">1) <span class="string">"jonyon"</span></span><br><span class="line">2) <span class="string">"adger"</span></span><br><span class="line">3) <span class="string">"wzj"</span></span><br><span class="line">127.0.0.1:6666> ZRANGEBYSCORE salary -inf +inf <span class="comment">#正无穷--->负无穷排序</span></span><br><span class="line">1) <span class="string">"jonyon"</span></span><br><span class="line">2) <span class="string">"adger"</span></span><br><span class="line">3) <span class="string">"wzj"</span></span><br><span class="line">127.0.0.1:6666> ZRANGEBYSCORE salary -inf +inf withscores <span class="comment">#正无穷--->负无穷排序,带上scores</span></span><br><span class="line">1) <span class="string">"jonyon"</span></span><br><span class="line">2) <span class="string">"1200"</span></span><br><span class="line">3) <span class="string">"adger"</span></span><br><span class="line">4) <span class="string">"2500"</span></span><br><span class="line">5) <span class="string">"wzj"</span></span><br><span class="line">6) <span class="string">"10000"</span></span><br><span class="line">127.0.0.1:6666> ZRANGEBYSCORE salary -inf 2500 withscores <span class="comment">#正无穷--->2500排序,带上scores</span></span><br><span class="line">1) <span class="string">"jonyon"</span></span><br><span class="line">2) <span class="string">"1200"</span></span><br><span class="line">3) <span class="string">"adger"</span></span><br><span class="line">4) <span class="string">"2500"</span></span><br><span class="line">127.0.0.1:6666> ZREVRANGEBYSCORE salary +inf -inf <span class="comment">#负无穷--->正无穷排序</span></span><br><span class="line">1) <span class="string">"wzj"</span></span><br><span class="line">2) <span class="string">"adger"</span></span><br><span class="line">3) <span class="string">"jonyon"</span></span><br><span class="line"><span class="comment">############################################################################################################ 移除</span></span><br><span class="line">127.0.0.1:6666> zrange salary 0 -1</span><br><span class="line">1) <span class="string">"jonyon"</span></span><br><span class="line">2) <span class="string">"adger"</span></span><br><span class="line">3) <span class="string">"wzj"</span></span><br><span class="line">127.0.0.1:6666> zrem salary wzj</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> zrange salary 0 -1</span><br><span class="line">1) <span class="string">"jonyon"</span></span><br><span class="line">2) <span class="string">"adger"</span></span><br><span class="line">127.0.0.1:6666> zcard salary <span class="comment">#获取有序集合中的个数</span></span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br><span class="line"><span class="comment">############################################################################################################ 获取区间的成员数量</span></span><br><span class="line">127.0.0.1:6666> zcount salary 1 2</span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line">127.0.0.1:6666> zcount salary 0 2500</span><br><span class="line">(<span class="built_in">integer</span>) 2</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>排行榜应用实现、取TopN测试</p><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>这个功能可以推算地理位置的信息,两地之间的距离,方圆几里的人</p><p>只有6个命令</p><p><img src="/2021/02/10/redis/image-20210201171435312.png" alt="image-20210201171435312"></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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">#geoadd 添加add</span></span><br><span class="line"><span class="comment">#规则:两极(南极北极)无法添加,我们一般会下载城市数据、直接通过java程序一次性导入</span></span><br><span class="line"><span class="comment">#参数key 经度、纬度、名称</span></span><br><span class="line"><span class="comment">########################################################################################################## </span></span><br><span class="line">127.0.0.1:6666> geoadd china:city 116.40 39.90 beijing 121.47 31.23 shanghai 106.50 29.53 chongqing 114.05 22.52 shenzheng 120.16 30.24 hangzhou 108.96 34.26 xian</span><br><span class="line">(<span class="built_in">integer</span>) 6</span><br><span class="line">127.0.0.1:6666> geopos china:city chongqing</span><br><span class="line">1) 1) <span class="string">"106.49999767541885376"</span></span><br><span class="line"> 2) <span class="string">"29.52999957900659211"</span></span><br><span class="line">127.0.0.1:6666> geopos china:city beijing</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"><span class="comment">########################################################################################################## 获取指定程序的经度纬度,获取当前定位一定是一个坐标值 geopos</span></span><br><span class="line">127.0.0.1:6666> 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><span class="line"><span class="comment">########################################################################################################## 两人之间的距离 geodist</span></span><br><span class="line">127.0.0.1:6666> geodist china:city beijing shanghai km</span><br><span class="line"><span class="string">"1067.3788"</span></span><br><span class="line"><span class="comment">########################################################################################################## georadius 以给定的经度为中心,找出某一半径内的元素</span></span><br><span class="line">127.0.0.1:6666> 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:6666> GEORADIUS china:city 110 30 1000 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">3) <span class="string">"shenzheng"</span></span><br><span class="line">4) <span class="string">"hangzhou"</span></span><br><span class="line">127.0.0.1:6666> GEORADIUS china:city 110 30 1000 km withdist <span class="comment">#跟上直线距离</span></span><br><span class="line">1) 1) <span class="string">"chongqing"</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><br><span class="line">3) 1) <span class="string">"shenzheng"</span></span><br><span class="line"> 2) <span class="string">"924.6408"</span></span><br><span class="line">4) 1) <span class="string">"hangzhou"</span></span><br><span class="line"> 2) <span class="string">"977.5143"</span></span><br><span class="line">127.0.0.1:6666> GEORADIUS china:city 110 30 1000 km withcoord <span class="comment">#跟上经纬度</span></span><br><span class="line">1) 1) <span class="string">"chongqing"</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><span class="line">2) 1) <span class="string">"xian"</span></span><br><span class="line"> 2) 1) <span class="string">"108.96000176668167114"</span></span><br><span class="line"> 2) <span class="string">"34.25999964418929977"</span></span><br><span class="line">3) 1) <span class="string">"shenzheng"</span></span><br><span class="line"> 2) 1) <span class="string">"114.04999762773513794"</span></span><br><span class="line"> 2) <span class="string">"22.5200000879503861"</span></span><br><span class="line">4) 1) <span class="string">"hangzhou"</span></span><br><span class="line"> 2) 1) <span class="string">"120.1600000262260437"</span></span><br><span class="line"> 2) <span class="string">"30.2400003229490224"</span></span><br><span class="line"><span class="comment">########################################################################################################## GEORADIUSBYMEMBER 找出位于指定元素周围的其他元素</span></span><br><span class="line">127.0.0.1:6666> GEORADIUSBYMEMBER china:city beijing 1000 km</span><br><span class="line">1) <span class="string">"beijing"</span></span><br><span class="line">2) <span class="string">"xian"</span></span><br><span class="line">127.0.0.1:6666> GEORADIUSBYMEMBER china:city xian 400 km</span><br><span class="line">1) <span class="string">"xian"</span></span><br><span class="line"><span class="comment">########################################################################################################## geohash 该命令将返回11个字符的Geohash字符串 </span></span><br><span class="line">127.0.0.1:6666> geohash china:city beijing chongqing <span class="comment">#将二维的经纬度转换为一维的字符串,如果两个字符串越接近则距离越近</span></span><br><span class="line">1) <span class="string">"wx4fbxxfke0"</span></span><br><span class="line">2) <span class="string">"wm5xzrybty0"</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="geo底层实现原理其实就是zset-可以用zset命令来操作geo"><a href="#geo底层实现原理其实就是zset-可以用zset命令来操作geo" class="headerlink" title="geo底层实现原理其实就是zset,可以用zset命令来操作geo"></a>geo底层实现原理其实就是zset,可以用zset命令来操作geo</h3><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:6666> zrange china:city 0 -1</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">"shenzheng"</span></span><br><span class="line">4) <span class="string">"hangzhou"</span></span><br><span class="line">5) <span class="string">"shanghai"</span></span><br><span class="line">6) <span class="string">"beijing"</span></span><br><span class="line">127.0.0.1:6666> zrem china:city beijing</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> zrange china:city 0 -1</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">"shenzheng"</span></span><br><span class="line">4) <span class="string">"hangzhou"</span></span><br><span class="line">5) <span class="string">"shanghai"</span></span><br></pre></td></tr></table></figure><h2 id="hyperloglog-基数统计"><a href="#hyperloglog-基数统计" class="headerlink" title="hyperloglog(基数统计)"></a>hyperloglog(基数统计)</h2><p><strong>什么是基数</strong></p><blockquote><p>基数是指一个集合(这里的集合允许存在重复元素)中不同元素的个数。</p><p>这就类似“求一个数组中不重复元素的个数”的算法。如数组a[10] = {1,2,3,4,1,2,3,4,5,6,7},那么不重复元素就是{1,2,3,4,5,6,7},一共7个。</p><p>对于它的应用场景,比如一个网站要统计“一个人”的访问次数的时候,比如小明,那么就给对“小明”打上标记,当它下次来访问的时候,总访问次数不能加一。只有当不是“小明”的人,比如“小丽”来访问,对将总访问次数加一。</p></blockquote><p>Hyperloglog数据结构 基数统计的算法</p><p><strong>网页的UV(一个人访问网站多次,但是还是算作一个人)</strong></p><ul><li>传统的方式:set保存用户id,然后就可以统计set中的元素数量作为标准判断<ul><li>这个方式如果保存大量的用户id就会比较麻烦,我们的目的是为了计数,而不是保存用户id</li></ul></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></pre></td><td class="code"><pre><span class="line">127.0.0.1:6666> PFADD myloglog a b c d e f j <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:6666> PFCOUNT myloglog <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:6666> PFADD myloglog2 f j h i g k <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:6666> PFCOUNT myloglog2 <span class="comment">#统计第一组元素基数数量</span></span><br><span class="line">(<span class="built_in">integer</span>) 6</span><br><span class="line">127.0.0.1:6666> PFMERGE myloglog3 myloglog myloglog2 <span class="comment">#合并两组</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> PFCOUNT myloglog3</span><br><span class="line">(<span class="built_in">integer</span>) 11</span><br></pre></td></tr></table></figure><p>如果允许容错,那么一定可以使用Hyperloglog</p><p>如果不允许容错,就是用set或则自己的数据类型即可</p><h2 id="bitmap"><a href="#bitmap" class="headerlink" title="bitmap"></a>bitmap</h2><blockquote><p>位存储</p></blockquote><p>统计用户信息</p><ul><li>活跃、不活跃</li><li>登录、未登录</li><li>打卡、未打卡</li></ul><p>两个状态的,都可以使用bitmap</p><p>bitmap位图、数据结构。都是操作二进制位来进行记录,就只有0和1两个状态</p><p>365天=365bit 46字节左右</p><p>使用bitmap来记录周一到周日的打卡</p><p>周一:1 周二:0 周三:1 周四:0…</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:6666> 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:6666> setbit sign 1 0</span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line">127.0.0.1:6666> setbit sign 2 1</span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line">127.0.0.1:6666> 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:6666> setbit sign 4 0</span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br><span class="line">127.0.0.1:6666> 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:6666> 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:6666> getbit sign 0</span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> getbit sign 6</span><br><span class="line">(<span class="built_in">integer</span>) 0</span><br></pre></td></tr></table></figure><p>统计操作,统计打卡的天数(1的天数)</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:6666> 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><p><strong>Redis事务没有隔离级别的概念</strong></p><p>所有的命令在事务中并没有直接被执行,只有发起执行命令的时候才会执行,Exec</p><p><strong>Redis的单条命令是保证原子性的,但是事务不保证原子性</strong></p><p>Redis的事务</p><ul><li>开启事务(multi)</li><li>命令入队(….)</li><li>执行事务(exec)</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><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">127.0.0.1:6666> MULTI</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> <span class="built_in">set</span> k1 v1 </span><br><span class="line">QUEUED <span class="comment">#命令入队</span></span><br><span class="line">127.0.0.1:6666> <span class="built_in">set</span> k2 v2</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6666> get k2</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6666> <span class="built_in">set</span> k3 v3</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6666> mget k1 k2 k3</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6666> <span class="built_in">exec</span> <span class="comment">#执行命令</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><span class="line">5) 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"> </span><br><span class="line"><span class="comment">############################################################################################################ 放弃事务</span></span><br><span class="line">127.0.0.1:6666> multi</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> <span class="built_in">set</span> k1 v1</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6666> <span class="built_in">set</span> k2 v2</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6666> <span class="built_in">set</span> k4 v4</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6666> DISCARD <span class="comment">#取消事务</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> get k4 <span class="comment">#事务队列中的命令都不会被执行</span></span><br><span class="line">(nil)</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li><p>编译型异常(代码有问题、命令有错),事务中的命令不会被执行</p><ul><li><pre><code class="bash">127.0.0.1:6666> multiOK127.0.0.1:6666> set k1 v1QUEUED127.0.0.1:6666> set k2 v2QUEUED127.0.0.1:6666> set k3 v3QUEUED127.0.0.1:6666> getset k3 #错误的命令(error) ERR wrong number of arguments for 'getset' command127.0.0.1:6666> exec #执行事务报错(error) EXECABORT Transaction discarded because of previous errors.127.0.0.1:6666> keys * #所有命令都不会执行(empty array)<figure class="highlight plain"><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"></span><br><span class="line">- 运行时异常(1/0),如果事务队列中存在语法性、那么执行命令的时候、其他命令是可以正常执行的、错误命令抛出异常</span><br><span class="line"></span><br><span class="line"> - ```bash</span><br><span class="line"> 127.0.0.1:6666> set k1 v1</span><br><span class="line"> OK</span><br><span class="line"> 127.0.0.1:6666> multi</span><br><span class="line"> OK</span><br><span class="line"> 127.0.0.1:6666> incr k1</span><br><span class="line"> QUEUED</span><br><span class="line"> 127.0.0.1:6666> set k2 v2</span><br><span class="line"> QUEUED</span><br><span class="line"> 127.0.0.1:6666> set k3 v3</span><br><span class="line"> QUEUED</span><br><span class="line"> 127.0.0.1:6666> get k2</span><br><span class="line"> QUEUED</span><br><span class="line"> 127.0.0.1:6666> exec</span><br><span class="line"> 1) (error) ERR value is not an integer or out of range</span><br><span class="line"> 2) OK</span><br><span class="line"> 3) OK</span><br><span class="line"> 4) "v2"</span><br></pre></td></tr></table></figure></code></pre></li></ul></li></ul><p>锁:Reids可以实现乐观锁</p><h2 id="监控Watch"><a href="#监控Watch" class="headerlink" title="监控Watch"></a>监控Watch</h2><p><strong>悲观锁:</strong></p><ul><li>很悲观,认为什么时候都有问题,无论做什么都会加锁</li></ul><p><strong>乐观锁:</strong></p><ul><li>很乐观,认为什么时候都不会出现问题,所以不会上锁。更新数据的时候去判断一下,在此期间是否有人修改过这个数据</li><li>获取version</li><li>更新的时候比较version</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">#乐观锁正常执行成功</span></span><br><span class="line">127.0.0.1:6666> <span class="built_in">set</span> get 100</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> <span class="built_in">set</span> out 0</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> flushdb</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> <span class="built_in">set</span> money 100</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> <span class="built_in">set</span> out 0</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> watch money <span class="comment">#监视money对象</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> multi <span class="comment">#事务正常结束,数据期间没有发生变动,这个时候就正常执行成功</span></span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> decrby money 20</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6666> incrby out 20</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6666> <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><span class="line"><span class="comment">#在事务执行的同时其它操作仍然在进行</span></span><br><span class="line">127.0.0.1:6666> watch money</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> multi</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> decrby money 20 <span class="comment">#同一时间 127.0.0.1:6666> DECRBY money 20</span></span><br><span class="line">QUEUED (<span class="built_in">integer</span>) 60 </span><br><span class="line">127.0.0.1:6666> incrby out 20</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6666> <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><span class="line">127.0.0.1:6666> watch money </span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> multi</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6666> DECRBY money 20</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6666> INCRBY out 20</span><br><span class="line">QUEUED</span><br><span class="line">127.0.0.1:6666> <span class="built_in">exec</span> <span class="comment">#执行之前,另外一个线程,修改了我们的值,就会导致事务执行失败</span></span><br><span class="line">(nil)</span><br></pre></td></tr></table></figure><p><strong>如果监控失败,获取最新的值就好</strong></p><p><img src="/2021/02/10/redis/image-20210202211534981.png" alt="image-20210202211534981"></p><h1 id="Jedis"><a href="#Jedis" class="headerlink" title="Jedis"></a>Jedis</h1><p>我们要使用java来操作redis</p><blockquote><p>什么是Jedis</p><ul><li>官方推荐的java连接开发工具</li><li>使用java操作java的中间件</li><li>如果需要使用java操作redis,那么一定要对jedis十分熟悉</li></ul></blockquote><p>测试</p><ol><li><p>导入对应的依赖</p><figure class="highlight xml"><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="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="comment"><!-- https://mvnrepository.com/artifact/redis.clients/jedis --></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>redis.clients<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>jedis<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>3.3.0<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>com.alibaba<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>fastjson<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>1.2.75<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependencies</span>></span></span><br></pre></td></tr></table></figure></li><li><p>编码测试</p><ul><li>连接数据库</li><li>操作命令</li><li>断开连接</li></ul></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></pre></td><td class="code"><pre><span class="line"><span class="comment">//测试连接是否成功</span></span><br><span class="line"><span class="keyword">package</span> com.jonyon;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> redis.clients.jedis.Jedis;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">test</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> Jedis jedis = <span class="keyword">new</span> Jedis(<span class="string">"39.97.212.128"</span>,<span class="number">6666</span>);</span><br><span class="line"> System.out.println(jedis.ping()); <span class="comment">//输出pong</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jonyon;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> redis.clients.jedis.Jedis;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">test</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> Jedis jedis = <span class="keyword">new</span> Jedis(<span class="string">"39.97.212.128"</span>,<span class="number">6666</span>);</span><br><span class="line"> System.out.println(<span class="string">"清空数据:"</span>+jedis.flushDB());</span><br><span class="line"> System.out.println(<span class="string">"判断吧某个键是否存在:"</span>+jedis.exists(<span class="string">"username"</span>));</span><br><span class="line"> System.out.println(<span class="string">"新增用户键值对:"</span>+jedis.set(<span class="string">"username"</span>,<span class="string">"jonyon"</span>));</span><br><span class="line"> System.out.println(<span class="string">"新增密码键值对:"</span>+jedis.set(<span class="string">"password"</span>,<span class="string">"123456"</span>));</span><br><span class="line"> Set<String> keys = jedis.keys(<span class="string">"*"</span>);</span><br><span class="line"> System.out.println(<span class="string">"系统中所有的键值对是:"</span>+keys);</span><br><span class="line"> System.out.println(<span class="string">"删除键password:"</span>+jedis.del(<span class="string">"password"</span>));</span><br><span class="line"> System.out.println(<span class="string">"判断键password是否存在:"</span>+jedis.exists(<span class="string">"password"</span>));</span><br><span class="line"> System.out.println(<span class="string">"查看键username锁存储的值的类型:"</span>+jedis.type(<span class="string">"username"</span>));</span><br><span class="line"> System.out.println(<span class="string">"随机返回key空间的一个:"</span>+jedis.randomKey());</span><br><span class="line"> System.out.println(<span class="string">"重命名key:"</span>+jedis.rename(<span class="string">"username"</span>,<span class="string">"name"</span>));</span><br><span class="line"> System.out.println(<span class="string">"按索引查询:"</span>+jedis.select(<span class="number">0</span>));</span><br><span class="line"> System.out.println(<span class="string">"删除当前选择数据库中的所有key:"</span>+jedis.flushDB());</span><br><span class="line"> System.out.println(<span class="string">"返回当前数据库中key的数目:"</span>+jedis.dbSize());</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">清空数据:OK</span><br><span class="line">判断吧某个键是否存在:<span class="keyword">false</span></span><br><span class="line">新增用户键值对:OK</span><br><span class="line">新增密码键值对:OK</span><br><span class="line">系统中所有的键值对是:[password, username]</span><br><span class="line">删除键password:<span class="number">1</span></span><br><span class="line">判断键password是否存在:<span class="keyword">false</span></span><br><span class="line">查看键username锁存储的值的类型:string</span><br><span class="line">随机返回key空间的一个:username</span><br><span class="line">重命名key:OK</span><br><span class="line">按索引查询:OK</span><br><span class="line">删除当前选择数据库中的所有key:OK</span><br><span class="line">返回当前数据库中key的数目:<span class="number">0</span></span><br><span class="line"></span><br><span class="line">Process finished with exit code <span class="number">0</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="事务操作"><a href="#事务操作" class="headerlink" title="事务操作"></a>事务操作</h2><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.jonyon;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.alibaba.fastjson.JSONObject;</span><br><span class="line"><span class="keyword">import</span> redis.clients.jedis.Jedis;</span><br><span class="line"><span class="keyword">import</span> redis.clients.jedis.Transaction;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">test</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> Jedis jedis = <span class="keyword">new</span> Jedis(<span class="string">"39.97.212.128"</span>,<span class="number">6666</span>);</span><br><span class="line"> jedis.flushDB();</span><br><span class="line"> JSONObject jsonObject = <span class="keyword">new</span> JSONObject();</span><br><span class="line"> jsonObject.put(<span class="string">"hello"</span>,<span class="string">"hello"</span>);</span><br><span class="line"> jsonObject.put(<span class="string">"name"</span>,<span class="string">"jonyon"</span>);</span><br><span class="line"> <span class="comment">//开启事务</span></span><br><span class="line"> Transaction multi = jedis.multi();</span><br><span class="line"> String s = jsonObject.toJSONString();</span><br><span class="line"> <span class="keyword">try</span>{</span><br><span class="line"> multi.set(<span class="string">"user1"</span>,s);</span><br><span class="line"> multi.set(<span class="string">"user2"</span>,s);</span><br><span class="line"> <span class="keyword">int</span> i=<span class="number">1</span>/<span class="number">0</span>; <span class="comment">//代码抛出异常,事务执行失败</span></span><br><span class="line"> multi.exec(); <span class="comment">//执行事务</span></span><br><span class="line"> }<span class="keyword">catch</span> (Exception e){</span><br><span class="line"> multi.discard(); <span class="comment">//放弃事务</span></span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">finally</span> {</span><br><span class="line"> System.out.println(jedis.get(<span class="string">"user1"</span>));</span><br><span class="line"> System.out.println(jedis.get(<span class="string">"user2"</span>));</span><br><span class="line"> jedis.close(); <span class="comment">//关闭连接</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><h1 id="SpringBoot整合"><a href="#SpringBoot整合" class="headerlink" title="SpringBoot整合"></a>SpringBoot整合</h1><p>SpringBoot操作数据 : Spring-data jpa jdbc mongodb redis</p><p>SpringData也是和SpringBoot齐名的项目</p><p>说明:在SpringBoot2.X之后,原来使用的jedis被替换为了lettuce</p><p>jedis:底层采用直连,多个线程操作的话是不安全的,如果想要避免不安全的,使用jedis pool连接池 更像 BIO模式</p><p>lettuce:底层采用Netty,实例可以在多个线程下共享,不存在线程不安全的情况,可以减少线程数据,更像 NIO模式</p><h2 id="整合测试"><a href="#整合测试" class="headerlink" title="整合测试"></a>整合测试</h2><ol><li><p>导入依赖</p><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="meta"><?xml version="1.0" encoding="UTF-8"?></span></span><br><span class="line"><span class="tag"><<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">"http://maven.apache.org/POM/4.0.0"</span> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag"> <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">modelVersion</span>></span>4.0.0<span class="tag"></<span class="name">modelVersion</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">parent</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-parent<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.4.2<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">relativePath</span>/></span> <span class="comment"><!-- lookup parent from repository --></span></span><br><span class="line"> <span class="tag"></<span class="name">parent</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>com.joyon<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>redis-springboot<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>0.0.1-SNAPSHOT<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">name</span>></span>redis-springboot<span class="tag"></<span class="name">name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">description</span>></span>Demo project for Spring Boot<span class="tag"></<span class="name">description</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">properties</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">java.version</span>></span>1.8<span class="tag"></<span class="name">java.version</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">properties</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependencies</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-data-redis<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-devtools<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>runtime<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-configuration-processor<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.projectlombok<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>lombok<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-test<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">scope</span>></span>test<span class="tag"></<span class="name">scope</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">dependencies</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">build</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-maven-plugin<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">excludes</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">exclude</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.projectlombok<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>lombok<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">exclude</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">excludes</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">configuration</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugin</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">plugins</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">build</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"></<span class="name">project</span>></span></span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ol><ol start="2"><li><p>配置连接</p><figure class="highlight yaml"><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="attr">spring:</span></span><br><span class="line"> <span class="attr">redis:</span></span><br><span class="line"> <span class="attr">host:</span> <span class="number">39.97</span><span class="number">.212</span><span class="number">.128</span></span><br><span class="line"> <span class="attr">port:</span> <span class="number">6666</span></span><br></pre></td></tr></table></figure></li></ol><ol start="3"><li><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.joyon;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.junit.jupiter.api.Test;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.test.context.SpringBootTest;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.connection.RedisConnection;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.core.RedisTemplate;</span><br><span class="line"></span><br><span class="line"><span class="meta">@SpringBootTest</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">RedisSpringbootApplicationTests</span> </span>{</span><br><span class="line"> <span class="meta">@Autowired</span></span><br><span class="line"> <span class="keyword">private</span> RedisTemplate redisTemplate;</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">contextLoads</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">//redisTemplate.opsForList(); //操作list</span></span><br><span class="line"> <span class="comment">//redisTemplate.opsForValue(); //操作String</span></span><br><span class="line"> <span class="comment">//redisTemplate.opsForHash(); //操作hash</span></span><br><span class="line"> <span class="comment">//redisTemplate.opsForSet(); //操作set</span></span><br><span class="line"> <span class="comment">//redisTemplate.opsForZSet(); //操作zset...</span></span><br><span class="line"> <span class="comment">//获取redis的连接对象</span></span><br><span class="line"> <span class="comment">//RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();</span></span><br><span class="line"> <span class="comment">//connection.flushAll();</span></span><br><span class="line"> <span class="comment">//connection.flushDb();</span></span><br><span class="line"> <span class="comment">//connection.close();</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img src="/2021/02/10/redis/image-20210202223422550.png" alt="image-20210202223422550"></p></li></ol><p><img src="/2021/02/10/redis/image-20210202223432941.png" alt="image-20210202223432941"></p><p>直接传递对象会报为序列化异常</p><p><img src="/2021/02/10/redis/image-20210203195420039.png" alt="image-20210203195420039"></p><h1 id="Redis-conf详解"><a href="#Redis-conf详解" class="headerlink" title="Redis.conf详解"></a>Redis.conf详解</h1><blockquote><p>单位</p></blockquote><p><img src="/2021/02/10/redis/image-20210206161655780.png" alt="image-20210206161655780"></p><ul><li>配置文件unit单位对大小写<strong>不敏感</strong></li></ul><blockquote><p>包含</p></blockquote><p><img src="/2021/02/10/redis/image-20210206161819864.png" alt="image-20210206161819864"></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><span class="line">3</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="comment">#保护模式</span></span><br><span class="line">port 6379 <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></pre></td><td class="code"><pre><span class="line">daemonize yes <span class="comment">#以守护进程的方式运行,默认是no,我们需要自己开启为yes</span></span><br><span class="line">pidfile /var/run/redis_6379.pid <span class="comment">#如果以后台方式运行,我们就需要指定一个pid文件</span></span><br></pre></td></tr></table></figure><p>日志</p><p><img src="/2021/02/10/redis/image-20210206162327641.png" alt="image-20210206162327641"></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">logfile <span class="string">""</span> <span class="comment">#日志的文件生产名</span></span><br><span class="line">databases <span class="comment">#数据库的数量默认是16个数据库</span></span><br><span class="line">always-show-logo yes <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><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">save 900 1 <span class="comment">#900秒内如果至少有1个key进行了修改,那么我们就进行持久化操作</span></span><br><span class="line">save 300 10 <span class="comment">#300秒内如果至少有10个key进行了修改,那么我们就进行持久化操作</span></span><br><span class="line">save 60 10000 <span class="comment">#60秒内如果至少有10000个key进行了修改,那么我们就进行持久化操作</span></span><br><span class="line"></span><br><span class="line">stop-writes-on-bgsave-error yes <span class="comment">#持久化如果出错,是否还要继续工作</span></span><br><span class="line"></span><br><span class="line">rdbcompression yes <span class="comment">#是否压缩rdb文件,需要消耗一些cpu资源</span></span><br><span class="line"></span><br><span class="line">rdbchecksum yes <span class="comment">#保存rdb文件的时候,进行错误的检测校验</span></span><br><span class="line"></span><br><span class="line">dir ./ <span class="comment">#rdb文件保存的目录</span></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></pre></td><td class="code"><pre><span class="line">127.0.0.1:6666> config get requirepass</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:6666> 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:6666> 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><p><img src="/2021/02/10/redis/image-20210206163931411.png" alt="image-20210206163931411"></p><blockquote><p>限制CLIENTS</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></pre></td><td class="code"><pre><span class="line">maxclients 10000 <span class="comment">#设置能连接上redis的最大客户端数量</span></span><br><span class="line">maxmemory <bytes> <span class="comment">#redis配置最大的内存容量 </span></span><br><span class="line">maxmemory-policy noeviction <span class="comment">#内存到达上限之后的处理策略</span></span><br><span class="line">1、volatile-lru:只对设置了过期时间的key进行LRU(默认值) </span><br><span class="line">2、allkeys-lru : 删除lru算法的key </span><br><span class="line">3、volatile-random:随机删除即将过期key </span><br><span class="line">4、allkeys-random:随机删除 </span><br><span class="line">5、volatile-ttl : 删除即将过期的 </span><br><span class="line">6、noeviction : 永不过期,返回错误</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></pre></td><td class="code"><pre><span class="line">appendonly no <span class="comment">#默认不开启aof模式,默认使用rdb持久化的,在大部分情况下,rdb完全够用</span></span><br><span class="line">appendfilename “appendonly.aof” <span class="comment">#持久化的文件的名字</span></span><br><span class="line"><span class="comment">#appendfsync always #每次修改都会sync(同步),消耗性能</span></span><br><span class="line">appendfsync everysec <span class="comment">#每秒执行一次sync,可能会丢失这一秒的数据</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><blockquote><p>Redis是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失,所以Redis提供了持久化功能</p></blockquote><h2 id="RDB-Redis-Database"><a href="#RDB-Redis-Database" class="headerlink" title="RDB(Redis Database)"></a>RDB(Redis Database)</h2><blockquote><p>什么是RDB</p></blockquote><p><img src="/2021/02/10/redis/image-20210206170015526.png" alt="image-20210206170015526"></p><p><img src="/2021/02/10/redis/image-20210206170640050.png" alt="image-20210206170640050"></p><p>RDB保存的文件是dump.rdb 都是在我们的配置文件中进行配置的</p><p><img src="/2021/02/10/redis/image-20210206170726410.png" alt="image-20210206170726410"></p><p>触发机制</p><ul><li>save的规则满足的情况下,会自动触发rdb规则</li><li>执行flushall命令,也会触发我们的edb规则</li><li>退出reids,也会产生rdb文件</li></ul><p>备份就会自动生成一个dump.rdb文件</p><p><img src="/2021/02/10/redis/image-20210206171708550.png" alt="image-20210206171708550"></p><blockquote><p>如何恢复rdb文件</p></blockquote><ul><li><p>只需要将rdb文件放在我们redis启动目录就可以,redis启动的时候会自动检查dump.rdb恢复其中的数据</p></li><li><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></pre></td><td class="code"><pre><span class="line">127.0.0.1:6666> config get dir</span><br><span class="line">1) <span class="string">"dir"</span></span><br><span class="line">2) <span class="string">"/data"</span> <span class="comment">#如果在这个目录下存在dump.rdb文件,启动就会自动恢复其中的数据</span></span><br></pre></td></tr></table></figure></li></ul><p>优点:</p><ul><li>适合大规模的数据恢复</li><li>对数据的完整性要求不高</li></ul><p>缺点:</p><ul><li>需要一定的时间间隔进程操作,如果redis宕机了,这个最后一次修改数据就没有了</li><li>fork进程的时候,会占用一定的内存空间</li></ul><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><blockquote><p>将我们的所有命令都记录下来,相当于history,恢复的时候就把这个文件全部执行一遍</p></blockquote><p><img src="/2021/02/10/redis/image-20210206174321626.png" alt="image-20210206174321626"></p><p><img src="/2021/02/10/redis/image-20210206174409138.png" alt="image-20210206174409138"></p><p><strong>AOF保存的文件是appendonly.aof文件</strong></p><p><img src="/2021/02/10/redis/image-20210206174512461.png" alt="image-20210206174512461"></p><p>默认是不开启的,我们需要手动进行配置,把no改为yes</p><p>如果aof文件有错误,这时候redis是无法启动的,我们需要修复这个aof文件</p><p>redis给我们提供了一个工具—><strong>redis-check-aof</strong> –fix appendonly.aof</p><p><img src="/2021/02/10/redis/image-20210206175621219.png" alt="image-20210206175621219"></p><p>优点:</p><ul><li>每一次修改都同步,文件的完整性更加好</li><li>每秒同步一次,可能会丢失一秒的数据</li><li>从不同步,效率最高</li></ul><p>缺点:</p><ul><li>相对于数据文件来说,aof远大于rdb,修复速度也比rdb慢</li><li>aof运行效率也要比rdb慢,所以我们redis默认的配置就是rdb持久化</li></ul><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>第一个:消息发送者 第二个:频道 第三个:消息订阅者</p><p><img src="/2021/02/10/redis/image-20210210121535607.png" alt="image-20210210121535607"></p><p><img src="/2021/02/10/redis/image-20210210122008450.png" alt="image-20210210122008450"></p><h2 id="命令"><a href="#命令" class="headerlink" title="命令"></a>命令</h2><p><img src="/2021/02/10/redis/image-20210210122153367.png" alt="image-20210210122153367"></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></pre></td><td class="code"><pre><span class="line">127.0.0.1:6666> SUBSCRIBE jonyon</span><br><span class="line">Reading messages... (press Ctrl-C to quit)</span><br><span class="line">1) <span class="string">"subscribe"</span></span><br><span class="line">2) <span class="string">"jonyon"</span></span><br><span class="line">3) (<span class="built_in">integer</span>) 1</span><br><span class="line">1) <span class="string">"message"</span></span><br><span class="line">2) <span class="string">"jonyon"</span></span><br><span class="line">3) <span class="string">"hello,jonyon"</span></span><br><span class="line">1) <span class="string">"message"</span></span><br><span class="line">2) <span class="string">"jonyon"</span></span><br><span class="line">3) <span class="string">"bye,jonyon"</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><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6666> PUBLISH jonyon <span class="string">"hello,jonyon"</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line">127.0.0.1:6666> PUBLISH jonyon <span class="string">"bye,jonyon"</span></span><br><span class="line">(<span class="built_in">integer</span>) 1</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p><img src="/2021/02/10/redis/image-20210210172831223.png" alt="image-20210210172831223"></p><h1 id="Redis主从复制"><a href="#Redis主从复制" class="headerlink" title="Redis主从复制"></a>Redis主从复制</h1><h2 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h2><p><img src="/2021/02/10/redis/image-20210210174956431.png" alt="image-20210210174956431"></p><p>对于这种场景,我们可以使用如下这种架构:</p><p><img src="/2021/02/10/redis/image-20210210175400947.png" alt="image-20210210175400947"></p><p>主从复制,读写分离,80%的情况下都是在进行读写操作,减缓服务器的压力。架构中经常使用一主二从</p><h2 id="环境配置"><a href="#环境配置" class="headerlink" title="环境配置"></a>环境配置</h2><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:6666> 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_replid:d81f74b76b44e71d16c9b21fd2dd060669e81ef3</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><p>redis集群:使用docker启动三个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></pre></td><td class="code"><pre><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]<span class="comment"># docker run -d -p 6667:6379 redis</span></span><br><span class="line">d4fe18ec3ccf625cf0fabb481138f734f51a03663b4b4823a8f1ceb290fd48c4</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]<span class="comment"># docker run -d -p 6668:6379 redis</span></span><br><span class="line">a5adf8a98ac6193bb1f93c452baf3d0aeaa1be9200e0d5da9ea9bf8eee63c901</span><br></pre></td></tr></table></figure><h2 id="一主二从"><a href="#一主二从" class="headerlink" title="一主二从"></a>一主二从</h2><p><strong>默认情况下,每台redis服务器都是主节点</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">#配置两台从机</span></span><br><span class="line">127.0.0.1:6667> SLAVEOF 39.97.212.128 6666</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6667> info replication</span><br><span class="line"><span class="comment"># Replication</span></span><br><span class="line">role:slave <span class="comment">#当前角色是从机</span></span><br><span class="line">master_host:39.97.212.128</span><br><span class="line">master_port:6666</span><br><span class="line">master_link_status:up</span><br><span class="line">master_last_io_seconds_ago:8</span><br><span class="line">master_sync_in_progress:0</span><br><span class="line">slave_repl_offset:70</span><br><span class="line">slave_priority:100</span><br><span class="line">slave_read_only:1</span><br><span class="line">connected_slaves:0</span><br><span class="line">master_replid:36c75a084ec9e0ce94a2cb0a4bbb2f44290a3772</span><br><span class="line">master_replid2:0000000000000000000000000000000000000000</span><br><span class="line">master_repl_offset:70</span><br><span class="line">second_repl_offset:-1</span><br><span class="line">repl_backlog_active:1</span><br><span class="line">repl_backlog_size:1048576</span><br><span class="line">repl_backlog_first_byte_offset:71</span><br><span class="line">repl_backlog_histlen:0</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">127.0.0.1:6668> SLAVEOF 39.97.212.128 6666</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6668> info replication</span><br><span class="line"><span class="comment"># Replication</span></span><br><span class="line">role:slave</span><br><span class="line">master_host:39.97.212.128</span><br><span class="line">master_port:6666</span><br><span class="line">master_link_status:up</span><br><span class="line">master_last_io_seconds_ago:0</span><br><span class="line">master_sync_in_progress:0</span><br><span class="line">slave_repl_offset:42</span><br><span class="line">slave_priority:100</span><br><span class="line">slave_read_only:1</span><br><span class="line">connected_slaves:0</span><br><span class="line">master_replid:36c75a084ec9e0ce94a2cb0a4bbb2f44290a3772</span><br><span class="line">master_replid2:0000000000000000000000000000000000000000</span><br><span class="line">master_repl_offset:42</span><br><span class="line">second_repl_offset:-1</span><br><span class="line">repl_backlog_active:1</span><br><span class="line">repl_backlog_size:1048576</span><br><span class="line">repl_backlog_first_byte_offset:1</span><br><span class="line">repl_backlog_histlen:42</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">#主机信息</span></span><br><span class="line">127.0.0.1:6666> info replication</span><br><span class="line"><span class="comment"># Replication</span></span><br><span class="line">role:master</span><br><span class="line">connected_slaves:2 <span class="comment">#有两个从机</span></span><br><span class="line">slave0:ip=39.97.212.128,port=6379,state=online,offset=84,lag=0 <span class="comment">#从机的ip地址,端口信息</span></span><br><span class="line">slave1:ip=39.97.212.128,port=6379,state=online,offset=84,lag=0</span><br><span class="line">master_replid:36c75a084ec9e0ce94a2cb0a4bbb2f44290a3772</span><br><span class="line">master_replid2:0000000000000000000000000000000000000000</span><br><span class="line">master_repl_offset:84</span><br><span class="line">second_repl_offset:-1</span><br><span class="line">repl_backlog_active:1</span><br><span class="line">repl_backlog_size:1048576</span><br><span class="line">repl_backlog_first_byte_offset:1</span><br><span class="line">repl_backlog_histlen:84</span><br></pre></td></tr></table></figure><p>真实的主从配置应该在配置文件中配置,这样的话是永久的;使用命令是暂时的</p><p><strong>细节</strong></p><ul><li>主机可以写,从机不能写只能读。(主机写,从机读)</li><li>主机中的所有信息。都可以被从机保存</li><li>主机断开连接,从机依旧连接到主机,但是没有写操作;如果主机回来了,从机依旧可以直接获取到主机写的信息</li><li>如果是使用命令行来配置的主从关系,这个时候如果从机重启了,从机就会变回主机。只要再次变为从机,就可以再次从主机里面得到值</li></ul><p><strong>复制原理</strong></p><p><img src="/2021/02/10/redis/image-20210210202105168.png" alt="image-20210210202105168"></p><p><strong>层层链路</strong></p><p>上一个M连接下一个S,S依旧无法写入</p><p><img src="/2021/02/10/redis/image-20210210202527893.png" alt="image-20210210202527893"></p><p>如果主机断开了连接,我们可以使用<strong>slaveof no one</strong>让自己变成主机。其他段节点就可以手动连接到最新的这个节点。如果这个时候原来的主机修复,则重新连接。(谋朝篡位手动版)</p><h2 id="哨兵模式"><a href="#哨兵模式" class="headerlink" title="哨兵模式"></a>哨兵模式</h2><p>(自动选举老大的模式)</p><p><strong>概述</strong></p><p><img src="/2021/02/10/redis/image-20210210203233190.png" alt="image-20210210203233190"></p><p><img src="/2021/02/10/redis/image-20210210203433296.png" alt="image-20210210203433296"></p><p><img src="/2021/02/10/redis/image-20210210203617403.png" alt="image-20210210203617403"></p><p><img src="/2021/02/10/redis/image-20210210203652216.png" alt="image-20210210203652216"></p><p>优点</p><ul><li>哨兵集群基于主从复制模式,所有的主从配置优点,他全都有</li><li>主从可以切换,故障可以转移,系统的可用性更好</li><li>哨兵模式就是主从模式的升级,手动到自动,更加健壮</li></ul><p>缺点</p><ul><li>redis不好在线扩容,集群容量一但上限,在线扩容就十分麻烦</li><li>实现哨兵模式的配置是十分麻烦的,里面又很多选择</li></ul><h1 id="Redis缓存穿透和雪崩"><a href="#Redis缓存穿透和雪崩" class="headerlink" title="Redis缓存穿透和雪崩"></a>Redis缓存穿透和雪崩</h1><p>服务的高可用问题</p><p><img src="/2021/02/10/redis/image-20210210205925505.png" alt="image-20210210205925505"></p><p><img src="/2021/02/10/redis/image-20210210210604787.png" alt="image-20210210210604787"></p><h2 id="缓存穿透(查不到)"><a href="#缓存穿透(查不到)" class="headerlink" title="缓存穿透(查不到)"></a>缓存穿透(查不到)</h2><p><strong>概念</strong></p><p><img src="/2021/02/10/redis/image-20210210205912919.png" alt="image-20210210205912919"></p><p><strong>解决方案</strong></p><p><img src="/2021/02/10/redis/image-20210210210823853.png" alt="image-20210210210823853"></p><p><img src="/2021/02/10/redis/image-20210210210843236.png" alt="image-20210210210843236"></p><p><img src="/2021/02/10/redis/image-20210210210917691.png" alt="image-20210210210917691"></p><h2 id="缓存击穿(量太大,缓存过期)"><a href="#缓存击穿(量太大,缓存过期)" class="headerlink" title="缓存击穿(量太大,缓存过期)"></a>缓存击穿(量太大,缓存过期)</h2><p>微博服务器宕机</p><p><strong>概念</strong></p><p><img src="/2021/02/10/redis/image-20210210211027043.png" alt="image-20210210211027043"></p><p><strong>解决方案</strong></p><p><img src="/2021/02/10/redis/image-20210210211218888.png" alt="image-20210210211218888"></p><p><img src="/2021/02/10/redis/image-20210210211442389.png" alt="image-20210210211442389"></p><p>、</p><h2 id="缓存雪崩"><a href="#缓存雪崩" class="headerlink" title="缓存雪崩"></a>缓存雪崩</h2><p><strong>概念</strong></p><p><img src="/2021/02/10/redis/image-20210210211606223.png" alt="image-20210210211606223"></p><p><img src="/2021/02/10/redis/image-20210210211626785.png" alt="image-20210210211626785"></p><p>双十一:停掉一些服务,保证主要的服务可用</p><p><strong>解决方案</strong></p><p><img src="/2021/02/10/redis/image-20210210211852028.png" alt="image-20210210211852028"></p>]]></content>
<summary type="html"><h1 id="NoSQL概述"><a href="#NoSQL概述" class="headerlink" title="NoSQL概述"></a>NoSQL概述</h1><h2 id="为什么要用NoSQL"><a href="#为什么要用NoSQL" class="headerlink" title="为什么要用NoSQL"></a>为什么要用NoSQL</h2><p>现在是大数据时代,一般的数据库无法进行分析处理</p>
<ol>
<li><p>单机MySQL年代</p>
<p><img src="/2021/02/10/redis/image-20210130134059341.png" alt="image-20210130134059341"></p>
<p>90年代,一个基本的网站访问量一般不会太大,单个数据库完全足够</p>
<p>那个时候更多的是去使用静态网页html,服务器更本没有太大的压力</p>
<p>在这种情况下,整个网站的瓶颈是什么</p>
<p>1.数据量如果太大,一个机器放不下</p>
<p>2.数据的索引,300万条数据,一定需要创建索引(B+Tree),一个机器内存放不下</p>
<p>3.访问量,读写混合,一个服务器承受不了</p>
<p>只要出现以上三个情况之一,那么就需要升级</p></li></ol></summary>
<category term="数据库" scheme="http://www.jonyonwzj.top/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
<category term="中间件" scheme="http://www.jonyonwzj.top/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/%E4%B8%AD%E9%97%B4%E4%BB%B6/"/>
<category term="NoSQL" scheme="http://www.jonyonwzj.top/tags/NoSQL/"/>
</entry>
<entry>
<title>MySQL</title>
<link href="http://www.jonyonwzj.top/2020/12/29/MySQL/"/>
<id>http://www.jonyonwzj.top/2020/12/29/MySQL/</id>
<published>2020-12-29T08:48:19.000Z</published>
<updated>2021-04-02T11:47:30.291Z</updated>
<content type="html"><![CDATA[<h1 id="MySQL"><a href="#MySQL" class="headerlink" title="MySQL"></a>MySQL</h1><p>javaEE 企业级开发 Web</p><p>前端:页面渲染,展示数据</p><p>后台:连接点</p><ul><li>连接数据库JDBC</li><li>连接前端(控制,控制视图跳转,给前端传数据)</li></ul><p>数据库:存储数据(TXT,Excel,Word)</p><a id="more"></a><p>5.7版本最稳定</p><h2 id="什么是数据库"><a href="#什么是数据库" class="headerlink" title="什么是数据库"></a>什么是数据库</h2><p>数据库(DB database)</p><p>概念:数据仓库,安装在操作系统(windows,linux)上,SQL可以存储大量的数据 500万</p><p>作用:存储数据,管理数据</p><h1 id="阿里云规范"><a href="#阿里云规范" class="headerlink" title="阿里云规范"></a>阿里云规范</h1><figure class="highlight sql"><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="comment">--每一个表都必须存在以下五个字段 做项目用的 表示一个记录存在的意义</span></span><br><span class="line">id <span class="comment">--主键</span></span><br><span class="line">version <span class="comment">--乐观锁</span></span><br><span class="line">is_delete <span class="comment">--伪删除</span></span><br><span class="line">gmt_create <span class="comment">--创建时间</span></span><br><span class="line">gmt_update <span class="comment">--修改时间</span></span><br></pre></td></tr></table></figure><h2 id="数据库分类"><a href="#数据库分类" class="headerlink" title="数据库分类"></a>数据库分类</h2><p><strong>关系型数据库(sql)</strong>:</p><ul><li>MySQL Oracle SqlServer DB2 SQLlite</li><li>通过表和表之间,行和列之间的关系进行数据的存储 </li></ul><p><strong>非关系型数据库(nosql—not only sql)</strong>:</p><ul><li>Redis MongoDB</li><li>非关系型数据库,对象存储,通过对象的自身属性来决定</li></ul><p><code>DBMS(数据库管理系统)</code></p><ul><li>数据库的管理软件,科学有效的管理我们的数据。维护和获取数据;</li><li>MySQL本质是一个数据库管理系统</li></ul><h2 id="新建数据库"><a href="#新建数据库" class="headerlink" title="新建数据库"></a>新建数据库</h2><p><img src="/2020/12/29/MySQL/image-20201227135821340.png" alt="image-20201227135821340"></p><h2 id="命令行操作数据库"><a href="#命令行操作数据库" class="headerlink" title="命令行操作数据库"></a>命令行操作数据库</h2><figure class="highlight sql"><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">mysql -uroot -proot <span class="comment">--连接数据库</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">update</span> mysql.user <span class="keyword">set</span> authentication_string=<span class="keyword">password</span>(<span class="string">'root'</span>) <span class="keyword">where</span> <span class="keyword">user</span>=<span class="string">'root'</span> <span class="keyword">and</span> Host=<span class="string">'localhost'</span>; <span class="comment">--修改用户密码</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">flush</span> <span class="keyword">privileges</span> <span class="comment">--刷新权限</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">show</span> <span class="keyword">databases</span>; <span class="comment">--查看所有数据库</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">use</span> school; <span class="comment">--切换数据库</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">show</span> <span class="keyword">tables</span>; <span class="comment">--查看数据库中所有的表</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">describe</span> student; <span class="comment">--显示数据库中所有的表信息</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">create</span> <span class="keyword">database</span> www; <span class="comment">--创建一个数据库</span></span><br></pre></td></tr></table></figure><p>数据库xxxx语言 CRUD增删改查</p><p>DDL Definition 定义</p><p>DML Manipulation 操作 </p><p>DQL Query 查询</p><p>DCL Control 控制</p><h1 id="操作数据库"><a href="#操作数据库" class="headerlink" title="操作数据库"></a>操作数据库</h1><p>操作数据库>操作数据库中的表>操作数据库中表的数据</p><p>mysql关键字不区分大小写</p><h2 id="操作数据库-1"><a href="#操作数据库-1" class="headerlink" title="操作数据库"></a>操作数据库</h2><p><strong>创建数据库</strong></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">create</span> <span class="keyword">database</span> [<span class="keyword">if</span> <span class="keyword">not</span> <span class="keyword">exists</span>] school;</span><br></pre></td></tr></table></figure><p><strong>删除数据库</strong></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">drop</span> <span class="keyword">database</span> [<span class="keyword">if</span> <span class="keyword">exists</span>] school;</span><br></pre></td></tr></table></figure><p><strong>使用数据库</strong></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> <span class="string">'school'</span>; <span class="comment">--如果你的表名或字段名是一个特殊字符,就需要带' '</span></span><br></pre></td></tr></table></figure><h2 id="数据库的列类型"><a href="#数据库的列类型" class="headerlink" title="数据库的列类型"></a>数据库的列类型</h2><p><strong>数值</strong></p><ul><li>tinyint 十分小的数据,一个字节</li><li>smallint 较小的数据 , 两个字节</li><li>mediumint 中等大小的数据,三个字节</li><li>int 标准的整数, 四个字节 “常用的” int</li><li>bigint 较大的数据,八个字节 long</li><li>float 浮点数 ,四个字节 float</li><li>double 浮点数, 八个字节(精度问题)double</li><li>decimal 字符串形式的浮点数 金融计算的时候,一般使用decimal</li></ul><p><strong>字符串</strong></p><ul><li>char 固定大小的字符串 0-255</li><li>varchar 可变字符串 0-65535 常用的 String</li><li>tinytest 微型文本 2^8-1 (存一般的博客文章)</li><li>text 文本串 2^16-1 (保存特别大的文本) 较常用</li></ul><p><strong>时间日期</strong></p><p>java.util.date</p><ul><li>date YYYY-MM-DD 日期格式</li><li>time HH-mm-ss 时间格式</li><li>datetime YYYY-MM-DD HH-mm-ss 最常用的时间格式</li><li>timestrap 时间戳 197.1.1到现在的毫秒数 较为常用</li><li>year 年份表示</li></ul><p><strong>null</strong></p><ul><li>没有值,未知</li><li>注意,不要使用null进行运算</li></ul><h2 id="数据库的字段属性(重点)"><a href="#数据库的字段属性(重点)" class="headerlink" title="数据库的字段属性(重点)"></a>数据库的字段属性(重点)</h2><p>Unsigned(无符号):</p><ul><li>无符号整数</li><li>不能声明为负数</li></ul><p>zerofill:</p><ul><li>0填充的</li><li>不足的位数用0填充 例如:int(3) , 数据为5—-填充为005</li></ul><p>自增:</p><ul><li>自动在上一条记录的基础上+1</li><li>通常用来设计唯一的主键 index,必须是整数类型</li><li>可以自定义设计主键自增的起始值和步长</li></ul><p>非空</p><ul><li>假设设置为not null,如果不给他赋值,就会报错</li><li>null 如果不填写值,默认为null</li></ul><p>默认</p><ul><li>设置默认的值</li><li>sex 默认值为男,如果不指定该列的值,则会有默认的值</li></ul><h2 id="创建数据库表"><a href="#创建数据库表" class="headerlink" title="创建数据库表"></a>创建数据库表</h2><figure class="highlight sql"><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="keyword">create</span> <span class="keyword">table</span> <span class="keyword">if</span> <span class="keyword">not</span> <span class="keyword">EXISTS</span> student(</span><br><span class="line"><span class="keyword">id</span> <span class="built_in">int</span>(<span class="number">4</span>) <span class="keyword">not</span> <span class="literal">null</span> auto_increment <span class="keyword">comment</span> <span class="string">'学号'</span>,</span><br><span class="line"><span class="keyword">name</span> <span class="built_in">VARCHAR</span>(<span class="number">30</span>) <span class="keyword">not</span> <span class="literal">null</span> <span class="keyword">DEFAULT</span> <span class="string">'匿名'</span> <span class="keyword">comment</span> <span class="string">'姓名'</span>,</span><br><span class="line">pwd <span class="built_in">VARCHAR</span>(<span class="number">20</span>) <span class="keyword">not</span> <span class="literal">null</span> <span class="keyword">default</span> <span class="string">'123456'</span> <span class="keyword">comment</span> <span class="string">'密码'</span>,</span><br><span class="line">sex <span class="built_in">VARCHAR</span>(<span class="number">2</span>) <span class="keyword">not</span> <span class="literal">null</span> <span class="keyword">default</span> <span class="string">'女'</span> <span class="keyword">comment</span> <span class="string">'性别'</span>,</span><br><span class="line">birthday datetime <span class="keyword">default</span> <span class="literal">null</span> <span class="keyword">comment</span> <span class="string">'出生日期'</span>,</span><br><span class="line">address <span class="built_in">VARCHAR</span>(<span class="number">100</span>) <span class="keyword">default</span> <span class="literal">null</span> <span class="keyword">comment</span> <span class="string">'家庭住址'</span>,</span><br><span class="line">email <span class="built_in">VARCHAR</span>(<span class="number">50</span>) <span class="keyword">default</span> <span class="literal">null</span> <span class="keyword">comment</span> <span class="string">'邮箱'</span>,</span><br><span class="line">PRIMARY <span class="keyword">KEY</span> (<span class="keyword">id</span>)</span><br><span class="line">)<span class="keyword">ENGINE</span>=<span class="keyword">INNODB</span> <span class="keyword">default</span> <span class="keyword">CHARSET</span>=utf8</span><br></pre></td></tr></table></figure><h2 id="查看创建数据库的语句"><a href="#查看创建数据库的语句" class="headerlink" title="查看创建数据库的语句"></a>查看创建数据库的语句</h2><figure class="highlight sql"><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">show</span> <span class="keyword">create</span> <span class="keyword">database</span> school <span class="comment">--查看创建数据库的语句</span></span><br><span class="line"><span class="keyword">show</span> <span class="keyword">create</span> <span class="keyword">table</span> student <span class="comment">--查看student数据表的定义语句</span></span><br><span class="line"><span class="keyword">desc</span> student <span class="comment">--显示表的结构</span></span><br></pre></td></tr></table></figure><h2 id="数据表的类型"><a href="#数据表的类型" class="headerlink" title="数据表的类型"></a>数据表的类型</h2><p>关于数据库引擎</p><p>innodb 默认使用</p><p>myisam早些年使用的</p><table><thead><tr><th></th><th>MYISAM</th><th>INNODB</th></tr></thead><tbody><tr><td>事务支持</td><td>不支持</td><td>支持</td></tr><tr><td>数据行锁定</td><td>不支持</td><td>支持</td></tr><tr><td>外键约束</td><td>不支持</td><td>支持</td></tr><tr><td>全文索引</td><td>支持</td><td>不支持</td></tr><tr><td>表空间大小</td><td>较小</td><td>较大,约为myisam的两倍</td></tr></tbody></table><p>常规使用操作:</p><ul><li>MYISAM:节约空间,速度较快</li><li>INNODB:安全性高,支持事务的处理,多表多用户操作</li></ul><p><code>在物理空间存在的位置</code></p><p>所有的数据库文件都存在data目录下,一个文件夹对应一个数据库</p><p>本质还是文件存储</p><p>MySQL引擎在物理文件上的区别</p><ul><li>innoDB在数据库表中只有一个*.frm文件,以及上级目录下的lbdata1文件</li><li>MYISAM对应文件<ul><li>*.frm –表结构的定义文件</li><li>*.MYD –数据文件(data)</li><li>*.MYI –索引文件(index)</li></ul></li></ul><p><code>设置数据库表的字符集编码</code></p><p>CHARSET=utf8</p><p>不设置的话,会是mysql默认的字符集编码(不支持中文)</p><p>MySQL默认编码是Latin1,不支持中文</p><p>在my.ini中配置默认的编码:character-set-server=utf8 (不建议,跨平台无法使用)</p><h2 id="修改和删除表"><a href="#修改和删除表" class="headerlink" title="修改和删除表"></a>修改和删除表</h2><p><strong>修改</strong></p><figure class="highlight sql"><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"><span class="keyword">alter</span> <span class="keyword">table</span> 旧表名 <span class="keyword">rename</span> <span class="keyword">as</span> 新表名 <span class="comment">--修改表名</span></span><br><span class="line"><span class="keyword">alter</span> <span class="keyword">table</span> 表名 <span class="keyword">add</span> age <span class="built_in">int</span>(<span class="number">11</span>) <span class="comment">--增加表的字段</span></span><br><span class="line"><span class="keyword">alter</span> <span class="keyword">table</span> 表名 <span class="keyword">modify</span> age <span class="built_in">varchar</span>(<span class="number">11</span>) <span class="comment">--修改表的字段 修改约束</span></span><br><span class="line"><span class="keyword">alter</span> <span class="keyword">table</span> 表名 <span class="keyword">change</span> 旧字段名 新字段名 <span class="built_in">int</span>(<span class="number">1</span>) <span class="comment">--字段重命名</span></span><br><span class="line"><span class="keyword">alter</span> <span class="keyword">table</span> 表名 <span class="keyword">drop</span> 字段 <span class="comment">--删除表的字段</span></span><br></pre></td></tr></table></figure><p><strong>删除</strong></p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">drop</span> <span class="keyword">table</span> <span class="keyword">if</span> <span class="keyword">exists</span> 表名 <span class="comment">--如果表存在再删除</span></span><br></pre></td></tr></table></figure><h1 id="Mysql数据管理"><a href="#Mysql数据管理" class="headerlink" title="Mysql数据管理"></a>Mysql数据管理</h1><h2 id="外键(了解即可)"><a href="#外键(了解即可)" class="headerlink" title="外键(了解即可)"></a>外键(了解即可)</h2><p>方式一:在创建表的时候增加约束(麻烦,比较复杂)</p><figure class="highlight sql"><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">key FK_gradeid(gradeid),</span><br><span class="line">constraint FK_gradeid foreign key (gradeid) references grade (gradeid)</span><br></pre></td></tr></table></figure><p>删除有外键关系的表时,必须要先删除引用别人的表(从表),再删除被引用的表(主表)</p><p>方式二:创建表成功后,添加外键约束</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">alter</span> <span class="keyword">table</span> 表 <span class="keyword">add</span> <span class="keyword">constraint</span> 约束名 <span class="keyword">foreign</span> <span class="keyword">key</span>(作为外键的列) <span class="keyword">references</span> 哪个表(哪个字段)</span><br></pre></td></tr></table></figure><p>以上操作都是物理外键,数据库级别的外键,我们不建议使用(避免数据库过多造成困扰)</p><p><strong>最佳实践</strong></p><ul><li>数据库就是单纯的表,只用来存数据,只有行(数据)和列(字段)</li><li>我们想使用多张表的数据,想使用外键(程序去实现)</li></ul><h2 id="DML语言(全部记住)"><a href="#DML语言(全部记住)" class="headerlink" title="DML语言(全部记住)"></a>DML语言(全部记住)</h2><p><strong>数据库意义</strong>:数据存储、数据管理</p><p>DML语言:数据操作语言</p><ul><li>insert</li><li>update</li><li>delete</li></ul><h2 id="添加-insert"><a href="#添加-insert" class="headerlink" title="添加(insert)"></a>添加(insert)</h2><figure class="highlight sql"><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">--insert into 表名(字段名1,字段名2,字段名3) values('值1','值2','值3')</span></span><br><span class="line"><span class="comment">--如果不写表的字段他就会一一匹配</span></span><br><span class="line"><span class="comment">--一般写插入语句,我们一定要数据和字段一一对应</span></span><br><span class="line"><span class="comment">--插入多个字段</span></span><br><span class="line"><span class="keyword">insert</span> <span class="keyword">into</span> grade (gradename)</span><br><span class="line"><span class="keyword">values</span></span><br><span class="line">(<span class="string">'大一'</span>),</span><br><span class="line">(<span class="string">'大二'</span>)</span><br></pre></td></tr></table></figure><p>注意事项</p><ul><li>字段和字段之间使用英文逗号隔开</li><li>字段是可以省略的,但后面的值必须一一对应,不能少</li><li>可以同时插入多条数据,values后面的值使用逗号隔开即可 <code>values(),(),()....</code></li></ul><h2 id="修改-update"><a href="#修改-update" class="headerlink" title="修改(update)"></a>修改(update)</h2><p><code>update 修改谁 (条件) set 原来的值=新值</code> </p><p>不指定条件的情况下,会改动所有的表</p><figure class="highlight sql"><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="comment">--修改学员名字,带了条件</span></span><br><span class="line"><span class="keyword">update</span> student <span class="keyword">set</span> <span class="keyword">name</span>=<span class="string">'zhangsan'</span> <span class="keyword">where</span> <span class="keyword">id</span>=<span class="number">1</span>;</span><br><span class="line"><span class="comment">--不指定条件的情况下会改动所有的表</span></span><br><span class="line"><span class="keyword">update</span> student <span class="keyword">set</span> <span class="keyword">name</span>=<span class="string">'zhangsan'</span></span><br><span class="line"><span class="comment">--修改多个属性,逗号隔开</span></span><br><span class="line"><span class="keyword">update</span> student <span class="keyword">set</span> <span class="keyword">name</span>=<span class="string">'zhangsan'</span>,emial=<span class="string">'994057864'</span> <span class="keyword">where</span> <span class="keyword">id</span>=<span class="number">1</span>;</span><br><span class="line"><span class="comment">--update 表名 set 字段名='value' where 条件='value';</span></span><br></pre></td></tr></table></figure><p>条件:where子句 运算符 id等于、大于、小于某个值 在某个区间内修改</p><table><thead><tr><th>操作符</th><th>含义</th><th>范围</th><th>结果</th></tr></thead><tbody><tr><td>=</td><td>范围</td><td>5=6</td><td>false</td></tr><tr><td><>或!=</td><td>不等于</td><td>5<>6</td><td>true</td></tr><tr><td>></td><td>大于</td><td></td><td></td></tr><tr><td><</td><td>小于</td><td></td><td></td></tr><tr><td>>=</td><td>大于等于</td><td></td><td></td></tr><tr><td><=</td><td>小于等于</td><td></td><td></td></tr><tr><td>between…and…</td><td>闭合区间[2,5],在某个范围内</td><td>[2,5]</td><td></td></tr><tr><td>and</td><td>和</td><td>5>1 and 1>2</td><td>false</td></tr><tr><td>or</td><td>或</td><td>5>1or 1>2</td><td>true</td></tr></tbody></table><h2 id="删除-delete"><a href="#删除-delete" class="headerlink" title="删除(delete)"></a>删除(delete)</h2><p>语法:<code>delete from 表名[where 条件]</code></p><figure class="highlight sql"><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"><span class="comment">--删除数据,避免这样写,会全删</span></span><br><span class="line"><span class="keyword">delete</span> <span class="keyword">from</span> student</span><br><span class="line"></span><br><span class="line"><span class="comment">--删除指定数据</span></span><br><span class="line"><span class="keyword">delete</span> <span class="keyword">from</span> student <span class="keyword">where</span> <span class="keyword">id</span>=<span class="number">1</span>;</span><br></pre></td></tr></table></figure><p><code>truncate命令</code></p><p>作用:完全清空一个数据库表,表的结果和索引约束不会变</p><figure class="highlight sql"><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">--清空student表</span></span><br><span class="line"><span class="keyword">truncate</span> student</span><br></pre></td></tr></table></figure><p><code>delete 和 truncate区别</code></p><ul><li>相同点:都会删除数据,都不会删除表结构</li><li>不同:<ul><li>truncate 重新设置 自增列 计数器会归零</li><li>truncate 不会影响事务</li></ul></li></ul><h2 id="DELETE删除的问题"><a href="#DELETE删除的问题" class="headerlink" title="DELETE删除的问题"></a>DELETE删除的问题</h2><p>使用delete删除后,重启数据库,现象</p><ul><li>INNODB 自增列会从1开始(存在内存当中,断电即失)</li><li>MYISAM 继续从上一个自增量开始(存在文件中,不会丢失)</li></ul><h1 id="SELECT完整的语法"><a href="#SELECT完整的语法" class="headerlink" title="SELECT完整的语法"></a>SELECT完整的语法</h1><p><img src="/2020/12/29/MySQL/image-20201228152233605.png" alt="image-20201228152233605"></p><h1 id="DQL查询数据-重点"><a href="#DQL查询数据-重点" class="headerlink" title="DQL查询数据(重点)"></a>DQL查询数据(重点)</h1><h2 id="DQL"><a href="#DQL" class="headerlink" title="DQL"></a>DQL</h2><p><strong>Date Query Language:数据查询语言</strong></p><ul><li>所有的查询操作都用它 select</li><li>简单的查询,复杂的查询它都能做</li><li>数据库中最核心的语言</li><li>使用频率最高的语句</li></ul><h2 id="指定查询字段"><a href="#指定查询字段" class="headerlink" title="指定查询字段"></a>指定查询字段</h2><figure class="highlight sql"><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">-- 查询全部的学生</span></span><br><span class="line"><span class="keyword">select</span> * <span class="keyword">from</span> student</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 查询指定字段</span></span><br><span class="line"><span class="keyword">select</span> studentno,studentname <span class="keyword">from</span> student</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 别名,给结果取一个名字,也可以给表起别名</span></span><br><span class="line"><span class="keyword">select</span> studentno <span class="keyword">as</span> 学号,studentname <span class="keyword">as</span> 学生姓名 <span class="keyword">from</span> student</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 函数 Concat(a,b)拼接字符串</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">CONCAT</span>(<span class="string">'姓名:'</span>,studentname) <span class="keyword">as</span> 新名字 <span class="keyword">from</span> student</span><br></pre></td></tr></table></figure><p>语法:<code>select 字段...from 表</code></p><h3 id="distinct"><a href="#distinct" class="headerlink" title="distinct"></a>distinct</h3><p>作用:去除select查询出来的结果中重复的数据,重复的数据只显示一条</p><figure class="highlight sql"><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="comment">-- 查询有多少同学参加了考试</span></span><br><span class="line"><span class="keyword">select</span> * <span class="keyword">from</span> <span class="keyword">result</span> <span class="comment">-- 查询全都的考试成绩</span></span><br><span class="line"><span class="comment">-- 查询有哪些同学参加了考试</span></span><br><span class="line"><span class="keyword">select</span> studentno <span class="keyword">from</span> <span class="keyword">result</span></span><br><span class="line"><span class="comment">-- 发现重复数据,去重复</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">distinct</span> studentno <span class="keyword">from</span> <span class="keyword">result</span></span><br></pre></td></tr></table></figure><h3 id="数据库的列-表达式"><a href="#数据库的列-表达式" class="headerlink" title="数据库的列(表达式)"></a>数据库的列(表达式)</h3><figure class="highlight sql"><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="keyword">select</span> <span class="keyword">version</span>() <span class="comment">-- 查询系统版本(函数)</span></span><br><span class="line">(elect <span class="number">100</span>*<span class="number">5</span><span class="number">-12</span> <span class="keyword">as</span> 计算结果 <span class="comment">-- 计算(表达式)</span></span><br><span class="line"><span class="keyword">select</span> @@auto_increment_increment <span class="comment">-- 查询自增的步长(变量)</span></span><br><span class="line"><span class="comment">-- 学院考试成绩+1查看</span></span><br><span class="line"><span class="keyword">select</span> studentno,studentresult <span class="keyword">as</span> <span class="string">'提分前'</span><span class="keyword">from</span> <span class="keyword">result</span></span><br><span class="line"><span class="keyword">select</span> studentno,studentresult+<span class="number">1</span> <span class="keyword">as</span> <span class="string">'提分后'</span> <span class="keyword">from</span> <span class="keyword">result</span></span><br></pre></td></tr></table></figure><p>数据库中的表达式:文本值、列、null、函数、计算表达式、系统变量</p><p>select 表达式 from 表</p><h2 id="where条件子句"><a href="#where条件子句" class="headerlink" title="where条件子句"></a>where条件子句</h2><p>作用:检索数据中符合条件的值</p><h3 id="逻辑运算符"><a href="#逻辑运算符" class="headerlink" title="逻辑运算符"></a>逻辑运算符</h3><table><thead><tr><th>运算符</th><th>语法</th><th>描述</th></tr></thead><tbody><tr><td>and &&</td><td></td><td>逻辑与</td></tr><tr><td>or ||</td><td></td><td>逻辑或</td></tr><tr><td>not !</td><td></td><td>逻辑非</td></tr></tbody></table><figure class="highlight sql"><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"><span class="comment">-- 查询考试成绩在95-100之间</span></span><br><span class="line"><span class="keyword">select</span> studentno,studentresult </span><br><span class="line"><span class="keyword">from</span> <span class="keyword">result</span> </span><br><span class="line"><span class="keyword">where</span> studentresult>=<span class="number">95</span> <span class="keyword">and</span> studentresult<=<span class="number">100</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- 模糊查询(区间)</span></span><br><span class="line"><span class="keyword">select</span> studentno,studentresult </span><br><span class="line"><span class="keyword">from</span> <span class="keyword">result</span> </span><br><span class="line"><span class="keyword">where</span> studentresult <span class="keyword">between</span> <span class="number">95</span> <span class="keyword">and</span> <span class="number">100</span></span><br><span class="line"></span><br><span class="line"><span class="comment">--!= 和 not</span></span><br><span class="line"><span class="keyword">select</span> studentno,studentresult </span><br><span class="line"><span class="keyword">from</span> <span class="keyword">result</span> </span><br><span class="line"><span class="keyword">where</span> studentresult!=<span class="number">85</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">select</span> studentno,studentresult </span><br><span class="line"><span class="keyword">from</span> <span class="keyword">result</span> </span><br><span class="line"><span class="keyword">where</span> <span class="keyword">not</span> studentresult=<span class="number">85</span></span><br></pre></td></tr></table></figure><h3 id="模糊查询-比较运算符"><a href="#模糊查询-比较运算符" class="headerlink" title="模糊查询:比较运算符"></a>模糊查询:比较运算符</h3><table><thead><tr><th>运算符</th><th>语法</th><th>描述</th></tr></thead><tbody><tr><td>is null</td><td>a is null</td><td>如果操作符null,则结果为true</td></tr><tr><td>is not null</td><td>a is not null</td><td>如果操作符为 not null ,则结果为true</td></tr><tr><td>between</td><td>a between a and b</td><td>若a在b和c之间,则结果为true</td></tr><tr><td><strong>like</strong></td><td>a like b</td><td>sql匹配,如果a匹配b,则结果true</td></tr><tr><td>in</td><td>a in(a1,a2,a3…)</td><td>假设a在a1或者a2….其中的某一个值,结果为true</td></tr></tbody></table><figure class="highlight sql"><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"><span class="comment">-- like</span></span><br><span class="line"><span class="comment">-- 查询姓张的同学</span></span><br><span class="line"><span class="comment">-- like结合 %(代表0到任意个字符) _(代表一个字符)</span></span><br><span class="line"><span class="keyword">select</span> studentno,studentname</span><br><span class="line"><span class="keyword">from</span> student</span><br><span class="line"><span class="keyword">where</span> studentname <span class="keyword">like</span> <span class="string">'张%'</span></span><br><span class="line"><span class="comment">-- 查询姓张的同学,名字后面只有一个字</span></span><br><span class="line"><span class="keyword">select</span> studentno,studentname</span><br><span class="line"><span class="keyword">from</span> student</span><br><span class="line"><span class="keyword">where</span> studentname <span class="keyword">like</span> <span class="string">'张_'</span></span><br><span class="line"><span class="comment">-- 查询姓张的同学,名字后面只有两个字</span></span><br><span class="line"><span class="keyword">select</span> studentno,studentname</span><br><span class="line"><span class="keyword">from</span> student</span><br><span class="line"><span class="keyword">where</span> studentname <span class="keyword">like</span> <span class="string">'张__'</span></span><br><span class="line"><span class="comment">-- 查询名字中有嘉字的同学</span></span><br><span class="line"><span class="keyword">select</span> studentno,studentname</span><br><span class="line"><span class="keyword">from</span> student</span><br><span class="line"><span class="keyword">where</span> studentname <span class="keyword">like</span> <span class="string">'%嘉%'</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- in(具体的一个或多个值)</span></span><br><span class="line"><span class="comment">-- 查询1001、1002号学员</span></span><br><span class="line"><span class="keyword">select</span> studentno,studentname</span><br><span class="line"><span class="keyword">from</span> student</span><br><span class="line"><span class="keyword">where</span> studentno <span class="keyword">in</span> (<span class="number">1000</span>,<span class="number">1001</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">-- null 和 not null</span></span><br><span class="line"><span class="keyword">select</span> studentno,studentname</span><br><span class="line"><span class="keyword">from</span> student</span><br><span class="line"><span class="keyword">where</span> studentno <span class="keyword">is</span> <span class="literal">null</span> <span class="keyword">or</span> studentno=<span class="string">''</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">select</span> studentno,studentname</span><br><span class="line"><span class="keyword">from</span> student</span><br><span class="line"><span class="keyword">where</span> studentno <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">null</span></span><br></pre></td></tr></table></figure><h2 id="联表查询"><a href="#联表查询" class="headerlink" title="联表查询"></a>联表查询</h2><h3 id="JOIN对比"><a href="#JOIN对比" class="headerlink" title="JOIN对比"></a>JOIN对比</h3><p><img src="/2020/12/29/MySQL/image-20201228134034520.png" alt="image-20201228134034520"></p><p><img src="/2020/12/29/MySQL/image-20201228134325920.png" alt="image-20201228134325920"></p><figure class="highlight sql"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">-- 联表查询join</span></span><br><span class="line"><span class="comment">-- 查询参加了考试的同学(学号、姓名、科目编号、分数)</span></span><br><span class="line"><span class="keyword">SELECT</span> * <span class="keyword">from</span> student</span><br><span class="line"><span class="keyword">SELECT</span> * <span class="keyword">from</span> <span class="keyword">result</span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> 思路</span></span><br><span class="line"><span class="comment"> 1.分析需求,分析查询的字段来自哪些表(连接查询)</span></span><br><span class="line"><span class="comment"> 2.确定使用哪种连接查询--7种</span></span><br><span class="line"><span class="comment"> 确定交叉点(这两个表中哪个数据是相同的)</span></span><br><span class="line"><span class="comment"> 判断的条件:学生表种的studentno=成绩表中的studentno</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="comment">-- inner join</span></span><br><span class="line"><span class="keyword">select</span> s.studentno,studentname,subjectno,studentresult</span><br><span class="line"><span class="keyword">from</span> student <span class="keyword">as</span> s</span><br><span class="line"><span class="keyword">inner</span> <span class="keyword">join</span> <span class="keyword">result</span> <span class="keyword">as</span> r</span><br><span class="line"><span class="keyword">where</span> s.studentno=r.studentno</span><br><span class="line"><span class="comment">-- left join</span></span><br><span class="line"><span class="keyword">select</span> s.studentno,studentname,subjectno,studentresult</span><br><span class="line"><span class="keyword">from</span> student <span class="keyword">as</span> s</span><br><span class="line"><span class="keyword">left</span> <span class="keyword">join</span> <span class="keyword">result</span> <span class="keyword">as</span> r</span><br><span class="line"><span class="keyword">on</span> s.studentno=r.studentno</span><br><span class="line"><span class="comment">-- right join</span></span><br><span class="line"><span class="keyword">select</span> s.studentno,studentname,subjectno,studentresult</span><br><span class="line"><span class="keyword">from</span> student <span class="keyword">as</span> s</span><br><span class="line"><span class="keyword">right</span> <span class="keyword">join</span> <span class="keyword">result</span> <span class="keyword">as</span> r</span><br><span class="line"><span class="keyword">on</span> s.studentno=r.studentno</span><br><span class="line"><span class="comment">-- 查询缺考的同学</span></span><br><span class="line"><span class="keyword">select</span> s.studentno,studentname,subjectno,studentresult</span><br><span class="line"><span class="keyword">from</span> student <span class="keyword">as</span> s</span><br><span class="line"><span class="keyword">left</span> <span class="keyword">join</span> <span class="keyword">result</span> <span class="keyword">as</span> r</span><br><span class="line"><span class="keyword">on</span> s.studentno=r.studentno</span><br><span class="line"><span class="keyword">where</span> studentresult <span class="keyword">is</span> <span class="literal">null</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- 查询参加了考试的同学信息(学号、姓名、科目名、分数)</span></span><br><span class="line"><span class="keyword">select</span> s.studentno,studentname,subjectname,studentresult</span><br><span class="line"><span class="keyword">from</span> student s</span><br><span class="line"><span class="keyword">right</span> <span class="keyword">join</span> <span class="keyword">result</span> r</span><br><span class="line"><span class="keyword">on</span> r.studentno=s.studentno</span><br><span class="line"><span class="keyword">inner</span> <span class="keyword">join</span> subject sub</span><br><span class="line"><span class="keyword">on</span> r.subjectno=sub.subjectno</span><br><span class="line"><span class="comment">-- 我要查询哪些数据</span></span><br><span class="line"><span class="comment">-- 从哪几个表中查 from表 xxx join 连接的表 on 交叉条件</span></span><br></pre></td></tr></table></figure><table><thead><tr><th>操作</th><th>描述</th></tr></thead><tbody><tr><td>inner join</td><td>如果表中至少有一个匹配,就返回行;是并集不是交集,只要有一张表有数据就可以拿到</td></tr><tr><td>left join</td><td>会从左表中返回所有的值,即使右表中没有匹配,</td></tr><tr><td>right join</td><td>会从右表中返回所有的值,即使左表中没有匹配,</td></tr></tbody></table><p>只要有并集就可以合并两张表所有的数据</p><h3 id="on和where"><a href="#on和where" class="headerlink" title="on和where"></a>on和where</h3><p>join on连接查询</p><p>where 等值查询</p><p>on是先筛选后关联,where是先关联后筛选</p><p>on条件是生成临时表时使用的条件,它不管on中的条件是否为真,都会返回左表中的记录</p><p>on确定连接 where确定筛选</p><p>on是建立连接 where是对结果筛选</p><h3 id="自连接"><a href="#自连接" class="headerlink" title="自连接"></a>自连接</h3><p>自己的表和自己的表连接</p><p><strong>核心:一张表拆为两张一样的表即可</strong></p><p>父类</p><table><thead><tr><th>categoryid</th><th>categoryname</th></tr></thead><tbody><tr><td>2</td><td>信息技术</td></tr><tr><td>3</td><td>软件开发</td></tr><tr><td>5</td><td>美术设计</td></tr></tbody></table><p>子类</p><table><thead><tr><th>pid</th><th>categoryid</th><th>categoryname</th></tr></thead><tbody><tr><td>3</td><td>4</td><td>数据库</td></tr><tr><td>2</td><td>8</td><td>办公信息</td></tr><tr><td>3</td><td>6</td><td>web开发</td></tr><tr><td>5</td><td>7</td><td>ps技术</td></tr></tbody></table><p>操作:查询父类对应的子类关系</p><table><thead><tr><th>父类</th><th>子类</th></tr></thead><tbody><tr><td>信息技术</td><td>办公信息</td></tr><tr><td>软件开发</td><td>数据库</td></tr><tr><td>软件开发</td><td>web开发</td></tr><tr><td>美术设计</td><td>ps技术</td></tr></tbody></table><figure class="highlight sql"><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">-- 查询父子信息 把一张表看成两张一模一样表</span></span><br><span class="line"><span class="keyword">select</span> a.categoryname <span class="keyword">as</span> <span class="string">'父'</span> , b.categoryname <span class="keyword">as</span> <span class="string">'子'</span></span><br><span class="line"><span class="keyword">from</span> <span class="keyword">category</span> <span class="keyword">as</span> a,<span class="keyword">category</span> <span class="keyword">as</span> b</span><br><span class="line"><span class="keyword">where</span> a.categoryid = b.pid</span><br></pre></td></tr></table></figure><h2 id="分页和排序"><a href="#分页和排序" class="headerlink" title="分页和排序"></a>分页和排序</h2><p>排序</p><figure class="highlight sql"><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="comment">-- 分页limit和排序order by</span></span><br><span class="line"><span class="comment">-- order by通过哪个字段排序,怎么排</span></span><br><span class="line"><span class="comment">-- 升序asc 降序 desc</span></span><br><span class="line"><span class="keyword">select</span> s.studentno,studentname,subjectname,studentresult</span><br><span class="line"><span class="keyword">from</span> student s</span><br><span class="line"><span class="keyword">inner</span> <span class="keyword">join</span> <span class="keyword">result</span> r</span><br><span class="line"><span class="keyword">on</span> r.studentno=s.studentno</span><br><span class="line"><span class="keyword">inner</span> <span class="keyword">join</span> subject sub</span><br><span class="line"><span class="keyword">on</span> r.subjectno=sub.subjectno</span><br><span class="line"><span class="keyword">order</span> <span class="keyword">by</span> studentresult <span class="keyword">desc</span></span><br></pre></td></tr></table></figure><p>分页</p><figure class="highlight sql"><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"><span class="comment">-- 为什么要分页?</span></span><br><span class="line"><span class="comment">-- 缓解数据库压力 给人的体验更好 一般图片会用瀑布流</span></span><br><span class="line"><span class="comment">-- 分页 每页只显示两条数据</span></span><br><span class="line"><span class="comment">-- 语法 limit 起始值 页面的大小</span></span><br><span class="line"><span class="comment">-- 网页应用:当前,总的页数,页面的大小</span></span><br><span class="line"><span class="comment">-- limit 0,5 1-5 第一页</span></span><br><span class="line"><span class="comment">-- limit 1,5 2-6</span></span><br><span class="line"><span class="comment">-- limit 5,5 第二页</span></span><br><span class="line"><span class="keyword">select</span> s.studentno,studentname,subjectname,studentresult</span><br><span class="line"><span class="keyword">from</span> student s</span><br><span class="line"><span class="keyword">inner</span> <span class="keyword">join</span> <span class="keyword">result</span> r</span><br><span class="line"><span class="keyword">on</span> r.studentno=s.studentno</span><br><span class="line"><span class="keyword">inner</span> <span class="keyword">join</span> subject sub</span><br><span class="line"><span class="keyword">on</span> r.subjectno=sub.subjectno</span><br><span class="line"><span class="keyword">order</span> <span class="keyword">by</span> studentresult <span class="keyword">desc</span></span><br><span class="line"><span class="keyword">LIMIT</span> <span class="number">1</span>,<span class="number">2</span></span><br></pre></td></tr></table></figure><h2 id="子查询"><a href="#子查询" class="headerlink" title="子查询"></a>子查询</h2><p>where(这个值是计算出来的)</p><p>本质:<code>在where语句中嵌套一个子查询语句</code></p><figure class="highlight sql"><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">-- where</span></span><br><span class="line"><span class="comment">-- 查询高等数学-1的所有考试结果</span></span><br><span class="line"><span class="comment">-- 方式一 使用连表查询 降序排列</span></span><br><span class="line"><span class="keyword">select</span> s.subjectno,subjectname,studentresult</span><br><span class="line"><span class="keyword">from</span> subject s</span><br><span class="line"><span class="keyword">inner</span> <span class="keyword">join</span> <span class="keyword">result</span> r</span><br><span class="line"><span class="keyword">on</span> s.subjectno=r.subjectno</span><br><span class="line"><span class="keyword">where</span> subjectname=<span class="string">'高等数学-1'</span></span><br><span class="line"><span class="keyword">order</span> <span class="keyword">by</span> studentresult <span class="keyword">desc</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- 方式二 使用子查询(由里及外)</span></span><br><span class="line"><span class="keyword">select</span> subjectno,studentresult</span><br><span class="line"><span class="keyword">from</span> <span class="keyword">result</span></span><br><span class="line"><span class="keyword">where</span> subjectno=(</span><br><span class="line"><span class="keyword">select</span> subjectno <span class="keyword">from</span> <span class="string">`subject`</span></span><br><span class="line"><span class="keyword">where</span> subjectname=<span class="string">'高等数学-1'</span></span><br><span class="line">)</span><br></pre></td></tr></table></figure><h2 id="分组和过滤(group-by…having)"><a href="#分组和过滤(group-by…having)" class="headerlink" title="分组和过滤(group by…having)"></a>分组和过滤(group by…having)</h2><figure class="highlight sql"><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="comment">-- 查询不同课程的平均分、最高分、最低分、平均分大于80</span></span><br><span class="line"><span class="keyword">select</span> subjectname,<span class="keyword">avg</span>(studentresult) <span class="keyword">as</span><span class="string">'平均分'</span>,<span class="keyword">max</span>(studentresult) <span class="keyword">as</span><span class="string">'最高分'</span>,<span class="keyword">min</span>(studentresult) <span class="keyword">as</span><span class="string">'最低分'</span></span><br><span class="line"><span class="keyword">from</span> <span class="keyword">result</span> r</span><br><span class="line"><span class="keyword">inner</span> <span class="keyword">join</span> <span class="string">`subject`</span> s</span><br><span class="line"><span class="keyword">on</span> r.subjectno=s.subjectno</span><br><span class="line"><span class="keyword">group</span> <span class="keyword">by</span> r.subjectno <span class="comment">-- 通过什么字段来分组</span></span><br><span class="line"><span class="keyword">HAVING</span> 平均分><span class="number">80</span></span><br></pre></td></tr></table></figure><h1 id="MySQL函数"><a href="#MySQL函数" class="headerlink" title="MySQL函数"></a>MySQL函数</h1><h2 id="常用函数"><a href="#常用函数" class="headerlink" title="常用函数"></a>常用函数</h2><figure class="highlight sql"><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">-- 常用函数</span></span><br><span class="line"><span class="comment">-- 数学运算</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">abs</span>(<span class="number">-8</span>) <span class="comment">-- 绝对值</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">CEILING</span>(<span class="number">9.4</span>) <span class="comment">-- 向上取整</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">FLOOR</span>(<span class="number">9.4</span>) <span class="comment">-- 向下取整</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">rand</span>() <span class="comment">-- 返回0-1之间的随机数</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">sign</span>(<span class="number">-10</span>) <span class="comment">-- 判断一个数的符号 负数返回-1 正数返回1</span></span><br><span class="line"><span class="comment">-- 字符串函数</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">char_length</span>(<span class="string">'dasdasdas'</span>) <span class="comment">-- 字符串长度</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">concat</span>(<span class="string">'我'</span>,<span class="string">'艾'</span>) <span class="comment">-- 拼接字符串</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">LOWER</span>(<span class="string">'Jonyon'</span>) <span class="comment">-- 全部转小写</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">UPPER</span>(<span class="string">'Jonyon'</span>) <span class="comment">-- 全部转大写</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">INSTR</span>(<span class="string">'jonyon'</span>,<span class="string">'n'</span>) <span class="comment">-- 返回第一次出现的子串的位置</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">REPLACE</span>(<span class="string">'坚持就是胜利'</span>,<span class="string">'就是'</span>,<span class="string">'也不一定是'</span>) <span class="comment">-- 替换出现的指定字符串</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">SUBSTR</span>(<span class="string">'坚持就是胜利'</span>,<span class="number">5</span>,<span class="number">2</span>) <span class="comment">-- 返回指定字符串(原字符串,截取的位置,截取的长度)</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">REVERSE</span>(<span class="string">'坚持就是胜利'</span>) <span class="comment">-- 反转字符串</span></span><br><span class="line"><span class="comment">-- 时间和日期函数(记住)</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">CURRENT_DATE</span> <span class="comment">-- 获取当前日期</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="keyword">NOW</span>() <span class="comment">-- 获取当前日期</span></span><br><span class="line"><span class="keyword">select</span> <span class="keyword">LOCALTIME</span>() <span class="comment">-- 本地时间</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="keyword">SYSDATE</span>() <span class="comment">-- 系统时间</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="keyword">USER</span>() <span class="comment">-- 系统</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="keyword">VERSION</span>()</span><br></pre></td></tr></table></figure><h2 id="聚合函数"><a href="#聚合函数" class="headerlink" title="聚合函数"></a>聚合函数</h2><table><thead><tr><th>函数名称</th><th>描述</th></tr></thead><tbody><tr><td>count()</td><td>计数</td></tr><tr><td>sum()</td><td>求和</td></tr><tr><td>avg()</td><td>平均值</td></tr><tr><td>max()</td><td>最大值</td></tr><tr><td>min()</td><td>最小值</td></tr><tr><td></td><td></td></tr></tbody></table><figure class="highlight sql"><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="comment">-- 聚合函数</span></span><br><span class="line"><span class="comment">-- 都能够统计表中的数据(想查询一个表中有多少记录)</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="keyword">COUNT</span>(studentname) <span class="keyword">from</span> student <span class="comment">-- count(字段),会忽略所有的null值</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="keyword">COUNT</span>(*) <span class="keyword">from</span> student <span class="comment">-- count(*)不会忽略null值 本质:计算行数</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="keyword">COUNT</span>(<span class="number">1</span>) <span class="keyword">from</span> student <span class="comment">-- count(1)不会忽略null值 本质:计算行数</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> <span class="keyword">sum</span>(studentresult) <span class="keyword">as</span><span class="string">'总分'</span> <span class="keyword">from</span> <span class="keyword">result</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="keyword">avg</span>(studentresult) <span class="keyword">as</span><span class="string">'平均分'</span> <span class="keyword">from</span> <span class="keyword">result</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="keyword">max</span>(studentresult) <span class="keyword">as</span><span class="string">'最高分'</span> <span class="keyword">from</span> <span class="keyword">result</span></span><br><span class="line"><span class="keyword">SELECT</span> <span class="keyword">min</span>(studentresult) <span class="keyword">as</span><span class="string">'最低分'</span> <span class="keyword">from</span> <span class="keyword">result</span></span><br></pre></td></tr></table></figure><h1 id="数据库级别的MD5加密"><a href="#数据库级别的MD5加密" class="headerlink" title="数据库级别的MD5加密"></a>数据库级别的MD5加密</h1><p>什么是MD5?</p><p>MD5不可逆,具体的值的MD5是一样的,比如说123456</p><p>MD5破解网站的原理,背后有一个字典,MD5加密后的值,加密后的值</p><figure class="highlight sql"><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">-- 测试MD5加密</span></span><br><span class="line"><span class="keyword">create</span> <span class="keyword">table</span> testmd5(</span><br><span class="line"><span class="keyword">id</span> <span class="built_in">int</span>(<span class="number">4</span>) <span class="keyword">not</span> <span class="literal">null</span>,</span><br><span class="line"><span class="keyword">name</span> <span class="built_in">varchar</span>(<span class="number">20</span>) <span class="keyword">not</span> <span class="literal">null</span>,</span><br><span class="line">pwd <span class="built_in">varchar</span>(<span class="number">50</span>) <span class="keyword">not</span> <span class="literal">null</span>,</span><br><span class="line">PRIMARY <span class="keyword">KEY</span>(<span class="keyword">id</span>)</span><br><span class="line"></span><br><span class="line">)<span class="keyword">ENGINE</span>=<span class="keyword">innodb</span> <span class="keyword">DEFAULT</span> <span class="keyword">CHARSET</span>=utf8</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 明文密码</span></span><br><span class="line"><span class="keyword">insert</span> <span class="keyword">into</span> testmd5 <span class="keyword">values</span>(<span class="string">'1'</span>,<span class="string">'zhangsan'</span>,<span class="string">'123456'</span>),</span><br><span class="line">(<span class="string">'2'</span>,<span class="string">'lisi'</span>,<span class="string">'123456'</span>),</span><br><span class="line">(<span class="string">'3'</span>,<span class="string">'wangwu'</span>,<span class="string">'123456'</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 加密</span></span><br><span class="line"><span class="keyword">update</span> testmd5 <span class="keyword">set</span> pwd=<span class="keyword">MD5</span>(pwd) <span class="keyword">where</span> <span class="keyword">id</span>=<span class="number">2</span> <span class="comment">-- 加密了</span></span><br><span class="line"><span class="keyword">update</span> testmd5 <span class="keyword">set</span> pwd=<span class="keyword">MD5</span>(pwd) <span class="comment">-- 加密了全部的密码</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- 插入的时候加密</span></span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">into</span> testmd5 <span class="keyword">values</span>(<span class="string">'4'</span>,<span class="string">'xiaohong'</span>,<span class="keyword">MD5</span>(<span class="string">'123456'</span>))</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 如何校验,将用户传递进来的代码,进行MD5加密,然后比对加密后的值</span></span><br><span class="line"><span class="keyword">SELECT</span> * <span class="keyword">from</span> testmd5 <span class="keyword">where</span> <span class="keyword">name</span>=<span class="string">'wangwu'</span> <span class="keyword">and</span> pwd=<span class="keyword">MD5</span>(<span class="string">'123456'</span>)</span><br></pre></td></tr></table></figure><h1 id="事务"><a href="#事务" class="headerlink" title="事务"></a>事务</h1><h2 id="什么是事务"><a href="#什么是事务" class="headerlink" title="什么是事务"></a>什么是事务</h2><p><code>要么都成功、要么都失败</code></p><p>将一组SQL放在一个批次中执行</p><h2 id="事务原则-ACID原则"><a href="#事务原则-ACID原则" class="headerlink" title="事务原则:ACID原则"></a>事务原则:ACID原则</h2><p><strong>原子性(Atomicity)</strong><br>原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。</p><p>针对同一个事务</p><p><img src="/2020/12/29/MySQL/image-20201229115051120.png" alt="image-20201229115051120"></p><p>这个过程包含两个步骤</p><p>A: 800 - 200 = 600<br>B: 200 + 200 = 400</p><p>原子性表示,这两个步骤一起成功,或者一起失败,不能只发生其中一个动作</p><p><strong>一致性(Consistency)</strong><br>事务前后数据的完整性必须保持一致。</p><p>针对一个事务操作前与操作后操作一致</p><p><img src="/2020/12/29/MySQL/image-20201229115228329.png" alt="image-20201229115228329"></p><p>操作前A:800,B:200<br>操作后A:600,B:400</p><p>一致性表示事务完成后,符合逻辑运算</p><p><strong>隔离性(Isolation)</strong><br>事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。</p><p>表示事务结束后的数据不随外界原因导致数据丢失</p><p>操作前A:800,B:200<br>操作后A:600,B:400<br>如果在操作前(事务还没有提交)服务器宕机或者断电,那么重启数据库以后,数据状态应该为<br>A:800,B:200<br>如果在操作后(事务已经提交)服务器宕机或者断电,那么重启数据库以后,数据状态应该为<br>A:600,B:400</p><p><strong>持久性(Durability)</strong><br>持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响</p><p>针对多个用户同时操作,主要是排除其他事务对本次事务的影响</p><p><img src="/2020/12/29/MySQL/image-20201229115452418.png" alt="image-20201229115452418"></p><h2 id="隔离性(Isolation)所导致的一些问题"><a href="#隔离性(Isolation)所导致的一些问题" class="headerlink" title="隔离性(Isolation)所导致的一些问题"></a><strong>隔离性(Isolation)</strong>所导致的一些问题</h2><p><strong>脏读:</strong></p><p>指一个事务读取了另一个事务未提交的数据</p><p><img src="/2020/12/29/MySQL/image-20201229115943793.png" alt="image-20201229115943793"></p><p><strong>不可重复读</strong></p><p>在一个事务内读取表中的某一行数据,多次读取结果不同(这个不一定是错误,只是某些场合不对)</p><p><img src="/2020/12/29/MySQL/image-20201229120104184.png" alt="image-20201229120104184"></p><p><strong>虚读(幻读)</strong></p><p>是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。(一般是行影响,多了一行)</p><p><img src="/2020/12/29/MySQL/image-20201229120155673.png" alt="image-20201229120155673"></p><figure class="highlight sql"><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"><span class="comment">-- mysql自动开启事务自动提交</span></span><br><span class="line"><span class="keyword">set</span> autocommit=<span class="number">0</span> <span class="comment">-- 关闭事务</span></span><br><span class="line"><span class="keyword">set</span> autocommit=<span class="number">1</span> <span class="comment">-- 开启事务(默认)</span></span><br><span class="line"><span class="comment">-- 手动处理事务</span></span><br><span class="line"><span class="comment">-- 事务开启 </span></span><br><span class="line"><span class="keyword">start</span> <span class="keyword">TRANSACTION</span> <span class="comment">-- 标记一个事务的开始,从这个之后的sql都在同一个事务内</span></span><br><span class="line"><span class="comment">-- 提交 持久化 commit</span></span><br><span class="line"><span class="keyword">commit</span></span><br><span class="line"><span class="comment">-- 回滚 回到原来的样子 rollback</span></span><br><span class="line"><span class="keyword">rollback</span></span><br><span class="line"><span class="comment">-- 事务结束</span></span><br><span class="line"><span class="keyword">savepoint</span> 保存点名 <span class="comment">-- 设置一个事务的保存点</span></span><br><span class="line"><span class="keyword">rollback</span> <span class="keyword">to</span> <span class="keyword">savepoint</span> 保存点名 <span class="comment">-- 回滚到保存点</span></span><br><span class="line"><span class="keyword">RELEASE</span> <span class="keyword">savepoint</span> 保存点名<span class="comment">-- 撤销保存点</span></span><br></pre></td></tr></table></figure><h1 id="索引"><a href="#索引" class="headerlink" title="索引"></a>索引</h1><blockquote><p>MySQL官方对索引的定义为:<strong>索引(Index)是帮助MySQL高效获取数据的数据结构。</strong></p><p>提取句子主干,就可以得到索引的本质:索引是数据结构。</p><p>索引在小数据量的时候用处不大,但在大数据量的时候区别十分明显</p></blockquote><h2 id="索引的分类"><a href="#索引的分类" class="headerlink" title="索引的分类"></a>索引的分类</h2><blockquote><p>在一个表中,主键索引只能有一个,唯一索引可以有多个</p></blockquote><ul><li>主键索引(primary key)<ul><li>唯一标识,主键不可重复,只能有一个列作为主键</li></ul></li><li>唯一索引(unique key)<ul><li>避免重复的列出现,唯一索引可以重复,多个列都可以标识为索引</li></ul></li><li>常规索引(key/index)<ul><li>默认的,index,key关键字来设置</li></ul></li><li>全文索引(fulltext)<ul><li>快速定位数据</li></ul></li></ul><figure class="highlight sql"><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="comment">-- 索引的使用</span></span><br><span class="line"><span class="comment">-- 1.在创建表的时候给字段增加索引</span></span><br><span class="line"><span class="comment">-- 2.创建完毕后,增加索引</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- 显示所有的索引信息</span></span><br><span class="line"><span class="keyword">show</span> <span class="keyword">index</span> <span class="keyword">from</span> student</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 增加全文索引</span></span><br><span class="line"><span class="keyword">alter</span> <span class="keyword">table</span> school.student <span class="keyword">add</span> FULLTEXT <span class="keyword">INDEX</span> studentname(studentname)</span><br><span class="line"></span><br><span class="line"><span class="comment">-- EXPLAIN 分析sql执行的状况</span></span><br><span class="line"><span class="keyword">explain</span> <span class="keyword">select</span> * <span class="keyword">from</span> student; <span class="comment">-- 非全文索引</span></span><br></pre></td></tr></table></figure><h2 id="测试索引"><a href="#测试索引" class="headerlink" title="测试索引"></a>测试索引</h2><figure class="highlight sql"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> <span class="string">`app_user`</span> (</span><br><span class="line"><span class="string">`id`</span> <span class="built_in">BIGINT</span>(<span class="number">20</span>) <span class="keyword">UNSIGNED</span> <span class="keyword">NOT</span> <span class="literal">NULL</span> AUTO_INCREMENT,</span><br><span class="line"><span class="string">`name`</span> <span class="built_in">VARCHAR</span>(<span class="number">50</span>) <span class="keyword">DEFAULT</span><span class="string">''</span> <span class="keyword">COMMENT</span><span class="string">'用户昵称'</span>,</span><br><span class="line"><span class="string">`email`</span> <span class="built_in">VARCHAR</span>(<span class="number">50</span>) <span class="keyword">NOT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span><span class="string">'用户邮箱'</span>,</span><br><span class="line"><span class="string">`phone`</span> <span class="built_in">VARCHAR</span>(<span class="number">20</span>) <span class="keyword">DEFAULT</span><span class="string">''</span> <span class="keyword">COMMENT</span><span class="string">'手机号'</span>,</span><br><span class="line"><span class="string">`gender`</span> <span class="built_in">TINYINT</span>(<span class="number">4</span>) <span class="keyword">UNSIGNED</span> <span class="keyword">DEFAULT</span> <span class="string">'0'</span><span class="keyword">COMMENT</span> <span class="string">'性别(0:男;1:女)'</span>,</span><br><span class="line"><span class="string">`password`</span> <span class="built_in">VARCHAR</span>(<span class="number">100</span>) <span class="keyword">NOT</span> <span class="literal">NULL</span> <span class="keyword">COMMENT</span> <span class="string">'密码'</span>,</span><br><span class="line"><span class="string">`age`</span> <span class="built_in">TINYINT</span>(<span class="number">4</span>) <span class="keyword">DEFAULT</span><span class="string">'0'</span> <span class="keyword">COMMENT</span> <span class="string">'年龄'</span>,</span><br><span class="line"><span class="string">`create_time`</span> datetime <span class="keyword">DEFAULT</span> <span class="keyword">CURRENT_TIMESTAMP</span>,</span><br><span class="line"><span class="string">`update_time`</span> <span class="built_in">TIMESTAMP</span> <span class="keyword">NOT</span> <span class="literal">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">CURRENT_TIMESTAMP</span> <span class="keyword">ON</span> <span class="keyword">UPDATE</span> <span class="keyword">CURRENT_TIMESTAMP</span>,</span><br><span class="line">PRIMARY <span class="keyword">KEY</span> (<span class="string">`id`</span>)</span><br><span class="line">) <span class="keyword">ENGINE</span>=<span class="keyword">INNODB</span> <span class="keyword">DEFAULT</span> <span class="keyword">CHARSET</span>=utf8 <span class="keyword">COMMENT</span> = <span class="string">'app用户表'</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- 插入100万数据.</span></span><br><span class="line">DELIMITER $$</span><br><span class="line"><span class="comment">-- 写函数之前必须要写,标志</span></span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">FUNCTION</span> mock_data ()</span><br><span class="line"><span class="keyword">RETURNS</span> <span class="built_in">INT</span></span><br><span class="line"><span class="keyword">BEGIN</span></span><br><span class="line"><span class="keyword">DECLARE</span> <span class="keyword">num</span> <span class="built_in">INT</span> <span class="keyword">DEFAULT</span> <span class="number">1000000</span>;</span><br><span class="line"><span class="keyword">DECLARE</span> i <span class="built_in">INT</span> <span class="keyword">DEFAULT</span> <span class="number">0</span>;</span><br><span class="line">WHILE i<num DO</span><br><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> <span class="string">`app_user`</span>(<span class="string">`name`</span>,<span class="string">`email`</span>,<span class="string">`phone`</span>,<span class="string">`gender`</span>)<span class="keyword">VALUES</span>(<span class="keyword">CONCAT</span>(<span class="string">'用户'</span>,i),<span class="string">'19224305@qq.com'</span>,<span class="string">'123456789'</span>,<span class="keyword">FLOOR</span>(<span class="keyword">RAND</span>()*<span class="number">2</span>));</span><br><span class="line"><span class="keyword">SET</span> i=i+<span class="number">1</span>;</span><br><span class="line"><span class="keyword">END</span> <span class="keyword">WHILE</span>;</span><br><span class="line">RETURN i;</span><br><span class="line"><span class="keyword">END</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> mock_data() <span class="comment">-- 执行此函数 生成一百万条数据</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> * <span class="keyword">from</span> app_user <span class="keyword">where</span> <span class="keyword">name</span> =<span class="string">'用户1000'</span></span><br><span class="line"><span class="comment">-- 创建索引之前> 时间: 0.525s</span></span><br><span class="line"><span class="keyword">EXPLAIN</span> <span class="keyword">SELECT</span> * <span class="keyword">from</span> app_user <span class="keyword">where</span> <span class="keyword">name</span> =<span class="string">'用户1000'</span></span><br><span class="line"><span class="comment">-- rows=994560 查了994560条数据</span></span><br><span class="line"><span class="comment">-- id _ 表名 _ 字段名</span></span><br><span class="line"><span class="comment">-- create index 索引名 on 表 (字段)</span></span><br><span class="line"><span class="keyword">create</span> <span class="keyword">index</span> id_app_user_name <span class="keyword">on</span> app_user(<span class="keyword">name</span>);</span><br><span class="line"><span class="keyword">SELECT</span> * <span class="keyword">from</span> app_user <span class="keyword">where</span> <span class="keyword">name</span> =<span class="string">'用户1000'</span></span><br><span class="line"><span class="comment">-- 创建索引之后> 时间: 0.045s</span></span><br><span class="line"><span class="keyword">EXPLAIN</span> <span class="keyword">SELECT</span> * <span class="keyword">from</span> app_user <span class="keyword">where</span> <span class="keyword">name</span> =<span class="string">'用户1000'</span></span><br><span class="line"><span class="comment">-- rows=1 查了1条数据</span></span><br></pre></td></tr></table></figure><h2 id="索引原则"><a href="#索引原则" class="headerlink" title="索引原则"></a>索引原则</h2><ul><li>索引不是越多越好</li><li>不要对经常变动的数据加索引</li><li>小数据量的表不需要加索引</li><li>索引一般加在常用来查询的字段上</li></ul><p>索引的数据结构</p><p>Btree:innodb默认的数据结构</p><h1 id="权限管理和备份"><a href="#权限管理和备份" class="headerlink" title="权限管理和备份"></a>权限管理和备份</h1><h2 id="用户管理"><a href="#用户管理" class="headerlink" title="用户管理"></a>用户管理</h2><p><strong>sql命令</strong></p><p>用户表:mysql.user</p><figure class="highlight sql"><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="comment">-- 创建用户 create user 用户名 IDENTIFIED by '密码'</span></span><br><span class="line"><span class="keyword">create</span> <span class="keyword">user</span> jonyon <span class="keyword">IDENTIFIED</span> <span class="keyword">by</span> <span class="string">'123456'</span></span><br><span class="line"><span class="comment">-- 修改密码(修改当前用户密码)</span></span><br><span class="line"><span class="keyword">set</span> <span class="keyword">password</span>=<span class="keyword">password</span>(<span class="string">'123456'</span>)</span><br><span class="line"><span class="comment">-- 修改密码(修改指定用户密码)</span></span><br><span class="line"><span class="keyword">set</span> <span class="keyword">password</span> <span class="keyword">for</span> jonyon=<span class="keyword">password</span>(<span class="string">'123456'</span>)</span><br><span class="line"><span class="comment">-- 重命名</span></span><br><span class="line"><span class="keyword">RENAME</span> <span class="keyword">user</span> jonyon <span class="keyword">to</span> wzj</span><br><span class="line"><span class="comment">-- 用户授权all PRIVILEGES 全部的权限 除了给别人授权,别的都能干</span></span><br><span class="line"><span class="keyword">GRANT</span> <span class="keyword">all</span> <span class="keyword">PRIVILEGES</span> <span class="keyword">on</span> *.* <span class="keyword">to</span> wzj </span><br><span class="line"><span class="comment">-- 查询权限</span></span><br><span class="line"><span class="keyword">show</span> <span class="keyword">GRANT</span> <span class="keyword">for</span> wzj <span class="comment">-- 查看指定用户的权限</span></span><br></pre></td></tr></table></figure><h1 id="MySQL数据库备份"><a href="#MySQL数据库备份" class="headerlink" title="MySQL数据库备份"></a>MySQL数据库备份</h1><ul><li>保证重要的数据不丢失</li><li>数据转移 A—>B</li></ul><p>MySQL数据库备份的方式</p><ul><li>直接拷贝物理文件</li><li>在可视化工具中手动导出</li><li>使用命令行导出 mysqkdump 命令行使用</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></pre></td><td class="code"><pre><span class="line"><span class="comment">#mysqldump -h 主机 -u 用户名 -p 密码 数据库 表名 > 物理磁盘位置/文件名</span></span><br><span class="line">mysqldump -hlocalhost -uroot -p123456 school student >D:/a.sql</span><br><span class="line"><span class="comment">#mysqldump -h 主机 -u 用户名 -p 密码 数据库 表名1 表名2 表名3 > 物理磁盘位置/文件名</span></span><br><span class="line"><span class="comment">#mysqldump -h 主机 -u 用户名 -p 密码 数据库> 物理磁盘位置/文件名</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#导入</span></span><br><span class="line"><span class="comment">#登录的情况下,切换到指定数据库</span></span><br><span class="line"><span class="comment">#source 备份文件</span></span><br><span class="line"><span class="built_in">source</span> D:/a.sql</span><br><span class="line">mysql -u用户名 -p密码 库名<备份文件</span><br></pre></td></tr></table></figure><h1 id="规范数据库设计"><a href="#规范数据库设计" class="headerlink" title="规范数据库设计"></a>规范数据库设计</h1><h2 id="为什么需要设计"><a href="#为什么需要设计" class="headerlink" title="为什么需要设计"></a>为什么需要设计</h2><p>当数据库比较复杂的时候就需要设计了</p><p><strong>糟糕的数据库设计</strong></p><ul><li>数据冗余,浪费空间</li><li>数据库插入和删除都会很麻烦、异常【屏蔽使用物理外键】</li><li>程序性能差</li></ul><p><strong>良好的数据库设计</strong></p><ul><li>节省内存空间</li><li>保证数据库的完整性</li><li>方便我们开发系统</li></ul><p><strong>软件开发中,关于数据库的设计</strong></p><ul><li>需求分析:分析业务和需要处理的数据库的需求</li><li>概念设计:设计关系图E-R图</li></ul><h2 id="三大范式"><a href="#三大范式" class="headerlink" title="三大范式"></a>三大范式</h2><p>为什么需要数据规范化</p><ul><li>信息重复</li><li>更新异常</li><li>插入异常<ul><li>无法正常显示信息</li></ul></li><li>删除异常<ul><li>丢失有效信息</li></ul></li></ul><p><strong>第一范式(1NF)</strong></p><p>原子性:保证每一列不可再分</p><p><img src="/2020/12/29/MySQL/image-20201229153000652.png" alt="image-20201229153000652"></p><p><strong>第二范式(2NF)</strong></p><p>前提:满足第一范式</p><p>每张表只描述一件事情</p><p><img src="/2020/12/29/MySQL/image-20201229153025902.png" alt="image-20201229153025902"></p><p><strong>第三范式(3NF)</strong></p><p>前提:满足第一二范式</p><p><strong>第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。</strong></p><p><img src="/2020/12/29/MySQL/image-20201229153051165.png" alt="image-20201229153051165"></p><p>(规范数据库设计)</p><p><strong>规范性和性能的问题</strong></p><p>阿里规定关联查询的表不得超过三张表</p><ul><li>考虑商业化的需求和目标,数据库的性能更重要</li><li>在规范性能的问题的时候,需要适当考虑 规范性</li><li>故意给某些表增加一些冗余字段(从多表查询变为单表查询)</li><li>故意增加一些计算列(从大数据量降低为小数据量的查询:索引)</li></ul><h1 id="JDBC"><a href="#JDBC" class="headerlink" title="JDBC"></a>JDBC</h1><h2 id="数据库驱动"><a href="#数据库驱动" class="headerlink" title="数据库驱动"></a>数据库驱动</h2><p>驱动:声卡、显卡、数据库</p><p><img src="/2020/12/29/MySQL/image-20201229153410785.png" alt="image-20201229153410785"></p><p>我们的程序会通过数据库驱动和数据库打交道</p><h2 id="JDBC-1"><a href="#JDBC-1" class="headerlink" title="JDBC"></a>JDBC</h2><p>SUN公司为了简化开发人员对数据库的统一操作,提供了一个规范(java操作数据库的)JDBC</p><p>这些规范的实现由具体的厂商去做</p><p>对于开发人员来说,只需要掌握JDBC接口的操作即可</p><p><img src="/2020/12/29/MySQL/image-20201229153751973.png" alt="image-20201229153751973"></p><p><strong>在架构中,没有什么是加一层解决不了的</strong></p><p>java.sql</p><p>javax.sql</p><p>数据库驱动:mysql-connector-java-5.1.47</p>]]></content>
<summary type="html"><h1 id="MySQL"><a href="#MySQL" class="headerlink" title="MySQL"></a>MySQL</h1><p>javaEE 企业级开发 Web</p>
<p>前端:页面渲染,展示数据</p>
<p>后台:连接点</p>
<ul>
<li>连接数据库JDBC</li>
<li>连接前端(控制,控制视图跳转,给前端传数据)</li>
</ul>
<p>数据库:存储数据(TXT,Excel,Word)</p></summary>
<category term="数据库" scheme="http://www.jonyonwzj.top/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
<category term="SQL" scheme="http://www.jonyonwzj.top/tags/SQL/"/>
</entry>
<entry>
<title>容器数据卷</title>
<link href="http://www.jonyonwzj.top/2020/12/12/%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%8D%B7/"/>
<id>http://www.jonyonwzj.top/2020/12/12/%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%8D%B7/</id>
<published>2020-12-12T09:16:44.000Z</published>
<updated>2020-12-12T09:22:34.932Z</updated>
<content type="html"><![CDATA[<h1 id="容器数据卷"><a href="#容器数据卷" class="headerlink" title="容器数据卷"></a>容器数据卷</h1><h2 id="什么是容器数据卷"><a href="#什么是容器数据卷" class="headerlink" title="什么是容器数据卷"></a>什么是容器数据卷</h2><p><strong>docker理念</strong>:将应用和环境打包成一个镜像</p><p>但是如果数据都在容器中,那么容器一删除,数据就会丢失。于是提出了新的需求:<strong>数据持久化</strong></p><a id="more"></a><p><strong>卷技术</strong>:容器之间可以有一个数据共享的技术,docker中产生的数据,同步到本地。也可说是目录的挂载,将容器内的目录,挂载到linux上</p><p><img src="/2020/12/12/%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%8D%B7/1-1.png" alt="image-20201212130911804"></p><p><strong>实现了容器的持久化和同步操作,容器间也是可以数据共享的</strong></p><h2 id="使用数据卷"><a href="#使用数据卷" class="headerlink" title="使用数据卷"></a>使用数据卷</h2><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><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">docker run -it -v 主机目录:容器内目录</span><br><span class="line"></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker run -it -v /home/ceshi:/home centos /bin/bash</span><br><span class="line">[root@cb221f836c64 /]# ls</span><br><span class="line">bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var</span><br><span class="line">[root@cb221f836c64 /]# exit</span><br><span class="line">exit</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# cd /home</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz home]# ls</span><br><span class="line">admin ceshi redis test.java www wzj.java</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz home]# docker inspect cb221f836c64</span><br><span class="line">[</span><br><span class="line"> {</span><br><span class="line"> "Id": "cb221f836c6464ef069bcb1edbca50dc78da0f48431ba588a371653c69d7b643",</span><br><span class="line"> "Created": "2020-12-12T05:22:33.030247139Z",</span><br><span class="line"> "Path": "/bin/bash",</span><br><span class="line"> "Args": [],</span><br><span class="line">................</span><br><span class="line">"Mounts": [</span><br><span class="line"> {</span><br><span class="line"> "Type": "bind",</span><br><span class="line"> "Source": "/home/ceshi",</span><br><span class="line"> "Destination": "/home",</span><br><span class="line"> "Mode": "",</span><br><span class="line"> "RW": true,</span><br><span class="line"> "Propagation": "rprivate"</span><br><span class="line"> }</span><br><span class="line"> ],</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="/2020/12/12/%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%8D%B7/1-2.png" alt="image-20201212132831017"></p><p>测试文件的同步(双向过程):</p><p><img src="/2020/12/12/%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%8D%B7/1-3.png" alt="image-20201212134119025"></p><p>好处:以后修改只需要在本地修改即可,容器内会自动同步。</p><h3 id="MySql数据持久化问题"><a href="#MySql数据持久化问题" class="headerlink" title="MySql数据持久化问题"></a>MySql数据持久化问题</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></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">安装启动mysqlMySql需要密码,到dockerhub官方文档上可以找到</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag</span></span><br><span class="line"></span><br><span class="line">docker run -d -p 3344:3306 -v /home/mysql/conf:/etc/mysql/conf -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7</span><br><span class="line"><span class="meta">#</span><span class="bash">-d 后台运行</span></span><br><span class="line"><span class="meta">#</span><span class="bash">-p 端口映射</span></span><br><span class="line"><span class="meta">#</span><span class="bash">-v 卷挂载(如需要挂载多个可用多个-v)</span></span><br><span class="line"><span class="meta">#</span><span class="bash">-e 环境配置(此处配置mysql密码)</span></span><br><span class="line"><span class="meta">#</span><span class="bash">--name 容器名字</span></span><br></pre></td></tr></table></figure><h3 id="具名和匿名挂载"><a href="#具名和匿名挂载" class="headerlink" title="具名和匿名挂载"></a>具名和匿名挂载</h3><h4 id="匿名挂载"><a href="#匿名挂载" class="headerlink" title="匿名挂载"></a>匿名挂载</h4><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">-v 容器内路径</span></span><br><span class="line">docker run -d -P --name nginx01 -v /etc/nginx nginx</span><br><span class="line"><span class="meta">#</span><span class="bash">-P 随机指定端口</span></span><br><span class="line"><span class="meta">#</span><span class="bash">查看所有volume的情况</span></span><br><span class="line">docker volume ls</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker volume ls</span><br><span class="line">DRIVER VOLUME NAME</span><br><span class="line">local 216b7f301cc54025c33f83773027ff48001e02c59061e7c598ea9ffc74445b59</span><br><span class="line"><span class="meta">#</span><span class="bash">这就是匿名挂载,在-v只写了容器内部的路径,没有写容器外部的路径</span></span><br></pre></td></tr></table></figure><h4 id="具名挂载"><a href="#具名挂载" class="headerlink" title="具名挂载"></a>具名挂载</h4><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">-v 卷名:容器内路径</span></span><br><span class="line">docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx</span><br><span class="line"><span class="meta">#</span><span class="bash">查看所有volume的情况</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker volume ls</span><br><span class="line">DRIVER VOLUME NAME</span><br><span class="line">local 216b7f301cc54025c33f83773027ff48001e02c59061e7c598ea9ffc74445b59</span><br><span class="line">local juming-nginx</span><br><span class="line"><span class="meta">#</span><span class="bash">查看一下这个卷在哪里</span></span><br><span class="line">docker volume inspect juming-nginx</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker volume inspect juming-nginx</span><br><span class="line">[</span><br><span class="line"> {</span><br><span class="line"> "CreatedAt": "2020-12-12T14:37:27+08:00",</span><br><span class="line"> "Driver": "local",</span><br><span class="line"> "Labels": null,</span><br><span class="line"> "Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data",</span><br><span class="line"> "Name": "juming-nginx",</span><br><span class="line"> "Options": null,</span><br><span class="line"> "Scope": "local"</span><br><span class="line"> }</span><br><span class="line">]</span><br></pre></td></tr></table></figure><p>所有的docker容器内部的卷,没有指定目录的情况下都是在<code>/var/lib/docker/volumes/xxxx/_data</code></p><p>通过具名挂载可以方便的找到我们的一个卷,大多数情况使用<code>具名挂载</code></p><h4 id="如何确定是指定路径挂载、匿名挂载、具名挂载"><a href="#如何确定是指定路径挂载、匿名挂载、具名挂载" class="headerlink" title="如何确定是指定路径挂载、匿名挂载、具名挂载"></a>如何确定是指定路径挂载、匿名挂载、具名挂载</h4><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">-v /宿主机路径:容器内路径 #指定路径挂载</span><br><span class="line">-v 容器内路径 #匿名挂载</span><br><span class="line">-v 卷名:容器内路径 #具名挂载</span><br></pre></td></tr></table></figure><h4 id="ro和rw"><a href="#ro和rw" class="headerlink" title="ro和rw"></a>ro和rw</h4><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></pre></td><td class="code"><pre><span class="line">ro readonly #只读</span><br><span class="line">rw readwirte #可读可写</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">通过-v 容器内路径:ro/rw 改变读写权限,设置后容器就会对挂载出来的内容有限定</span></span><br><span class="line">docker run -d -P --name nginx -v juming-nginx:/etc/nginx:ro nginx </span><br><span class="line">docker run -d -P --name nginx -v juming-nginx:/etc/nginx:rw nginx </span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">ro 这个路径只能通过宿主机来操作,容器内部无法操作</span></span><br><span class="line"><span class="meta">#</span><span class="bash">rw 默认为rw,宿主机和容器都可进行操作</span></span><br></pre></td></tr></table></figure><h2 id="使用DockerFile"><a href="#使用DockerFile" class="headerlink" title="使用DockerFile"></a>使用DockerFile</h2><blockquote><p>方式二:构建镜像文件的时候直接进行挂载</p></blockquote><p>Dockerfile就是用来构建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></pre></td><td class="code"><pre><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz home]# mkdir docker-test-volume</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz home]# ls</span><br><span class="line">admin ceshi docker-test-volume mysql redis test.java www wzj.java</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz home]# cd docker-test-volume</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz docker-test-volume]# vim dockerfile1</span><br></pre></td></tr></table></figure><p><code>dockerfile1</code>:通过这个脚本可以生成镜像,镜像是一层一层的,而脚本是一个个的命令,每个命令都是一层</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></pre></td><td class="code"><pre><span class="line">FROM centos</span><br><span class="line">VOLUME["volume01","volume02"]</span><br><span class="line"></span><br><span class="line">CMD echo ".....end....."</span><br><span class="line">CMD /bin/bash</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">这里的每个命令,就是镜像的一层</span></span><br><span class="line"></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz docker-test-volume]# cat dockerfile1</span><br><span class="line">FROM centos #镜像</span><br><span class="line">VOLUME["volume01","volume02"] #挂载(匿名挂载)</span><br><span class="line"></span><br><span class="line">CMD echo ".....end....." #构建镜像成功打印 ".....end....." </span><br><span class="line">CMD /bin/bash #默认进入/bin/bash </span><br></pre></td></tr></table></figure><p><code>构建docker镜像</code></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></pre></td><td class="code"><pre><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz docker-test-volume]# docker build -f dockerfile1 -t jonyon/centos:1.0 .</span><br><span class="line">Sending build context to Docker daemon 2.048kB</span><br><span class="line">Step 1/4 : FROM centos #镜像</span><br><span class="line"><span class="meta"> ---></span><span class="bash"> 300e315adb2f</span></span><br><span class="line">Step 2/4 : VOLUME ["volume01","volume02"] #挂载(匿名挂载)</span><br><span class="line"><span class="meta"> ---></span><span class="bash"> Running <span class="keyword">in</span> c9e28ce4daf5</span></span><br><span class="line">Removing intermediate container c9e28ce4daf5</span><br><span class="line"><span class="meta"> ---></span><span class="bash"> 8deb5deffaf3</span></span><br><span class="line">Step 3/4 : CMD echo ".....end....." #输出文件内部命令</span><br><span class="line"><span class="meta"> ---></span><span class="bash"> Running <span class="keyword">in</span> 8f6a0781f409</span></span><br><span class="line">Removing intermediate container 8f6a0781f409</span><br><span class="line"><span class="meta"> ---></span><span class="bash"> 4f0e5be4d8fd</span></span><br><span class="line">Step 4/4 : CMD /bin/bash #进入/bin/bash </span><br><span class="line"><span class="meta"> ---></span><span class="bash"> Running <span class="keyword">in</span> fc4657cbab76</span></span><br><span class="line">Removing intermediate container fc4657cbab76</span><br><span class="line"><span class="meta"> ---></span><span class="bash"> c9531b9b79fd</span></span><br><span class="line">Successfully built c9531b9b79fd</span><br><span class="line">Successfully tagged jonyon/centos:1.0</span><br><span class="line"></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz docker-test-volume]# docker images</span><br><span class="line">REPOSITORY TAG IMAGE ID CREATED SIZE</span><br><span class="line">jonyon/centos 1.0 c9531b9b79fd 2 minutes ago 209MB</span><br></pre></td></tr></table></figure><p><code>启动自己的容器</code></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></pre></td><td class="code"><pre><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz docker-test-volume]# docker run -it c9531b9b79fd /bin/bash</span><br><span class="line">[root@a01086118f02 /]# ls -l</span><br><span class="line">total 56</span><br><span class="line">lrwxrwxrwx 1 root root 7 Nov 3 15:22 bin -> usr/bin</span><br><span class="line">drwxr-xr-x 5 root root 360 Dec 12 07:41 dev</span><br><span class="line">drwxr-xr-x 1 root root 4096 Dec 12 07:41 etc</span><br><span class="line">drwxr-xr-x 2 root root 4096 Nov 3 15:22 home</span><br><span class="line">lrwxrwxrwx 1 root root 7 Nov 3 15:22 lib -> usr/lib</span><br><span class="line">lrwxrwxrwx 1 root root 9 Nov 3 15:22 lib64 -> usr/lib64</span><br><span class="line">drwx------ 2 root root 4096 Dec 4 17:37 lost+found</span><br><span class="line">drwxr-xr-x 2 root root 4096 Nov 3 15:22 media</span><br><span class="line">drwxr-xr-x 2 root root 4096 Nov 3 15:22 mnt</span><br><span class="line">drwxr-xr-x 2 root root 4096 Nov 3 15:22 opt</span><br><span class="line">dr-xr-xr-x 107 root root 0 Dec 12 07:41 proc</span><br><span class="line">dr-xr-x--- 2 root root 4096 Dec 4 17:37 root</span><br><span class="line">drwxr-xr-x 11 root root 4096 Dec 4 17:37 run</span><br><span class="line">lrwxrwxrwx 1 root root 8 Nov 3 15:22 sbin -> usr/sbin</span><br><span class="line">drwxr-xr-x 2 root root 4096 Nov 3 15:22 srv</span><br><span class="line">dr-xr-xr-x 13 root root 0 Dec 12 07:41 sys</span><br><span class="line">drwxrwxrwt 7 root root 4096 Dec 4 17:37 tmp</span><br><span class="line">drwxr-xr-x 12 root root 4096 Dec 4 17:37 usr</span><br><span class="line">drwxr-xr-x 20 root root 4096 Dec 4 17:37 var</span><br><span class="line"><span class="meta">#</span><span class="bash">这两个目录就是生成镜像的时候自动挂载的数据卷目录</span></span><br><span class="line">drwxr-xr-x 2 root root 4096 Dec 12 07:41 volume01 </span><br><span class="line">drwxr-xr-x 2 root root 4096 Dec 12 07:41 volume02</span><br></pre></td></tr></table></figure><p>volume01和volume02这两个卷和外部一定有一个同步的目录</p><p><img src="/2020/12/12/%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%8D%B7/1-4.png" alt="image-20201212154823142"></p><p><code>查看挂载卷的路径</code></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">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker ps</span><br><span class="line">CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES</span><br><span class="line">a01086118f02 c9531b9b79fd "/bin/bash" 12 minutes ago Up 12 minutes</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker inspect a01086118f02</span><br><span class="line">[</span><br><span class="line"> {</span><br><span class="line"> "Id": "a01086118f02a901c48d5bceaa5139a6f79678ba11e6e260109cd0e97f9f7a99",</span><br><span class="line"> "Created": "2020-12-12T07:41:31.340919688Z",</span><br><span class="line"> "Path": "/bin/bash",</span><br><span class="line"> "Args": [],</span><br><span class="line">.............</span><br><span class="line">"Mounts": [</span><br><span class="line"> {</span><br><span class="line"> "Type": "volume",</span><br><span class="line"> "Name": "728f846f5a10ab15df64c5d403983153afa2a67d3bc7edb8c00dc3c9d06cf473",</span><br><span class="line"> "Source": "/var/lib/docker/volumes/728f846f5a10ab15df64c5d403983153afa2a67d3bc7edb8c00dc3c9d06cf473/_data",</span><br><span class="line"> "Destination": "volume01",</span><br><span class="line"> "Driver": "local",</span><br><span class="line"> "Mode": "",</span><br><span class="line"> "RW": true,</span><br><span class="line"> "Propagation": ""</span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> "Type": "volume",</span><br><span class="line"> "Name": "bd059648f78709ba778fdb89c5ffa89b9ac99a4f240bb5a5f5b6dccedbc602b0",</span><br><span class="line"> "Source": "/var/lib/docker/volumes/bd059648f78709ba778fdb89c5ffa89b9ac99a4f240bb5a5f5b6dccedbc602b0/_data",</span><br><span class="line"> "Destination": "volume02",</span><br><span class="line"> "Driver": "local",</span><br><span class="line"> "Mode": "",</span><br><span class="line"> "RW": true,</span><br><span class="line"> "Propagation": ""</span><br><span class="line"> }</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="/2020/12/12/%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%8D%B7/1-5.png" alt="image-20201212160036925"></p><p>这种方式未来使用的非常多,因为我们通常会自己构建自己的镜像。</p><p>假设构建镜像的时候没有挂载卷,需要手动挂载-v卷名:容器内路径</p><h2 id="数据卷容器"><a href="#数据卷容器" class="headerlink" title="数据卷容器"></a>数据卷容器</h2><p><img src="/2020/12/12/%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%8D%B7/1-6.png" alt="image-20201212162739759"></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></pre></td><td class="code"><pre><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker images</span><br><span class="line">REPOSITORY TAG IMAGE ID CREATED SIZE</span><br><span class="line">jonyon/centos 1.0 c9531b9b79fd 58 minutes ago 209MB</span><br><span class="line">mysql 5.7 697daaecf703 15 hours ago 448MB</span><br><span class="line">nginx latest 7baf28ea91eb 26 hours ago 133MB</span><br><span class="line">centos latest 300e315adb2f 4 days ago 209MB</span><br><span class="line"><span class="meta">#</span><span class="bash">启动一个父容器</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker run -it --name docker01 jonyon/centos:1.0</span><br><span class="line">[root@35a2cc3dbfc9 /]# ls</span><br><span class="line">bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var volume01volume02 #volume01、volume02是数据卷</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">启动docker02,继承docker01</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker run -it --name docker02 --volumes-from docker01 jonyon/centos:1.0</span><br><span class="line">[root@00554ad98171 /]# ls</span><br><span class="line">bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var volume01volume02</span><br></pre></td></tr></table></figure><p><code>测试</code></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"><span class="meta">#</span><span class="bash">在docker01的volume01中创建文件docker01</span></span><br><span class="line">[root@35a2cc3dbfc9 /]# cd volume01</span><br><span class="line">[root@35a2cc3dbfc9 volume01]# ls</span><br><span class="line">[root@35a2cc3dbfc9 volume01]# touch docker01</span><br><span class="line">[root@35a2cc3dbfc9 volume01]# ls</span><br><span class="line">docker01</span><br><span class="line"><span class="meta">#</span><span class="bash">docker02可以同步docker01,再在docker02中创建文件docker02</span></span><br><span class="line">[root@00554ad98171 /]# cd volume01</span><br><span class="line">[root@00554ad98171 volume01]# ls</span><br><span class="line">docker01</span><br><span class="line">[root@00554ad98171 volume01]# touch docker02</span><br><span class="line">[root@00554ad98171 volume01]# ls</span><br><span class="line">docker01 docker02</span><br><span class="line"><span class="meta">#</span><span class="bash">docker01中也同步了docker02</span></span><br><span class="line">[root@35a2cc3dbfc9 volume01]# ls</span><br><span class="line">docker01 docker02</span><br></pre></td></tr></table></figure><p><img src="/2020/12/12/%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%8D%B7/1-7.png" alt="image-20201212165126813"></p><p><code>docker01就是数据卷容器</code></p><p>再创建一个容器docker03 volumes-from docker01 也可以实现数据共享。</p><p>只要通过 <strong>–volumes-from</strong> 就可以实现数据共享了</p><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"><span class="meta">#</span><span class="bash">删除了docker01,依旧可以访问docker02,docker03中的docker01文件</span></span><br></pre></td></tr></table></figure><p><img src="/2020/12/12/%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%8D%B7/1-8.png" alt="image-20201212165914932"></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></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">多个mysql实现数据共享</span></span><br><span class="line">docker run -d -p 3344:3306 -v /etc/mysql/conf -v /var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7</span><br><span class="line"></span><br><span class="line">docker run -d -p 3344:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">这个时候,可以实现两个容器数据同步</span></span><br></pre></td></tr></table></figure><p><strong>结论:</strong></p><p>容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止(即删除所有的容器)</p><p>但是一旦持久化到了本地,本地的数据是不会被删除的</p>]]></content>
<summary type="html"><h1 id="容器数据卷"><a href="#容器数据卷" class="headerlink" title="容器数据卷"></a>容器数据卷</h1><h2 id="什么是容器数据卷"><a href="#什么是容器数据卷" class="headerlink" title="什么是容器数据卷"></a>什么是容器数据卷</h2><p><strong>docker理念</strong>:将应用和环境打包成一个镜像</p>
<p>但是如果数据都在容器中,那么容器一删除,数据就会丢失。于是提出了新的需求:<strong>数据持久化</strong></p></summary>
<category term="java" scheme="http://www.jonyonwzj.top/categories/java/"/>
<category term="Docker" scheme="http://www.jonyonwzj.top/tags/Docker/"/>
</entry>
<entry>
<title>Docker镜像加载原理</title>
<link href="http://www.jonyonwzj.top/2020/12/12/Docker%E9%95%9C%E5%83%8F%E5%8A%A0%E8%BD%BD%E5%8E%9F%E7%90%86/"/>
<id>http://www.jonyonwzj.top/2020/12/12/Docker%E9%95%9C%E5%83%8F%E5%8A%A0%E8%BD%BD%E5%8E%9F%E7%90%86/</id>
<published>2020-12-12T03:45:39.000Z</published>
<updated>2021-03-31T15:24:15.367Z</updated>
<content type="html"><![CDATA[<h2 id="镜像是什么"><a href="#镜像是什么" class="headerlink" title="镜像是什么"></a>镜像是什么</h2><p>镜像是一种轻量级,可独立执行的软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的内容,包括代码、运行时,库、环境变量和配置文件</p><p>所有的应用,直接打包docker镜像,就可以运行起来</p><p>如何得到镜像</p><ul><li><p>从远程仓库下载</p></li><li><p>别人拷贝给你</p></li><li><p>自己制作一个DockerFile</p><a id="more"></a></li></ul><h2 id="Docker镜像加载原理"><a href="#Docker镜像加载原理" class="headerlink" title="Docker镜像加载原理"></a>Docker镜像加载原理</h2><h3 id="UnionFS-联合文件系统"><a href="#UnionFS-联合文件系统" class="headerlink" title="UnionFS(联合文件系统)"></a>UnionFS(联合文件系统)</h3><p>下载镜像的时候,一层一层的就是这个</p><p>联合文件系统:Union文件系统是一种分层、轻量级、并且高性能的文件系统、它支持对文件系统的修改作为一次提交来一层层叠加,同时可以将不同目录挂载到同一虚拟文件系统下。联合文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。</p><p>特性:一次同时加载多个文件系统,但从外面看起来。只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。</p><h3 id="Docker镜像加载原理-1"><a href="#Docker镜像加载原理-1" class="headerlink" title="Docker镜像加载原理"></a>Docker镜像加载原理</h3><p>Docker的镜像实际上由一层一层文件系统组成,这种层级文件系统就是联合文件系统</p><p>bootfs(boot life system)主要包含bootloader和kernel,bootloader主要是引导加载kernel,linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的linux系统是一样的,包含boot加载的内核。当boot加载完成之后整个内核就都在内存中了。此时内存的使用已由bootfs转交给内核,此时系统也会卸载bootfs</p><p>rootfs在bootfs之上,包含的就是典型的linux系统中的/dev,/bin,/etc等标准目录和文件,rootfs就是各种不同的操作系统发行版,比如centos等等</p><p><img src="/2020/12/12/Docker%E9%95%9C%E5%83%8F%E5%8A%A0%E8%BD%BD%E5%8E%9F%E7%90%86/1-1.png" alt="image-20201210150556417"></p><p>我们平时安装虚拟机的centos都是好几个g,为什么docker里才200M?</p><p>对于一个精简的os,rootfs可以小,只要包含最基本的命令,工具和程序库就可以,因为底层直接用Host和kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs</p><h2 id="分层理解"><a href="#分层理解" class="headerlink" title="分层理解"></a>分层理解</h2><p><strong>分层的镜像</strong></p><p>下载一个镜像,观察下载的日志输出,可以看到是一层一层在下载</p><p>为什么docker镜像要采用这种分层的结构呢?</p><p>因为可以进行资源共享。比如有多个镜像从相同的Base镜像构建而来,那么宿主机只需要在磁盘上保留一份Base镜像,同时内存中也只需要加载一份Base镜像,这样就可以为所有的容器服务了,而且镜像每一层都可以被共享。</p><p><strong>理解</strong></p><p>所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的镜像层的时候,就会在当前镜像层之上,创建新的镜像层。</p><p><img src="/2020/12/12/Docker%E9%95%9C%E5%83%8F%E5%8A%A0%E8%BD%BD%E5%8E%9F%E7%90%86/1-2.png" alt="image-20201210153321084"></p><p>在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下面这个例子,每个镜像层包含三个文件,而镜像包含了两个镜像层的6个文件。</p><p><img src="/2020/12/12/Docker%E9%95%9C%E5%83%8F%E5%8A%A0%E8%BD%BD%E5%8E%9F%E7%90%86/1-3.png" alt="image-20201210153632361"></p><p>下图展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版本。</p><p><img src="/2020/12/12/Docker%E9%95%9C%E5%83%8F%E5%8A%A0%E8%BD%BD%E5%8E%9F%E7%90%86/1-4.png" alt="image-20201210153808042"></p><p>上图镜像层中的文件覆盖了底层镜像层中的文件,这样就使得文件的更新版本作为一个新的镜像层添加到镜像中。</p><p>Docker通过存储引擎(新版本是采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一文件系统</p><p>下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。</p><p><img src="/2020/12/12/Docker%E9%95%9C%E5%83%8F%E5%8A%A0%E8%BD%BD%E5%8E%9F%E7%90%86/1-5.png" alt="image-20201210154242853"></p><p><strong>特点</strong></p><p>Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部</p><p><strong>这一层就是我们通常所说的容器层,容器之下的都叫镜像层</strong></p><p><img src="/2020/12/12/Docker%E9%95%9C%E5%83%8F%E5%8A%A0%E8%BD%BD%E5%8E%9F%E7%90%86/1-6.png" alt="image-20201210154456020"></p>]]></content>
<summary type="html"><h2 id="镜像是什么"><a href="#镜像是什么" class="headerlink" title="镜像是什么"></a>镜像是什么</h2><p>镜像是一种轻量级,可独立执行的软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的内容,包括代码、运行时,库、环境变量和配置文件</p>
<p>所有的应用,直接打包docker镜像,就可以运行起来</p>
<p>如何得到镜像</p>
<ul>
<li><p>从远程仓库下载</p>
</li>
<li><p>别人拷贝给你</p>
</li>
<li><p>自己制作一个DockerFile</p></li></ul></summary>
<category term="运维" scheme="http://www.jonyonwzj.top/categories/%E8%BF%90%E7%BB%B4/"/>
<category term="容器" scheme="http://www.jonyonwzj.top/tags/%E5%AE%B9%E5%99%A8/"/>
</entry>
<entry>
<title>git</title>
<link href="http://www.jonyonwzj.top/2020/12/11/git/"/>
<id>http://www.jonyonwzj.top/2020/12/11/git/</id>
<published>2020-12-11T08:31:39.000Z</published>
<updated>2020-12-11T08:34:26.625Z</updated>
<content type="html"><![CDATA[<h1 id="查看配置信息"><a href="#查看配置信息" class="headerlink" title="查看配置信息"></a>查看配置信息</h1><p>git config –list</p><a id="more"></a><h1 id="设置用户信息"><a href="#设置用户信息" class="headerlink" title="设置用户信息"></a>设置用户信息</h1><p>git config –global user.name “”<br>git config –global user.email “”</p><h1 id="在本地初始化一个git仓库-此文件为隐藏文件夹"><a href="#在本地初始化一个git仓库-此文件为隐藏文件夹" class="headerlink" title="在本地初始化一个git仓库 (此文件为隐藏文件夹)#"></a>在本地初始化一个git仓库 (此文件为隐藏文件夹)#</h1><p>git init</p><h1 id="从远程仓库克隆"><a href="#从远程仓库克隆" class="headerlink" title="从远程仓库克隆"></a>从远程仓库克隆</h1><p>git clone 远程Git仓库地址</p><h1 id="工作目录、暂存区、-版本库概念"><a href="#工作目录、暂存区、-版本库概念" class="headerlink" title="工作目录、暂存区、 版本库概念#"></a>工作目录、暂存区、 版本库概念#</h1><p>版本库: .git隐藏文件<br>工作目录:包含.git文件夹的目录<br>暂存区: .git文件中的index文件</p><h1 id="git工作目录下文件的两种状态"><a href="#git工作目录下文件的两种状态" class="headerlink" title="git工作目录下文件的两种状态"></a>git工作目录下文件的两种状态</h1><p>untracked 未跟踪(未被纳入版本控制)<br>tracked 已跟踪(被纳入版本控制)<br> Unmodified 未修改状态<br> Modified 修改状态<br> Staged 已暂存状态</p><hr><h1 id="本地仓库操作"><a href="#本地仓库操作" class="headerlink" title="本地仓库操作"></a>本地仓库操作</h1><h2 id="查看状态"><a href="#查看状态" class="headerlink" title="查看状态"></a>查看状态</h2><p>git status<br>git status -s (使输出信息更加简洁)</p><h2 id="将未跟踪文件加入暂存区"><a href="#将未跟踪文件加入暂存区" class="headerlink" title="将未跟踪文件加入暂存区"></a>将未跟踪文件加入暂存区</h2><p>git add hello.txt</p><h2 id="将暂存区的文件取消暂存"><a href="#将暂存区的文件取消暂存" class="headerlink" title="将暂存区的文件取消暂存"></a>将暂存区的文件取消暂存</h2><p>git reset hello.txt</p><h2 id="将暂存区的文件修改提交到仓库"><a href="#将暂存区的文件修改提交到仓库" class="headerlink" title="将暂存区的文件修改提交到仓库"></a>将暂存区的文件修改提交到仓库</h2><p>git commit -m “日志文件”</p><h2 id="删除文件"><a href="#删除文件" class="headerlink" title="删除文件"></a>删除文件</h2><p>git rm hello.txt(只删除了工作区的,把操作放到暂存区)<br>git commit -m “delete hello.txt”(提交到本地仓库,真正删除)<br>注:手动删除后文件会变为未跟踪状态,需要git add 加入暂存区后,git commit 提交文件修改状态到仓库</p><h2 id="忽略列表"><a href="#忽略列表" class="headerlink" title="忽略列表"></a>忽略列表</h2><p>touch .gitignore 创建一个.gitignore文件列出要忽略的文件模式</p><p><em>.a (以.a结尾的文件忽略不进行管理)<br>!lib.a (lib.a除外)<br>/todo (tode文件忽略)<br>build/ (build目录下所有文件忽略)<br>doc/</em>.txt (忽略doc目录下所有的txt文件)<br>doc/*<em>/</em>.pdf (忽略doc目录下包含子目录下的所有pdf文件)</p><h2 id="查看日志信息"><a href="#查看日志信息" class="headerlink" title="查看日志信息"></a>查看日志信息</h2><p>git log</p><hr><h1 id="远程仓库操作"><a href="#远程仓库操作" class="headerlink" title="远程仓库操作"></a>远程仓库操作</h1><h2 id="查看远程仓库"><a href="#查看远程仓库" class="headerlink" title="查看远程仓库"></a>查看远程仓库</h2><p>git remote<br>git remote -v<br>git remote show origin(显示详细信息)</p><h2 id="添加远程仓库"><a href="#添加远程仓库" class="headerlink" title="添加远程仓库"></a>添加远程仓库</h2><p>git remote add 仓库名(一般叫origin) 地址</p><h2 id="移除无效远程仓库"><a href="#移除无效远程仓库" class="headerlink" title="移除无效远程仓库"></a>移除无效远程仓库</h2><p>git remote rm 仓库名 (只是从本地移除远程仓库的记录,并不会真正影响到远程仓库)</p><h2 id="从远程仓库抓取或拉取"><a href="#从远程仓库抓取或拉取" class="headerlink" title="从远程仓库抓取或拉取"></a>从远程仓库抓取或拉取</h2><p>git fitch是从远程仓库获取最新版本到本地仓库,不会自动merge(合并)<br>git merge origin/master(合并origin/master分支)</p><p>git pull是从远程仓库获取最新版本到本地仓库,会自动merge(合并)<br>git pull origin master –allow-unrelated-histories(强行拉取)</p><h2 id="推送到远程仓库"><a href="#推送到远程仓库" class="headerlink" title="推送到远程仓库"></a>推送到远程仓库</h2><p>git push origin master</p><hr><h1 id="git分支"><a href="#git分支" class="headerlink" title="git分支"></a>git分支</h1><h2 id="查看分支"><a href="#查看分支" class="headerlink" title="查看分支"></a>查看分支</h2><p>git branch 列出所有本地分支<br>git branch -r 列出所有远程分支<br>git branch -a 列出所有本地分支和远程分支</p><h2 id="创建分支"><a href="#创建分支" class="headerlink" title="创建分支"></a>创建分支</h2><p>git branch 分支名称(b1)</p><h2 id="切换分支"><a href="#切换分支" class="headerlink" title="切换分支"></a>切换分支</h2><p>git checkout 分支名称(b1)</p><h2 id="推送至远程仓库分支"><a href="#推送至远程仓库分支" class="headerlink" title="推送至远程仓库分支"></a>推送至远程仓库分支</h2><p>git push origin 分支名称(b1)</p><h2 id="合并分支"><a href="#合并分支" class="headerlink" title="合并分支"></a>合并分支</h2><p>git merge 分支名称b1</p><p>有时候合并操作不会如此顺利,如果你在两个不同的分支中,对同一个文件的同一个部分进行了不同的修改,git就没办法合并他们,<br>同时会提示文件冲突。此时我们需要打开冲突的文件并修复冲突的内容,最后执行git add命令来标识冲突已解决。</p><h2 id="推送到远程仓库-1"><a href="#推送到远程仓库-1" class="headerlink" title="推送到远程仓库"></a>推送到远程仓库</h2><p>git push origin 分支名称(master)<br>git push origin 分支名称(b1)</p><h2 id="删除分支"><a href="#删除分支" class="headerlink" title="删除分支"></a>删除分支</h2><p>git branch -d 分支名称(b1)<br>git branch -D 分支名称(b1) (强制删除)</p><h2 id="删除远程仓库的分支"><a href="#删除远程仓库的分支" class="headerlink" title="删除远程仓库的分支"></a>删除远程仓库的分支</h2><p>git push origin -d 分支名称(b1)</p><hr><h1 id="git标签"><a href="#git标签" class="headerlink" title="git标签"></a>git标签</h1><h2 id="创建标签"><a href="#创建标签" class="headerlink" title="创建标签"></a>创建标签</h2><p>git tag 标签名(v1.0)</p><h2 id="列出已有的标签"><a href="#列出已有的标签" class="headerlink" title="列出已有的标签"></a>列出已有的标签</h2><p>git tag (列出所有tag)<br>git show 标签名(v1.0)</p><h2 id="将标签推送至远程仓库"><a href="#将标签推送至远程仓库" class="headerlink" title="将标签推送至远程仓库"></a>将标签推送至远程仓库</h2><p>git push 远程仓库名(origin) 标签名(v1.0)</p><h2 id="检出标签"><a href="#检出标签" class="headerlink" title="检出标签"></a>检出标签</h2><p>git checkout -b 分支名称(b2) 标签名(v1.0) 创建新的分支b2状态为v1.0的状态</p><h2 id="删除标签"><a href="#删除标签" class="headerlink" title="删除标签"></a>删除标签</h2><p>git tag -d 标签名(v1.0) 删除本地标签<br>git push origin:refs/tags/标签名 删除远程标签</p>]]></content>
<summary type="html"><h1 id="查看配置信息"><a href="#查看配置信息" class="headerlink" title="查看配置信息"></a>查看配置信息</h1><p>git config –list</p></summary>
<category term="git" scheme="http://www.jonyonwzj.top/tags/git/"/>
</entry>
<entry>
<title>谈谈final、finally、finalize有什么不同</title>
<link href="http://www.jonyonwzj.top/2020/12/10/%E8%B0%88%E8%B0%88final%E3%80%81finally%E3%80%81finalize%E6%9C%89%E4%BB%80%E4%B9%88%E4%B8%8D%E5%90%8C/"/>
<id>http://www.jonyonwzj.top/2020/12/10/%E8%B0%88%E8%B0%88final%E3%80%81finally%E3%80%81finalize%E6%9C%89%E4%BB%80%E4%B9%88%E4%B8%8D%E5%90%8C/</id>
<published>2020-12-10T12:59:13.000Z</published>
<updated>2020-12-10T13:10:40.893Z</updated>
<content type="html"><![CDATA[<h1 id="典型回答"><a href="#典型回答" class="headerlink" title="典型回答"></a>典型回答</h1><p>final(修饰词):适合用来在语义方面标识当前的方法、变量、类不可以更改,适合封装一些代码,让用的人知道这些不要随意更改。<strong>final</strong>标识的变量不等于不可变,对于变量而言这个变量只是不能够再赋值,但是可以做任何增删改查操作。所以从这方面来讲,final在高并发下面的数据一致性起到积极作用,对性能比较好。</p><a id="more"></a><p>要想写一个不可变的对象(immutable):</p><p>首先对象和类的成员都是private和final;</p><p>其次对象的赋值不要直接赋值,而是采用<strong>深拷贝</strong>;</p><p>对象不要随意实现setter()方法;</p><p>在获取当前对象或状态的时候要遵守<strong>copy or write**</strong>原则**,创建私有的copy。</p><p>finally(基础类):保证重点代码一定要被执行的<strong>一种机制</strong>,在一些资源处理关闭时用到,使用try-finally,try-catch-finally来进行类似关闭JDBC,保证unlock锁等动作,对于try catch最好即关即用。更推荐使用java7中添加的try-with-resources语句。</p><blockquote><p>try-with-resources(语法糖):</p><p>try-with-resources会自动关闭try()中的资源,并且将先关闭后声明的资源。</p></blockquote><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></pre></td><td class="code"><pre><span class="line">列几个 fianlly 不会被执行的情况:</span><br><span class="line"><span class="number">1.</span> <span class="keyword">try</span>-cach 异常退出。</span><br><span class="line"><span class="keyword">try</span>{</span><br><span class="line">system.exit(<span class="number">1</span>)</span><br><span class="line">}<span class="keyword">finally</span>{</span><br><span class="line">print(abc)</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"><span class="keyword">try</span>{</span><br><span class="line"> <span class="keyword">while</span>(ture){</span><br><span class="line"> print(abc)</span><br><span class="line"> }</span><br><span class="line">}<span class="keyword">finally</span>{</span><br><span class="line">print(abc)</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">当执行 <span class="keyword">try</span>,<span class="keyword">finally</span> 的线程被杀死时。<span class="keyword">finally</span> 也无法执行。</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 class="keyword">finally</span> 中使用 <span class="keyword">return</span> 语句。</span><br><span class="line"><span class="number">2</span>,<span class="keyword">finally</span> 总是执行,除非程序或者线程被中断。</span><br></pre></td></tr></table></figure><p>finalize(基础类):java虚拟机在实现GC(垃圾回收)时调用的方法,理论上是进行内存回收等操作的地方。但实际上这个方法调用时机并不固定,有可能处理不当导致程序异常。并且finalize源码实现使用了try catch,但是并没有抛出异常,而是生吞。所以要是在这里面处理逻辑,自己都不知道哪里出了问题。<strong>finalize**</strong>机制**已经不推荐使用,并且在JDK9被标记为deprecated.(目前在逐步使用Cleaner来替换掉原有的finalize实现)</p><h1 id="深拷贝与浅拷贝"><a href="#深拷贝与浅拷贝" class="headerlink" title="深拷贝与浅拷贝"></a>深拷贝与浅拷贝</h1><p>这两个概念的区别就是“当在给一个变量赋值的时候是否直接使用这个值的内存地址”</p><p>例如:</p><p>基础类型都是值传递,所以浅拷贝过来的对象赋值后不会影响之前被拷贝的对象。</p><p>但是对于引用类型的变量,在拷贝的时候就需要考虑了,如果你要使新的对象的赋值不会影响之前被拷贝的对象,就要用深拷贝,否则就是copy的内存地址。</p><p>一个类实现拷贝的功能很简单,有两种方式:</p><p>1.实现Clone接口,在clone方法里面进行拷贝</p><p>2.要是实现序列化,先把对象写到输入流里面,然后再读出来对象,这样就是一个新的对象了。</p><h1 id="Copy-or-write"><a href="#Copy-or-write" class="headerlink" title="Copy or write"></a>Copy or write</h1><p>Copy or write:保证只有一个专门的线程往里面写;可以有多个线程读取,这样能保证线程同步。</p><p>Copy or wirte原则核心思想:有线程使用容器中的数据时,如果是写入,则复制出一个新容器,修改新容器中的数据后,再将引用指向新容器。如果是读操作则正常读引用地址中的容器数据。</p>]]></content>
<summary type="html"><h1 id="典型回答"><a href="#典型回答" class="headerlink" title="典型回答"></a>典型回答</h1><p>final(修饰词):适合用来在语义方面标识当前的方法、变量、类不可以更改,适合封装一些代码,让用的人知道这些不要随意更改。<strong>final</strong>标识的变量不等于不可变,对于变量而言这个变量只是不能够再赋值,但是可以做任何增删改查操作。所以从这方面来讲,final在高并发下面的数据一致性起到积极作用,对性能比较好。</p></summary>
<category term="java" scheme="http://www.jonyonwzj.top/categories/java/"/>
<category term="Java面试基础" scheme="http://www.jonyonwzj.top/tags/Java%E9%9D%A2%E8%AF%95%E5%9F%BA%E7%A1%80/"/>
</entry>
<entry>
<title>Docker的常用命令</title>
<link href="http://www.jonyonwzj.top/2020/12/09/Docker%E7%9A%84%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/"/>
<id>http://www.jonyonwzj.top/2020/12/09/Docker%E7%9A%84%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/</id>
<published>2020-12-09T09:54:30.000Z</published>
<updated>2020-12-09T09:58:04.964Z</updated>
<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><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 version #显示docker的版本信息</span><br><span class="line">docker info #显示docker的系统信息,包括镜像和容器的数量</span><br><span class="line">docker --help #万能命令 帮助命令</span><br></pre></td></tr></table></figure><a id="more"></a><h2 id="镜像命令"><a href="#镜像命令" class="headerlink" title="镜像命令"></a>镜像命令</h2><p><strong>docker images</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><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">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker images</span><br><span class="line">REPOSITORY TAG IMAGE ID CREATED SIZE</span><br><span class="line">hello-world latest bf756fb1ae65 11 months ago 13.3kB</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">解释</span></span><br><span class="line">REPOSITORY 镜像仓库源</span><br><span class="line">TAG 标签</span><br><span class="line">IMAGE ID id</span><br><span class="line">CREATED 创建时间</span><br><span class="line">SIZE 大小</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">可选项</span></span><br><span class="line">Options:</span><br><span class="line"> -a, --all #列出所有镜像</span><br><span class="line"> -q, --quiet #只显示镜像的id</span><br></pre></td></tr></table></figure><p><strong>docker search</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><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">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# 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… 10247 [OK] </span><br><span class="line">mariadb MariaDB is a community-developed fork of MyS… 3785 [OK] </span><br><span class="line"><span class="meta">#</span><span class="bash">STARS 收藏数</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">可选项,通过收藏来过滤</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker search mysql --filter=STARS=3000 #瘦素出来的镜像收藏大于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… 10247 [OK] </span><br><span class="line">mariadb MariaDB is a community-developed fork of MyS… 3785 [OK] </span><br><span class="line"></span><br></pre></td></tr></table></figure><p><strong>docker pull</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><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">#</span><span class="bash">下载镜像 docker pull 镜像名[:tag]</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker pull mysql</span><br><span class="line">Using default tag: latest #如果不写tag,默认就是lates</span><br><span class="line">latest: Pulling from library/mysql</span><br><span class="line">852e50cd189d: Pull complete #分层下载,docker image的核心联合文件</span><br><span class="line">29969ddb0ffb: Pull complete </span><br><span class="line">a43f41a44c48: Pull complete </span><br><span class="line">5cdd802543a3: Pull complete </span><br><span class="line">b79b040de953: Pull complete </span><br><span class="line">938c64119969: Pull complete </span><br><span class="line">7689ec51a0d9: Pull complete </span><br><span class="line">a880ba7c411f: Pull complete </span><br><span class="line">984f656ec6ca: Pull complete </span><br><span class="line">9f497bce458a: Pull complete </span><br><span class="line">b9940f97694b: Pull complete </span><br><span class="line">2f069358dc96: Pull complete </span><br><span class="line">Digest: sha256:4bb2e81a40e9d0d59bd8e3dc2ba5e1f2197696f6de39a91e90798dd27299b093 #签名</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">#</span><span class="bash">docker pull mysql 等价于 docker pull docker.io/library/mysql:latest</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">指定版本下载</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker pull mysql:5.7</span><br><span class="line">5.7: Pulling from library/mysql</span><br><span class="line">852e50cd189d: Already exists #不下载重复文件</span><br><span class="line">29969ddb0ffb: Already exists </span><br><span class="line">a43f41a44c48: Already exists </span><br><span class="line">5cdd802543a3: Already exists </span><br><span class="line">b79b040de953: Already exists </span><br><span class="line">938c64119969: Already exists </span><br><span class="line">7689ec51a0d9: Already exists </span><br><span class="line">36bd6224d58f: Pull complete </span><br><span class="line">cab9d3fa4c8c: Pull complete </span><br><span class="line">1b741e1c47de: Pull complete </span><br><span class="line">aac9d11987ac: Pull complete </span><br><span class="line">Digest: sha256:8e2004f9fe43df06c3030090f593021a5f283d028b5ed5765cc24236c2c4d88e</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></pre></td></tr></table></figure><p><strong>docker rmi</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><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">#</span><span class="bash">rmi:remove image</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">删除指定的镜像</span></span><br><span class="line">docker rmi -f 镜像id</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker rmi -f ae0658fdbad5</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">删除多个镜像</span></span><br><span class="line">docker rmi -f 镜像id 镜像id 镜像id </span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">删除全部镜像</span></span><br><span class="line">docker rmi -f $(docker images -aq)</span><br></pre></td></tr></table></figure><h2 id="容器命令"><a href="#容器命令" class="headerlink" title="容器命令"></a>容器命令</h2><p><strong>有了镜像才可以创建容器,linux,下载一个centOS来测试学习</strong></p><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">docker pull centos</span><br></pre></td></tr></table></figure><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><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">docker run[可选参数] 镜像名</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">参数说明</span></span><br><span class="line">--name="Name" 容器名字 --tomcat01,tomcat02来区分容器</span><br><span class="line">-d 后台方式运行</span><br><span class="line">-it 使用交互方式运行,进入容器查看内容 i是交互,t是伪终端,两者通常同时使用</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"> 容器端口</span><br><span class="line">-P 随机指定端口</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">新建启动并进入容器</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker run -it centos /bin/bash</span><br><span class="line">[root@82f74728d9db /]# ls #容器内部的centos,内部的centos和外部的centos没有关系,很多命令是不完善的</span><br><span class="line">bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var</span><br><span class="line"><span class="meta">#</span><span class="bash">从容器中退出</span></span><br><span class="line">[root@82f74728d9db /]# exit</span><br><span class="line">exit</span><br></pre></td></tr></table></figure><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><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">#</span><span class="bash">docker ps命令</span></span><br><span class="line"> #列出正在运行的容器</span><br><span class="line"> -a #列出正在运行的容器+历史运行过的容器</span><br><span class="line"> -n=? #显示最近创建的容器</span><br><span class="line"> -q #只显示容器的编号</span><br><span class="line"></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker ps #正在运行的容器</span><br><span class="line">CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker ps -a #运行过的容器</span><br><span class="line">CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES</span><br><span class="line">82f74728d9db centos "/bin/bash" 4 minutes ago Exited (0) About a minute ago objective_haslett</span><br><span class="line">bce4aec829a4 bf756fb1ae65 "/hello" 2 hours ago Exited (0) 2 hours ago sleepy_mcnulty</span><br><span class="line"></span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line">exit #容器停止并退出</span><br><span class="line">Ctrl+p+q #容器不停止退出</span><br></pre></td></tr></table></figure><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></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><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></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><h2 id="常用其他命令"><a href="#常用其他命令" class="headerlink" title="常用其他命令"></a>常用其他命令</h2><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><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">docker run -d 镜像名</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker run -d centos</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">问题:执行docker ps,发现后台停止了</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker ps</span><br><span class="line">CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">常见的坑:docker容器使用后台运行,就必须要有一个前台进程,docker返现没有应用,就会自动停止</span></span><br><span class="line"><span class="meta">#</span><span class="bash">Nginx:容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了</span></span><br></pre></td></tr></table></figure><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><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">docker logs -tf --tail 容器,没有日志</span><br><span class="line"><span class="meta">#</span><span class="bash">自己编写一段shell脚本</span></span><br><span class="line">docker run -d centos /bin/sh -c "while true;do echo wzj;sleep 1;done"</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">显示日志</span></span><br><span class="line">docker logs -tf --tail 10 容器id</span><br><span class="line">-f 动态打印内容,先打印10条,后面继续打印</span><br><span class="line">-t 打印时间戳+内容,只打印10条</span><br><span class="line">-tf 动态打印时间戳+内容,先打印10条,后面继续打印</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">命令 docker top 容器id</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker top 61aefd99735b</span><br><span class="line">UID PID PPID C STIME TTY TIME CMD</span><br><span class="line">root 10447 10423 0 14:03 ? 00:00:00 /bin/sh -c while true;do echo wzj;sleep 1;done</span><br><span class="line">root 11444 10447 0 14:10 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1</span><br><span class="line"></span><br></pre></td></tr></table></figure><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><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><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">命令 docker inspect 容器id</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker inspect 61aefd99735b</span><br><span class="line">[</span><br><span class="line"> {</span><br><span class="line"> "Id": "61aefd99735ba514d489686897c1aedd42565403ab6250db9b9dd1ba0b1e3d04",</span><br><span class="line"> "Created": "2020-12-09T06:03:00.62604644Z",</span><br><span class="line"> "Path": "/bin/sh",</span><br><span class="line"> "Args": [</span><br><span class="line"> "-c",</span><br><span class="line"> "while true;do echo wzj;sleep 1;done"</span><br><span class="line"> ],</span><br><span class="line"> "State": {</span><br><span class="line"> "Status": "running",</span><br><span class="line"> "Running": true,</span><br><span class="line"> "Paused": false,</span><br><span class="line"> "Restarting": false,</span><br><span class="line"> "OOMKilled": false,</span><br><span class="line"> "Dead": false,</span><br><span class="line"> "Pid": 10447,</span><br><span class="line"> "ExitCode": 0,</span><br><span class="line"> "Error": "",</span><br><span class="line"> "StartedAt": "2020-12-09T06:03:00.967666729Z",</span><br><span class="line"> "FinishedAt": "0001-01-01T00:00:00Z"</span><br><span class="line"> },</span><br><span class="line"> "Image": "sha256:300e315adb2f96afe5f0b2780b87f28ae95231fe3bdd1e16b9ba606307728f55",</span><br><span class="line"> "ResolvConfPath": "/var/lib/docker/containers/61aefd99735ba514d489686897c1aedd42565403ab6250db9b9dd1ba0b1e3d04/resolv.conf",</span><br><span class="line"> "HostnamePath": "/var/lib/docker/containers/61aefd99735ba514d489686897c1aedd42565403ab6250db9b9dd1ba0b1e3d04/hostname",</span><br><span class="line"> "HostsPath": "/var/lib/docker/containers/61aefd99735ba514d489686897c1aedd42565403ab6250db9b9dd1ba0b1e3d04/hosts",</span><br><span class="line"> "LogPath": "/var/lib/docker/containers/61aefd99735ba514d489686897c1aedd42565403ab6250db9b9dd1ba0b1e3d04/61aefd99735ba514d489686897c1aedd42565403ab6250db9b9dd1ba0b1e3d04-json.log",</span><br><span class="line"> "Name": "/sharp_colden",</span><br><span class="line"> "RestartCount": 0,</span><br><span class="line"> "Driver": "overlay2",</span><br><span class="line"> "Platform": "linux",</span><br><span class="line"> "MountLabel": "",</span><br><span class="line"> "ProcessLabel": "",</span><br><span class="line"> "AppArmorProfile": "",</span><br><span class="line"> "ExecIDs": null,</span><br><span class="line"> "HostConfig": {</span><br><span class="line"> "Binds": null,</span><br><span class="line"> "ContainerIDFile": "",</span><br><span class="line"> "LogConfig": {</span><br><span class="line"> "Type": "json-file",</span><br><span class="line"> "Config": {}</span><br><span class="line"> },</span><br><span class="line"> "NetworkMode": "default",</span><br><span class="line"> "PortBindings": {},</span><br><span class="line"> "RestartPolicy": {</span><br><span class="line"> "Name": "no",</span><br><span class="line"> "MaximumRetryCount": 0</span><br><span class="line"> },</span><br><span class="line"> "AutoRemove": false,</span><br><span class="line"> "VolumeDriver": "",</span><br><span class="line"> "VolumesFrom": null,</span><br><span class="line"> "CapAdd": null,</span><br><span class="line"> "CapDrop": null,</span><br><span class="line"> "Capabilities": null,</span><br><span class="line"> "Dns": [],</span><br><span class="line"> "DnsOptions": [],</span><br><span class="line"> "DnsSearch": [],</span><br><span class="line"> "ExtraHosts": null,</span><br><span class="line"> "GroupAdd": null,</span><br><span class="line"> "IpcMode": "private",</span><br><span class="line"> "Cgroup": "",</span><br><span class="line"> "Links": null,</span><br><span class="line"> "OomScoreAdj": 0,</span><br><span class="line"> "PidMode": "",</span><br><span class="line"> "Privileged": false,</span><br><span class="line"> "PublishAllPorts": false,</span><br><span class="line"> "ReadonlyRootfs": false,</span><br><span class="line"> "SecurityOpt": null,</span><br><span class="line"> "UTSMode": "",</span><br><span class="line"> "UsernsMode": "",</span><br><span class="line"> "ShmSize": 67108864,</span><br><span class="line"> "Runtime": "runc",</span><br><span class="line"> "ConsoleSize": [</span><br><span class="line"> 0,</span><br><span class="line"> 0</span><br><span class="line"> ],</span><br><span class="line"> "Isolation": "",</span><br><span class="line"> "CpuShares": 0,</span><br><span class="line"> "Memory": 0,</span><br><span class="line"> "NanoCpus": 0,</span><br><span class="line"> "CgroupParent": "",</span><br><span class="line"> "BlkioWeight": 0,</span><br><span class="line"> "BlkioWeightDevice": [],</span><br><span class="line"> "BlkioDeviceReadBps": null,</span><br><span class="line"> "BlkioDeviceWriteBps": null,</span><br><span class="line"> "BlkioDeviceReadIOps": null,</span><br><span class="line"> "BlkioDeviceWriteIOps": null,</span><br><span class="line"> "CpuPeriod": 0,</span><br><span class="line"> "CpuQuota": 0,</span><br><span class="line"> "CpuRealtimePeriod": 0,</span><br><span class="line"> "CpuRealtimeRuntime": 0,</span><br><span class="line"> "CpusetCpus": "",</span><br><span class="line"> "CpusetMems": "",</span><br><span class="line"> "Devices": [],</span><br><span class="line"> "DeviceCgroupRules": null,</span><br><span class="line"> "DeviceRequests": null,</span><br><span class="line"> "KernelMemory": 0,</span><br><span class="line"> "KernelMemoryTCP": 0,</span><br><span class="line"> "MemoryReservation": 0,</span><br><span class="line"> "MemorySwap": 0,</span><br><span class="line"> "MemorySwappiness": null,</span><br><span class="line"> "OomKillDisable": false,</span><br><span class="line"> "PidsLimit": null,</span><br><span class="line"> "Ulimits": null,</span><br><span class="line"> "CpuCount": 0,</span><br><span class="line"> "CpuPercent": 0,</span><br><span class="line"> "IOMaximumIOps": 0,</span><br><span class="line"> "IOMaximumBandwidth": 0,</span><br><span class="line"> "MaskedPaths": [</span><br><span class="line"> "/proc/asound",</span><br><span class="line"> "/proc/acpi",</span><br><span class="line"> "/proc/kcore",</span><br><span class="line"> "/proc/keys",</span><br><span class="line"> "/proc/latency_stats",</span><br><span class="line"> "/proc/timer_list",</span><br><span class="line"> "/proc/timer_stats",</span><br><span class="line"> "/proc/sched_debug",</span><br><span class="line"> "/proc/scsi",</span><br><span class="line"> "/sys/firmware"</span><br><span class="line"> ],</span><br><span class="line"> "ReadonlyPaths": [</span><br><span class="line"> "/proc/bus",</span><br><span class="line"> "/proc/fs",</span><br><span class="line"> "/proc/irq",</span><br><span class="line"> "/proc/sys",</span><br><span class="line"> "/proc/sysrq-trigger"</span><br><span class="line"> ]</span><br><span class="line"> },</span><br><span class="line"> "GraphDriver": {</span><br><span class="line"> "Data": {</span><br><span class="line"> "LowerDir": "/var/lib/docker/overlay2/d82a3742a1536776a8ca12275a828d31d2aa577d9e7ccdeaa1e52823b368d5fd-init/diff:/var/lib/docker/overlay2/95dda4a69e01b60eaf2ce0ea310c41f2be953dd10d4a0716f6f4368e22dc1595/diff",</span><br><span class="line"> "MergedDir": "/var/lib/docker/overlay2/d82a3742a1536776a8ca12275a828d31d2aa577d9e7ccdeaa1e52823b368d5fd/merged",</span><br><span class="line"> "UpperDir": "/var/lib/docker/overlay2/d82a3742a1536776a8ca12275a828d31d2aa577d9e7ccdeaa1e52823b368d5fd/diff",</span><br><span class="line"> "WorkDir": "/var/lib/docker/overlay2/d82a3742a1536776a8ca12275a828d31d2aa577d9e7ccdeaa1e52823b368d5fd/work"</span><br><span class="line"> },</span><br><span class="line"> "Name": "overlay2"</span><br><span class="line"> },</span><br><span class="line"> "Mounts": [],</span><br><span class="line"> "Config": {</span><br><span class="line"> "Hostname": "61aefd99735b",</span><br><span class="line"> "Domainname": "",</span><br><span class="line"> "User": "",</span><br><span class="line"> "AttachStdin": false,</span><br><span class="line"> "AttachStdout": false,</span><br><span class="line"> "AttachStderr": false,</span><br><span class="line"> "Tty": false,</span><br><span class="line"> "OpenStdin": false,</span><br><span class="line"> "StdinOnce": false,</span><br><span class="line"> "Env": [</span><br><span class="line"> "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"</span><br><span class="line"> ],</span><br><span class="line"> "Cmd": [</span><br><span class="line"> "/bin/sh",</span><br><span class="line"> "-c",</span><br><span class="line"> "while true;do echo wzj;sleep 1;done"</span><br><span class="line"> ],</span><br><span class="line"> "Image": "centos",</span><br><span class="line"> "Volumes": null,</span><br><span class="line"> "WorkingDir": "",</span><br><span class="line"> "Entrypoint": null,</span><br><span class="line"> "OnBuild": null,</span><br><span class="line"> "Labels": {</span><br><span class="line"> "org.label-schema.build-date": "20201204",</span><br><span class="line"> "org.label-schema.license": "GPLv2",</span><br><span class="line"> "org.label-schema.name": "CentOS Base Image",</span><br><span class="line"> "org.label-schema.schema-version": "1.0",</span><br><span class="line"> "org.label-schema.vendor": "CentOS"</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> "NetworkSettings": {</span><br><span class="line"> "Bridge": "",</span><br><span class="line"> "SandboxID": "eb5b89741e2e4fdb4c694f7e841ea4c9e8463c6cf30c3ca9756a0eee8636f220",</span><br><span class="line"> "HairpinMode": false,</span><br><span class="line"> "LinkLocalIPv6Address": "",</span><br><span class="line"> "LinkLocalIPv6PrefixLen": 0,</span><br><span class="line"> "Ports": {},</span><br><span class="line"> "SandboxKey": "/var/run/docker/netns/eb5b89741e2e",</span><br><span class="line"> "SecondaryIPAddresses": null,</span><br><span class="line"> "SecondaryIPv6Addresses": null,</span><br><span class="line"> "EndpointID": "44576319715bea27fb66b2258585ac4d3e42eed35d92dbcf35810d1884fc663f",</span><br><span class="line"> "Gateway": "172.17.0.1",</span><br><span class="line"> "GlobalIPv6Address": "",</span><br><span class="line"> "GlobalIPv6PrefixLen": 0,</span><br><span class="line"> "IPAddress": "172.17.0.2",</span><br><span class="line"> "IPPrefixLen": 16,</span><br><span class="line"> "IPv6Gateway": "",</span><br><span class="line"> "MacAddress": "02:42:ac:11:00:02",</span><br><span class="line"> "Networks": {</span><br><span class="line"> "bridge": {</span><br><span class="line"> "IPAMConfig": null,</span><br><span class="line"> "Links": null,</span><br><span class="line"> "Aliases": null,</span><br><span class="line"> "NetworkID": "86dff082c7cb9acb552b2acf9116e7d6290a6c301fab07f364ab877f8a0b8483",</span><br><span class="line"> "EndpointID": "44576319715bea27fb66b2258585ac4d3e42eed35d92dbcf35810d1884fc663f",</span><br><span class="line"> "Gateway": "172.17.0.1",</span><br><span class="line"> "IPAddress": "172.17.0.2",</span><br><span class="line"> "IPPrefixLen": 16,</span><br><span class="line"> "IPv6Gateway": "",</span><br><span class="line"> "GlobalIPv6Address": "",</span><br><span class="line"> "GlobalIPv6PrefixLen": 0,</span><br><span class="line"> "MacAddress": "02:42:ac:11:00:02",</span><br><span class="line"> "DriverOpts": null</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></pre></td></tr></table></figure><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><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="meta">#</span><span class="bash">我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">方式一</span></span><br><span class="line">docker exec -it 容器id /bin/bash</span><br><span class="line"></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker ps</span><br><span class="line">CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES</span><br><span class="line">61aefd99735b centos "/bin/sh -c 'while t…" 16 minutes ago Up 16 minutes sharp_colden</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker exec -it 61aefd99735b /bin/bash</span><br><span class="line">[root@61aefd99735b /]# ps -ef</span><br><span class="line">UID PID PPID C STIME TTY TIME CMD</span><br><span class="line">root 1 0 0 06:03 ? 00:00:00 /bin/sh -c while true;do echo wzj;sleep 1;done</span><br><span class="line">root 1022 0 0 06:19 pts/0 00:00:00 /bin/bash</span><br><span class="line">root 1048 1 0 06:20 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1</span><br><span class="line">root 1049 1022 0 06:20 pts/0 00:00:00 ps -ef</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">方式二</span></span><br><span class="line">docker attach 容器id</span><br><span class="line">正在执行当前的带啊吗</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">区别</span></span><br><span class="line">docker exec #进入容器后开启一个新的终端,可以在里面操作</span><br><span class="line">docker attach #进入容器正在执行的新的终端,不会启动新的进程</span><br></pre></td></tr></table></figure><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><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">docker cp 容器id:容器内路径 目的主机路径</span><br><span class="line"></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker ps</span><br><span class="line">CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker images</span><br><span class="line">REPOSITORY TAG IMAGE ID CREATED SIZE</span><br><span class="line">centos latest 300e315adb2f 30 hours ago 209MB</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker run -it centos /bin/bash</span><br><span class="line">[root@227c1c4d8d5c /]# [root@iz2ze3x4is8pvdy0vb4x4kz ~]# docker ps</span><br><span class="line">CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES</span><br><span class="line">227c1c4d8d5c centos "/bin/bash" 27 seconds ago Up 27 seconds fervent_noether</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz ~]# cd /home</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz home]# ls</span><br><span class="line">admin redis www</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz home]# touch wzj.java</span><br><span class="line"><span class="meta">#</span><span class="bash">查看当前主机目录下</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz home]# ls</span><br><span class="line">admin redis www wzj.java</span><br><span class="line"><span class="meta">#</span><span class="bash">进入docker容器内部</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz home]# docker attach 227c1c4d8d5c</span><br><span class="line">[root@227c1c4d8d5c /]# cd /home</span><br><span class="line">[root@227c1c4d8d5c home]# ls</span><br><span class="line"><span class="meta">#</span><span class="bash">在容器内新建一个文件</span></span><br><span class="line">[root@227c1c4d8d5c home]# touch test.java</span><br><span class="line">[root@227c1c4d8d5c home]# ls</span><br><span class="line">test.java</span><br><span class="line">[root@227c1c4d8d5c home]# exit</span><br><span class="line">exit</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz home]# docker ps</span><br><span class="line">CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES</span><br><span class="line"><span class="meta">#</span><span class="bash">将文件拷贝出来到主机上</span></span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz home]# docker cp 227c1c4d8d5c:/home/test.java /home</span><br><span class="line">[root@iz2ze3x4is8pvdy0vb4x4kz home]# ls</span><br><span class="line">admin redis test.java www wzj.java</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">拷贝是一个手动过程,未来我们使用-v卷的技术可以实现主机/home目录和容器/home目录连通</span></span><br></pre></td></tr></table></figure><h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><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></pre></td><td class="code"><pre><span class="line">docker image #查看本地主机上所有的镜像</span><br><span class="line">docker image -q #查看本地主机上所有的镜像,只显示id</span><br><span class="line">docker search 镜像名 #搜索镜像</span><br><span class="line">docker search 镜像名 --filter=STARS=num #搜索收藏数大于镜像</span><br><span class="line">docker pull 镜像名 #下载镜像</span><br><span class="line">docker pull 镜像名:tag #下载tag版本的镜像</span><br><span class="line">docker rmi 镜像id #删除指定镜像</span><br><span class="line">docker rmi -f 镜像id 镜像id... #删除多个镜像</span><br><span class="line">docker rmi -f $(docker images -aq) #删除全部镜像</span><br><span class="line">docker run -it 镜像名 /bin/bash #使用交互方式运行,新建并启动容器</span><br><span class="line">docker ps #列出正在运行的容器</span><br><span class="line">docker ps -a #列出正在运行的容器和运行过的容器</span><br><span class="line">exit #容器停止并退出</span><br><span class="line">Ctrl+p+q #容器退出但不停止</span><br><span class="line">docker rm 容器id #删除指定容器</span><br><span class="line">docker rm -f $(docker ps -aq) #删除所有容器</span><br><span class="line">docker rm -a -q|xargs docker rm #删除所有容器</span><br><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><span class="line">docker run -d 镜像名 #后台启动容器</span><br><span class="line">docker logs -tf --tail num id #显示日志</span><br><span class="line">docker top 容器id #查看容器中的进程信息</span><br><span class="line">docker inspect 容器id #查看镜像的元数据</span><br><span class="line">docker exec -it 容器id /bin/bash #进入当前正在运行的容器</span><br><span class="line">docker attach 容器id #进入当前正在运行的容器</span><br><span class="line">docker cp 容器id:容器内路径 目的主机路径 #从容器内拷贝文件到主机上</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1 id="Docker的常用命令"><a href="#Docker的常用命令" class="headerlink" title="Docker的常用命令"></a>Docker的常用命令</h1><h2 id="帮助命令"><a href="#帮助命令" class="headerlink" title="帮助命令"></a>帮助命令</h2><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 version #显示docker的版本信息</span><br><span class="line">docker info #显示docker的系统信息,包括镜像和容器的数量</span><br><span class="line">docker --help #万能命令 帮助命令</span><br></pre></td></tr></table></figure></summary>
<category term="java" scheme="http://www.jonyonwzj.top/categories/java/"/>
<category term="Docker" scheme="http://www.jonyonwzj.top/tags/Docker/"/>
</entry>
<entry>
<title>对比Exception和Erorr,运行时异常和一般异常由什么区别</title>
<link href="http://www.jonyonwzj.top/2020/12/08/%E5%AF%B9%E6%AF%94Exception%E5%92%8CErorr%EF%BC%8C%E8%BF%90%E8%A1%8C%E6%97%B6%E5%BC%82%E5%B8%B8%E5%92%8C%E4%B8%80%E8%88%AC%E5%BC%82%E5%B8%B8%E7%94%B1%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB/"/>
<id>http://www.jonyonwzj.top/2020/12/08/%E5%AF%B9%E6%AF%94Exception%E5%92%8CErorr%EF%BC%8C%E8%BF%90%E8%A1%8C%E6%97%B6%E5%BC%82%E5%B8%B8%E5%92%8C%E4%B8%80%E8%88%AC%E5%BC%82%E5%B8%B8%E7%94%B1%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB/</id>
<published>2020-12-08T13:13:15.000Z</published>
<updated>2020-12-08T13:27:13.997Z</updated>
<content type="html"><![CDATA[<h1 id="典型回答"><a href="#典型回答" class="headerlink" title="典型回答:"></a>典型回答:</h1><ul><li><p>Exception和Error都继承了Throwable类,在java中只有Throwable类型的实例才可以被抛出(throw)或捕获(catch)</p></li><li><p>Error:非正常情况下,不太可能出现的情况,绝大多数Error都会导致程序(比如JVM自身)处于非正常的,不可恢复的情况。因为是非正常的情况,所以不需要捕获。</p></li><li><p>Exception:程序正常运行中,可以预料的意外情况,并且应该被捕获,进行相应的处理。</p></li><li><p>Exception分为可检查异常和不可检查异常</p></li></ul><ol><li>可检查异常(非RuntimeException):在源码里必须显式的进行捕获处理,这是编译检查期的一部分。</li><li>不可检查异常(RuntimeException):运行时异常,通常可以通过编码避免的逻辑错误,具体根据需求判断是否需要捕获,不在编译期做具体要求。</li></ol><a id="more"></a><p><img src="/2020/12/08/%E5%AF%B9%E6%AF%94Exception%E5%92%8CErorr%EF%BC%8C%E8%BF%90%E8%A1%8C%E6%97%B6%E5%BC%82%E5%B8%B8%E5%92%8C%E4%B8%80%E8%88%AC%E5%BC%82%E5%B8%B8%E7%94%B1%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB/1-1.png" alt="Trowable"></p><h1 id="throws和throw的区别:"><a href="#throws和throw的区别:" class="headerlink" title="throws和throw的区别:"></a>throws和throw的区别:</h1><ul><li>throw:语句抛出一个具体的异常类型,一般在代码块内部</li></ul><p><code>public static void testThrow(Integer i) {</code></p><p><code>if (i == null) {</code></p><p>`throw new NullPointerException();*//运行时异常不需要在方法上申明*``</p><p><code>}</code></p><p><code>}</code></p><ul><li>throws:声明一个方法可能产生的所有异常,不做任何处理而是将异常往上抛,谁调用我我就抛给谁</li></ul><p><code>public static void testThrows() throws NullPointerException {</code></p><p><code>Integer i = null;</code></p><p><code>System.out.println(i + 1);</code></p><p><code>}</code></p><h1 id="NoClassDefFoundError和ClassNotFoundException的区别"><a href="#NoClassDefFoundError和ClassNotFoundException的区别" class="headerlink" title="NoClassDefFoundError和ClassNotFoundException的区别"></a>NoClassDefFoundError和ClassNotFoundException的区别</h1><ul><li><p>NoClassDefFoundError:一个class在编译时存在,在运行时找不到class文件了。(javac已经成功把程序编译为字节码文件了,</p><p>当JVM进程启动,通过类加载器加载字节码文件,由JIT编译字节码指令时,在classpath下找不到相应的类进行加载)</p></li></ul><ul><li><p>ClassNotFoundException:使用类似Class.forName()方法时check Exception。(编码时编译器就能告诉你这个地方需要捕获异常,</p><p>使用Class.forName()时必须捕获或者throws这个异常)</p></li></ul><h1 id="异常处理的两个基本原则"><a href="#异常处理的两个基本原则" class="headerlink" title="异常处理的两个基本原则"></a>异常处理的两个基本原则</h1><p>1.尽量不要捕获Exception这样的通用异常,而是捕获特定异常;</p><p>2.不要生吞(swallow)异常:如果不把异常抛出来,或者输出到日志,程序可能在后续代码以不可控的方式结束,无法判断哪里出了异常</p><ul><li>很多人喜欢在catch中用e.printStackTrace打印异常信息,但在稍微复杂的系统中就会不知道异常现象输出在哪里.最好使用日志,详细的输出到日志中.</li></ul><p>StackTrace(堆栈轨迹)</p><p><code>try {</code></p><p> <code>// 业务代码</code></p><p> <code>// …</code></p><p><code>} catch (IOException e) {</code></p><p> <code>e.printStackTrace();</code></p><p><code>}</code></p><h1 id="异常处理机制"><a href="#异常处理机制" class="headerlink" title="异常处理机制"></a>异常处理机制</h1><p>我们从性能角度来审视一下 Java 的异常处理机制,这里有两个可能会相对昂贵的地方:</p><p>1.try-catch 代码段会产生额外的性能开销,或者换个角度说,它往往会影响 JVM 对代码进行优化,所以建议仅捕获有必要的代码段,尽量不要一个大的 try 包住整段的代码;与此同时,利用异常控制代码流程,也不是一个好主意,远比我们通常意义上的条件语句(if/else、switch)要低效。</p><p>2.Java 每实例化一个 Exception,都会对当时的栈进行快照,这是一个相对比较重的操作。如果发生的非常频繁,这个开销可就不能被忽略了。</p><h2 id="稍微比喻一下"><a href="#稍微比喻一下" class="headerlink" title="稍微比喻一下"></a>稍微比喻一下</h2><p>开车上山,车坏了,拿出工具箱修一修,修好了,继续上路(Exception被捕获,从异常中恢复,继续程序的运行)</p><p>车坏了,自己不知道该怎么修,打电话告诉修车行,告诉他具体是什么问题,要车行过来修(不知道是什么样的逻辑,把异常跑出去到更高的业务层来处理),打电话时要描述的具体,不然修车行不知道你有什么问题(要捕获特定的异常,不能捕获Exception特定异常)</p><p>山塌了(Error)</p>]]></content>
<summary type="html"><h1 id="典型回答"><a href="#典型回答" class="headerlink" title="典型回答:"></a>典型回答:</h1><ul>
<li><p>Exception和Error都继承了Throwable类,在java中只有Throwable类型的实例才可以被抛出(throw)或捕获(catch)</p>
</li>
<li><p>Error:非正常情况下,不太可能出现的情况,绝大多数Error都会导致程序(比如JVM自身)处于非正常的,不可恢复的情况。因为是非正常的情况,所以不需要捕获。</p>
</li>
<li><p>Exception:程序正常运行中,可以预料的意外情况,并且应该被捕获,进行相应的处理。</p>
</li>
<li><p>Exception分为可检查异常和不可检查异常</p>
</li>
</ul>
<ol>
<li>可检查异常(非RuntimeException):在源码里必须显式的进行捕获处理,这是编译检查期的一部分。</li>
<li>不可检查异常(RuntimeException):运行时异常,通常可以通过编码避免的逻辑错误,具体根据需求判断是否需要捕获,不在编译期做具体要求。</li>
</ol></summary>
<category term="java" scheme="http://www.jonyonwzj.top/categories/java/"/>
<category term="Java面试基础" scheme="http://www.jonyonwzj.top/tags/Java%E9%9D%A2%E8%AF%95%E5%9F%BA%E7%A1%80/"/>
</entry>
<entry>
<title>谈谈自己对Java平台的理解,java是解释执行,这句话正确吗?</title>
<link href="http://www.jonyonwzj.top/2020/12/07/%E8%B0%88%E8%B0%88%E8%87%AA%E5%B7%B1%E5%AF%B9Java%E5%B9%B3%E5%8F%B0%E7%9A%84%E7%90%86%E8%A7%A3-java%E6%98%AF%E8%A7%A3%E9%87%8A%E6%89%A7%E8%A1%8C%EF%BC%8C%E8%BF%99%E5%8F%A5%E8%AF%9D%E6%AD%A3%E7%A1%AE%E5%90%97%EF%BC%9F/"/>
<id>http://www.jonyonwzj.top/2020/12/07/%E8%B0%88%E8%B0%88%E8%87%AA%E5%B7%B1%E5%AF%B9Java%E5%B9%B3%E5%8F%B0%E7%9A%84%E7%90%86%E8%A7%A3-java%E6%98%AF%E8%A7%A3%E9%87%8A%E6%89%A7%E8%A1%8C%EF%BC%8C%E8%BF%99%E5%8F%A5%E8%AF%9D%E6%AD%A3%E7%A1%AE%E5%90%97%EF%BC%9F/</id>
<published>2020-12-07T11:20:25.000Z</published>
<updated>2020-12-08T13:11:37.452Z</updated>
<content type="html"><![CDATA[<h1 id="Java是解释执行吗?"><a href="#Java是解释执行吗?" class="headerlink" title="Java是解释执行吗?"></a>Java是解释执行吗?</h1><p>不正确</p><p>1.java源代码经由javac编译为.CLASS字节码文件</p><p>2..CLASS文件经由JVM类加载器解释或编译运行</p><a id="more"></a><p>(1)解释:.CLASS文件经过JVM内嵌的解析器解释执行</p><p>(2)编译:存在JIT(即时编译器)</p><p>(3)AOT编译器:java9提供的直接将所有代码编译为机器语言</p><p><img src="/2020/12/07/%E8%B0%88%E8%B0%88%E8%87%AA%E5%B7%B1%E5%AF%B9Java%E5%B9%B3%E5%8F%B0%E7%9A%84%E7%90%86%E8%A7%A3-java%E6%98%AF%E8%A7%A3%E9%87%8A%E6%89%A7%E8%A1%8C%EF%BC%8C%E8%BF%99%E5%8F%A5%E8%AF%9D%E6%AD%A3%E7%A1%AE%E5%90%97%EF%BC%9F/1-1.png" alt="关于JAVA平台"></p><h1 id="对Java平台的理解"><a href="#对Java平台的理解" class="headerlink" title="对Java平台的理解"></a>对Java平台的理解</h1><p>说到java平台就不免想到java语言的跨平台特性,java语言的跨平台特性与java虚拟机的存在有着密不可分的关系,使java可以在不同环境中运行,比如说windows,linux平台都有相应的JDK,那么他们也就都有了java运行环境。java和其他编程语言没有特别大的差别,并不是说<strong>java可以跨平台,而是说不同的平台都有着可以让java语言运行的环境</strong>,所以才有了“一次编译,到处运行”。</p><p>严格来说,跨平台的语言不止java一种,但java是<strong>较为</strong>成熟的一种。</p><p>程序从源代码到运行有三个阶段:编码—编译—运行—调试,java是在<strong>编译</strong>阶段体现了跨平台的特性。</p><p>编译过程:</p><p>1.第一次编译:javac编译器将java源代码转化为.CLASS字节码文件</p><p>(.CLASS文件就是可以到处运行的文件)</p><p>2.第二次编译:java字节码会被转换成目标机器代码,由JVM类加载器加载字节码文件,通过解释器逐行解释执行,转换为最终的机器码</p><p>“到处运行”的关键就是JVM,因为在第二次编译中JVM起关键作用。在可以运行java虚拟机的地方都内含着一个JVM操作系统,从而使用java提供了各种不同平台上的虚拟机制。</p><p>强调:java不是编译机制,而是解释机制。java字节码的设计充分考虑了JIT这一即时编译方式,可以将字节码转换成高性能的本地机器码,这同样是虚拟机的一个构成部分。</p><p>第二次编译由JVM类加载器加载字节码文件这种方式执行速度较慢,有些方法和代码块是高频率调用的(热点代码)。所以引进JIT技术(运行时编译),<strong>提前将这些字节码文件编译成本地机器码,类似于缓存技术,运行时再遇到这类代码可直接执行,而不是先解释后执行。</strong></p><p><img src="/2020/12/07/%E8%B0%88%E8%B0%88%E8%87%AA%E5%B7%B1%E5%AF%B9Java%E5%B9%B3%E5%8F%B0%E7%9A%84%E7%90%86%E8%A7%A3-java%E6%98%AF%E8%A7%A3%E9%87%8A%E6%89%A7%E8%A1%8C%EF%BC%8C%E8%BF%99%E5%8F%A5%E8%AF%9D%E6%AD%A3%E7%A1%AE%E5%90%97%EF%BC%9F/1-2.png" alt="对JAVA平台的理解"></p>]]></content>
<summary type="html"><h1 id="Java是解释执行吗?"><a href="#Java是解释执行吗?" class="headerlink" title="Java是解释执行吗?"></a>Java是解释执行吗?</h1><p>不正确</p>
<p>1.java源代码经由javac编译为.CLASS字节码文件</p>
<p>2..CLASS文件经由JVM类加载器解释或编译运行</p></summary>
<category term="java" scheme="http://www.jonyonwzj.top/categories/java/"/>
<category term="Java面试基础" scheme="http://www.jonyonwzj.top/tags/Java%E9%9D%A2%E8%AF%95%E5%9F%BA%E7%A1%80/"/>
</entry>
<entry>
<title>Hello World</title>
<link href="http://www.jonyonwzj.top/2020/12/05/hello-world/"/>
<id>http://www.jonyonwzj.top/2020/12/05/hello-world/</id>
<published>2020-12-05T09:57:22.844Z</published>
<updated>2020-12-08T05:42:38.934Z</updated>
<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><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br><span class="line">hexo new <span class="string">"标题"</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><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br><span class="line">hexo s</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><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br><span class="line">hexo g</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><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br><span class="line">hexo d</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>]]></content>
<summary type="html"><center>基本操作</center></summary>
</entry>
</feed>