-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
453 lines (240 loc) · 200 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
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>答案</title>
<subtitle>答案的个人博客</subtitle>
<link href="http://www.aquestian.cn/atom.xml" rel="self"/>
<link href="http://www.aquestian.cn/"/>
<updated>2024-01-29T16:00:00.000Z</updated>
<id>http://www.aquestian.cn/</id>
<author>
<name>Volantis Team</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>我的程序人生——第六年</title>
<link href="http://www.aquestian.cn/life/Life-Six-Year/"/>
<id>http://www.aquestian.cn/life/Life-Six-Year/</id>
<published>2024-01-29T16:00:00.000Z</published>
<updated>2024-01-29T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><div class="story post-story"><h2 id="程序人生第六年"><a href="#程序人生第六年" class="headerlink" title="程序人生第六年"></a>程序人生第六年</h2><p>承蒙公司信任,今年我开始独立负责项目了,也挂上了项目执行经理的名头。</p><p>三月初,我把项目执行计划做完在公司开了项目启动会,又做了详细设计报告交付甲方。这些东西虽然不是头回做了,但还是反反复复改了好几版,总算是应付过去了。三月中旬,我到了现场开始实施。第一件难事,甲方找的设计院的施工蓝图半个月都没有交稿,反而甩锅给我们交付的现场实际设计图标点位置不明确,没办法我只能找甲方项目交接人,也是信息中心部门的甄总组织一下会议,确定一下双方责任以及图纸交付时间。大家都明白的,求人办事,就得请人吃饭,这也是我头一次在商务上请人吃饭,两人600多,其中300多是额外点餐打包带回家的,不过花钱真能办事。期间还发生一件有意思的事儿,甲方组织了一个故障分析会,眼跟前了才通知我会议地点,甄总迟到了,结果会后特地给我来电话给我臭骂一顿说我没通知他害他在领导面前迟到……</p><p>4月初,图纸总算是出来了,第二个难事也来了,搬货!我们的货是寄给甲方项目交接人甄总的。其实呢,是施工队顺手的事,但甄总要求必须得有施工队和使用部门签一份验收单,目的是为了责任划分,此话一出,施工队和使用部门都退避三舍,谁都不想担责,设备损坏作为项目负责人是可以对责任人进行索赔的。就这样拖了一周,施工队天天催我什么时候可以拉货,但使用部门又迟迟不肯签字。项目陷入停滞,我作为负责人也只能干着急,最后我们领导给我分析说现在的矛盾点是甲方企业内部矛盾,他说搬货咱就去人配合,不搬就拖着,看谁着急,但要确定一下搬货日期,并通知他们项目实施计划的实施节点,延期跟咱们没关系。于是,我悟了,再和甄总确认好搬货日期后我就通知施工队准时到仓库搬货。釜底抽薪呗,搬货卡车到院里停着,没人签字就等着,施工队也发话了,就来这一次后续自己找人搬货去。终于等了一个晌午,使用部门领导珊珊来迟,这收货单签了字!这段时间我跟甄总关系还不错,我请他吃饭送他汾酒,请他打羽毛球,给他报销油费,甚至请他儿子看电影,最过分的是我花钱租的车转头被他借跑了,真是无利不起早,苍蝇肉再小也不放过!反过来我跟他打羽毛球手机还搁旁边放着,不知道被哪个臭小子把后壳敲碎了。说到这我又想起一件特别无语的事儿,他儿子在球馆打球看到有个球拍没人管,臭小子直接顺回家了,这臭小子还把他同学叫过来一起打球,他跟他爹一队,他两同学一队,我特么出钱坐场下喊加油!真是难伺候,只能用狗篮子来形容我,我快卑微到尘埃里了,得跟他处好关系他才能帮我推进项目呀!整个4月好就好在,两个点中的港口点开始施工,虽然施工磨磨唧唧,10的天的活楞干到月底,其中我也主动包揽一部分接线的活儿。</p><p>我明白广东人为啥发展好了,真他么扣啊!我多说几个事儿就明白了,比如说还是这个甄总,他请他们单位部门吃饭,美其名曰是给我们公司铺路,打通关系了后续可以拿项目,我就在当地却不带上我,吃完了给我丢过来总计3600的发票!再比如,我和仪控部的开会,蔡总就说了你们五岳和保运的也是时候团建了哈,完事他就张罗把仪控的人也叫上也来舔着个大脸蹭我们团建聚餐!再比如,保运的一个臭小子吴工,他可是我的下属,某天中午我寻思一块吃个午饭,随便吃口,这臭小子开车居然把我带到了西餐厅,大言不惭的说我这段时间估计吃不惯,吃饭贵就不说啥了,臭小子居然还点咖啡喝。我中途问他这地方适合带你对象来啊带我算怎么个事,臭小子也是毫不避讳说他是经常带着对象来,所以感觉味道不错你肯定能接受……我没打他真是证明我素质高,只能硬着头皮请呗!还有个混蛋专门给我打电话说我说话口气有点大,我寻思我天天好爱好喝供着你们哪得罪人了?没想这家伙说我嘴里有异味让我买他的调理中药茶包,我说我天天刷牙不需要,下次再见我口气太重我躲你远点就行了!我在广东半年啊,三人请回过我,蔡班长,罗工,杨工,真没法表达这种操蛋玩意,逮住机会就往死里耗羊毛!</p><p>到了5月份,第三件难事,由于4月份石化企业出现安全事故,突然要求所有施工作业暂停先进行安全培训,这就导致我们单位同事到场之后迟迟不能进入厂区干活儿,整整半个月,只干了些零碎的小事,反而时间全耗费到培训跑手续签字上!第四件难事,因为一个点已经施工完成了,可网络ip甄总却一直拖着不给我,为此我和计量部门负责人陈总打了一个配合,在项目大群里陈总问工期进度,我回答网络ip甄总还没申请下来,陈总于是直接艾特甄总抓紧落实!虽然这样确实起到了催促效果,但把甄总惹恼了!直接给发消息炮轰我——ip没下来不能私信跟我说吗?我说我已经在钉钉私信给您发了,他说我没看到消息……但打羽毛球定场地的消息他是一条没错过!整个五月份是彻底陷入停滞了,但期间公司冷哥和任总给我上了一课,项目为啥停滞?除了安全培训,甄总为啥一直使绊子?项目背景得了解清楚,另外关键客户图啥?要么图钱,要么图权,要么就是啥也不图怕担责。了解过后,确实是我们单位回款没回甄总手里,我让我们领导也催公司抓紧给人汇款!</p><p>6月份,第五件难事,因为前期各种事情,导致现在就得压缩工期,就得加班加点的干,我也是服了我们公司柜机设计,接线、拆卸超级麻烦,设备也是三天两头烧个零件,而且还有外部车辆借磅业务。我一个人这么长时间也开始情绪崩溃,中间我一度想放弃了。好在经过不懈努力,6月底总算是投入使用了。</p><p>7月我终于回去休息一个月,8月又来甲方这里办上线手续。本来半个月,好死不死,百年难遇,地磅被雷击了,只能被强留着配合修复,最讽刺的是,我六月份因为没按规定着装考核我们公司1000,而反过来因为不可抗因素导致地磅损坏,我们加班加点维修才奖励200块。</p><p>9月份回了天津之后,是一个项目空窗期,狠狠歇了一把,期间我们做了项目总结会,会上我也深刻反思了自己的问题。一直到年底,我才跟着我领导但云南开启另外一个项目。这个项目的原型设计,详细设计,数据库设计,都出自我手(领导也指点迷津了),也确实是具备一定的项目管理能力了,我自己都明显感知自己进步了,这值得骄傲,但这份骄傲或者说自负,也导致了我跟领导在言语上的冲突。</p><p>云南这个项目,唯一问题就是工期紧只有一个月,到了现场时间进一步压缩为二十天,我们一行三人,都在高强度的工作,发生了好几回争吵。因为公司要实行什么积分制,每个人工资要从中划两千出来,一分10块,如果这个月积分为0,那么这两千没了,超过200分则多给。我强烈反对,话敢话吵架,直接把我从云南现场直接撤回天津了。</p><p>一直以来我挺感谢我们公司的,公司也一直很信任我,但这次我跟领导吵架,终归是希望我个人和公司之间有一个良性平衡的关系,达成一种默契,好的时候多给些,不好的时候公司也需要尽力拖底。我付出我的幸苦劳作,公司兑现给我的相应报酬。同享福,大家一起赚钱!不共患难,不代表我不与公司度过难光关,但也不能是公司反过来绑架我,要求我付出劳动的同时还要求我经济利益作出让步!</p><p>某天下班拼车回宿舍,后座的两个刚毕业的男生讨论着工资的事儿,跟他们年纪相仿的同事做开发一个月个税缴纳三百,而他们搞测试想找领导涨工资却始终犹豫不决,我很想扭头告诉他们方向选错了,在天津测试岗是有瓶颈的。经过这几年的成长,我的方向是正确的,从开发中慢慢转变为业务,这路我觉得是越走越远宽了。我中途面试过别的公司,面试官问了我一个问题直接让我陷入了沉思——你做生产系统这么久了,突然换个领域,这种业务上和思维上的变化,你怎么快速切换或者适应!是的,从头探索一个行业,了解它的模式也是需要长时间吸纳的。因此,28岁的我临近年关,又站在十字路口,面临抉择,但开发转业务这条路,应该坚定不移!</p></div>]]></content>
<summary type="html">转型。</summary>
<category term="程序人生" scheme="http://www.aquestian.cn/categories/%E7%A8%8B%E5%BA%8F%E4%BA%BA%E7%94%9F/"/>
<category term="程序人生" scheme="http://www.aquestian.cn/tags/%E7%A8%8B%E5%BA%8F%E4%BA%BA%E7%94%9F/"/>
</entry>
<entry>
<title>对于Oracle,MySQL,SQL Server重复数据去重,只保留一条数据。</title>
<link href="http://www.aquestian.cn/blogs/SQL-De-Duplicate/"/>
<id>http://www.aquestian.cn/blogs/SQL-De-Duplicate/</id>
<published>2023-09-18T16:00:00.000Z</published>
<updated>2023-09-18T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><div class="story post-story"><h2 id="问题前提"><a href="#问题前提" class="headerlink" title="问题前提"></a>问题前提</h2><p>之前做过数据入湖,建表的时候匆忙,没有做主键,导致入湖出现了重复数据。举个例子:</p><table><thead><tr><th>id</th><th>name</th><th>age</th><th>sex</th></tr></thead><tbody><tr><td>1</td><td>张三</td><td>23</td><td>男</td></tr><tr><td>1</td><td>张三</td><td>23</td><td>男</td></tr><tr><td>1</td><td>张三</td><td>23</td><td>男</td></tr><tr><td>2</td><td>李四</td><td>23</td><td>男</td></tr></tbody></table><p>存在了如上两条及两条数据,目的是要去除重复数据,只保留一条,从而设置id为主键。</p></div><div class="story post-story"><h2 id="Oracle"><a href="#Oracle" class="headerlink" title="Oracle"></a>Oracle</h2><p>Oracle如果存在重复数据,id设置主键时,会有02437报错。</p><p>对于Oracle去处重复数据是最简单的,每行自带rowid。</p><figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">DELETE</span> </span><br><span class="line"><span class="keyword">FROM</span></span><br><span class="line"> <span class="keyword">user</span> </span><br><span class="line"><span class="keyword">WHERE</span></span><br><span class="line"> id <span class="keyword">IN</span> ( <span class="keyword">SELECT</span> id <span class="keyword">FROM</span> <span class="keyword">user</span> <span class="keyword">GROUP</span> <span class="keyword">BY</span> id <span class="keyword">HAVING</span> <span class="built_in">count</span>( id ) <span class="operator">></span> <span class="number">1</span> ) </span><br><span class="line"> <span class="keyword">AND</span> rowid <span class="keyword">NOT</span> <span class="keyword">IN</span> (</span><br><span class="line"> <span class="keyword">SELECT</span></span><br><span class="line"> <span class="built_in">min</span>( rowid ) </span><br><span class="line"> <span class="keyword">FROM</span></span><br><span class="line"> <span class="keyword">user</span> </span><br><span class="line"> <span class="keyword">GROUP</span> <span class="keyword">BY</span></span><br><span class="line"> id </span><br><span class="line"><span class="keyword">HAVING</span></span><br><span class="line"> <span class="built_in">count</span>( id )<span class="operator">></span> <span class="number">1</span>)</span><br></pre></td></tr></table></figure><p>执行如上语句即可删除重复数据。</p><p>因为本地没有Oracle数据库,就不做演示了。</p></div><div class="story post-story"><h2 id="MySQL"><a href="#MySQL" class="headerlink" title="MySQL"></a>MySQL</h2><p>MySQL没有rowid,那么MySQL解决办法只有一种,把A表的数据去重添加到B表中,在B表中设置id为主键,最后把B表重命名为A表。</p><figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> user1 ( <span class="keyword">SELECT</span> <span class="keyword">DISTINCT</span> <span class="operator">*</span> <span class="keyword">FROM</span> <span class="keyword">user</span> );</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/e18271935315408983aa2679f0f776c2.png" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/e18271935315408983aa2679f0f776c2.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>暂不清楚,数据量大的情况下会不会出现崩溃,可以通过limit截取。</p><p>如果不确定A表的数据是否全部添加到B表,可以添加完成后,执行</p><figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">DELETE</span> <span class="keyword">FROM</span> <span class="keyword">user</span> <span class="keyword">WHERE</span> user.id <span class="keyword">IN</span> (<span class="keyword">SELECT</span> user1.id <span class="keyword">FROM</span> user1)</span><br></pre></td></tr></table></figure><p>这种方式当然也适用于其他数据库。<br></br></p><p>当然MySQL还有另外一种方式,就是新增一个字段为自增字段且不为null,让其自动填充,类似充当Orcal中的rowid。</p><p><img src="https://img-blog.csdnimg.cn/3173a40ad92f4af5ae9732eaf6d25aac.png" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/3173a40ad92f4af5ae9732eaf6d25aac.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>填充完成后。</p><figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">DELETE</span> </span><br><span class="line"><span class="keyword">FROM</span></span><br><span class="line"> <span class="keyword">user</span> </span><br><span class="line"><span class="keyword">WHERE</span></span><br><span class="line"> user.rowid <span class="keyword">NOT</span> <span class="keyword">IN</span> (</span><br><span class="line"> <span class="keyword">SELECT</span></span><br><span class="line"> dt.minid </span><br><span class="line"> <span class="keyword">FROM</span></span><br><span class="line"> ( <span class="keyword">SELECT</span> <span class="built_in">MIN</span>( user.rowid ) <span class="keyword">AS</span> minid <span class="keyword">FROM</span> <span class="keyword">user</span> <span class="keyword">GROUP</span> <span class="keyword">BY</span> name ) dt </span><br><span class="line"> )</span><br></pre></td></tr></table></figure><p>有多种方式,<a href="https://blog.csdn.net/n950814abc/article/details/82284838" target="_blank" rel="noopener external nofollow noreferrer">可参考【mysql】mysql删除重复记录并且只保留一条_mysql删除完全重复数据只保留一条_千g的博客-CSDN博客</a></p></div><div class="story post-story"><h2 id="SQL-Server"><a href="#SQL-Server" class="headerlink" title="SQL Server"></a>SQL Server</h2><p>SQL Server 和MySQL逻辑是一样的,但语法上稍有变化</p><figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="keyword">DISTINCT</span> <span class="operator">*</span> <span class="keyword">INTO</span> [dbo].[user1] <span class="keyword">FROM</span> [dbo].[<span class="keyword">user</span>]</span><br></pre></td></tr></table></figure><p>SQL Server是不需要创建user1表的,会自动创建,数据导入到新表后再设置主键即可。<br></br></p><p>另外一种设置自增rowid,执行:</p><figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">DELETE</span> </span><br><span class="line"><span class="keyword">FROM</span></span><br><span class="line"> [dbo].[<span class="keyword">user</span>] </span><br><span class="line"><span class="keyword">WHERE</span></span><br><span class="line"> [dbo].[<span class="keyword">user</span>].rowid <span class="keyword">NOT</span> <span class="keyword">IN</span> (</span><br><span class="line"> <span class="keyword">SELECT</span></span><br><span class="line"> dt.minid </span><br><span class="line"> <span class="keyword">FROM</span></span><br><span class="line"> ( <span class="keyword">SELECT</span> <span class="built_in">MIN</span>( [dbo].[<span class="keyword">user</span>].rowid ) <span class="keyword">AS</span> minid <span class="keyword">FROM</span> [dbo].[<span class="keyword">user</span>] <span class="keyword">GROUP</span> <span class="keyword">BY</span> name ) dt </span><br><span class="line"> )</span><br></pre></td></tr></table></figure></div><div class="story post-story"><h2 id="后续"><a href="#后续" class="headerlink" title="后续"></a>后续</h2><p>后续研究其他数据库,mongo等其他用到的数据库再做更新。</p></div>]]></content>
<summary type="html">之前做过数据入湖,建表的时候匆忙,没有做主键,导致入湖出现了重复数据,所以在不同的数据库中去除重复数据只保留一条数据。</summary>
<category term="数据处理" scheme="http://www.aquestian.cn/categories/%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/"/>
<category term="MySQL" scheme="http://www.aquestian.cn/tags/mysql/"/>
<category term="Oracle" scheme="http://www.aquestian.cn/tags/oracle/"/>
<category term="SQL Server" scheme="http://www.aquestian.cn/tags/sql-server/"/>
</entry>
<entry>
<title>springboot出入库管理系统源码分享</title>
<link href="http://www.aquestian.cn/code/Code-Wms/"/>
<id>http://www.aquestian.cn/code/Code-Wms/</id>
<published>2023-09-15T16:00:00.000Z</published>
<updated>2023-09-15T16:00:00.000Z</updated>
<content type="html"><![CDATA[<div class="story post-story"><h2 id="项目描述"><a href="#项目描述" class="headerlink" title="项目描述"></a>项目描述</h2><p>springboot出入库管理系统源码分享,前端使用vue-element,后端使用springboot+mybatis-plus+redis+JWT。</p></div><div class="story post-story"><h2 id="运行环境"><a href="#运行环境" class="headerlink" title="运行环境"></a>运行环境</h2><p>jdk8+tomcat8+mysql5.7+IntelliJ IDEA+maven</p></div><div class="story post-story"><h2 id="项目技术"><a href="#项目技术" class="headerlink" title="项目技术"></a>项目技术</h2><p>spring boot+mybatis-plus+vue-element+redis+JWT</p></div><div class="story post-story"><h2 id="项目截图"><a href="#项目截图" class="headerlink" title="项目截图"></a>项目截图</h2><p><img src="https://double.aquestian.cn/code/inbolg/wms/%E9%A1%B9%E7%9B%AE%E6%88%AA%E5%9B%BE.png" class="lazyload" data-srcset="https://double.aquestian.cn/code/inbolg/wms/%E9%A1%B9%E7%9B%AE%E6%88%AA%E5%9B%BE.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="https://img-blog.csdnimg.cn/2020042713250456.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" /></p></div><div class="story post-story"><h2 id="运行截图"><a href="#运行截图" class="headerlink" title="运行截图"></a>运行截图</h2><p>左侧菜单数据库可配置</p><p>首页</p><div galleryFlag itemscope itemtype="http://schema.org/ImageGallery" class="gallery " data-group='default'><div class='fancybox'><a class='fancybox' pjax-fancybox itemscope itemtype="http://schema.org/ImageObject" itemprop="url" href='https://double.aquestian.cn/code/inbolg/wms/%E9%A6%96%E9%A1%B5.png' data-fancybox='default' data-caption='首页'><img fancybox itemprop="contentUrl" src="https://double.aquestian.cn/code/inbolg/wms/%E9%A6%96%E9%A1%B5.png" class="lazyload" data-srcset="https://double.aquestian.cn/code/inbolg/wms/%E9%A6%96%E9%A1%B5.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="首页"></a><span class='image-caption'>首页</span></div></div><p>管理员管理</p><div galleryFlag itemscope itemtype="http://schema.org/ImageGallery" class="gallery " data-group='default'><div class='fancybox'><a class='fancybox' pjax-fancybox itemscope itemtype="http://schema.org/ImageObject" itemprop="url" href='https://double.aquestian.cn/code/inbolg/wms/%E7%AE%A1%E7%90%86%E5%91%98%E7%AE%A1%E7%90%86.png' data-fancybox='default' data-caption='管理员管理'><img fancybox itemprop="contentUrl" src="https://double.aquestian.cn/code/inbolg/wms/%E7%AE%A1%E7%90%86%E5%91%98%E7%AE%A1%E7%90%86.png" class="lazyload" data-srcset="https://double.aquestian.cn/code/inbolg/wms/%E7%AE%A1%E7%90%86%E5%91%98%E7%AE%A1%E7%90%86.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="管理员管理"></a><span class='image-caption'>管理员管理</span></div></div><p>用户管理</p><p>只有出库,入库权限</p><div galleryFlag itemscope itemtype="http://schema.org/ImageGallery" class="gallery " data-group='default'><div class='fancybox'><a class='fancybox' pjax-fancybox itemscope itemtype="http://schema.org/ImageObject" itemprop="url" href='https://double.aquestian.cn/code/inbolg/wms/%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86.png' data-fancybox='default' data-caption='用户管理'><img fancybox itemprop="contentUrl" src="https://double.aquestian.cn/code/inbolg/wms/%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86.png" class="lazyload" data-srcset="https://double.aquestian.cn/code/inbolg/wms/%E7%94%A8%E6%88%B7%E7%AE%A1%E7%90%86.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="用户管理"></a><span class='image-caption'>用户管理</span></div></div><p>仓库管理</p><div galleryFlag itemscope itemtype="http://schema.org/ImageGallery" class="gallery " data-group='default'><div class='fancybox'><a class='fancybox' pjax-fancybox itemscope itemtype="http://schema.org/ImageObject" itemprop="url" href='https://double.aquestian.cn/code/inbolg/wms/%E4%BB%93%E5%BA%93%E7%AE%A1%E7%90%86.png' data-fancybox='default' data-caption='仓库管理'><img fancybox itemprop="contentUrl" src="https://double.aquestian.cn/code/inbolg/wms/%E4%BB%93%E5%BA%93%E7%AE%A1%E7%90%86.png" class="lazyload" data-srcset="https://double.aquestian.cn/code/inbolg/wms/%E4%BB%93%E5%BA%93%E7%AE%A1%E7%90%86.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="仓库管理"></a><span class='image-caption'>仓库管理</span></div></div><p>类别管理</p><div galleryFlag itemscope itemtype="http://schema.org/ImageGallery" class="gallery " data-group='default'><div class='fancybox'><a class='fancybox' pjax-fancybox itemscope itemtype="http://schema.org/ImageObject" itemprop="url" href='https://double.aquestian.cn/code/inbolg/wms/%E7%B1%BB%E5%88%AB%E7%AE%A1%E7%90%86.png' data-fancybox='default' data-caption='类别管理'><img fancybox itemprop="contentUrl" src="https://double.aquestian.cn/code/inbolg/wms/%E7%B1%BB%E5%88%AB%E7%AE%A1%E7%90%86.png" class="lazyload" data-srcset="https://double.aquestian.cn/code/inbolg/wms/%E7%B1%BB%E5%88%AB%E7%AE%A1%E7%90%86.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="类别管理"></a><span class='image-caption'>类别管理</span></div></div><p>物品管理</p><p>出入库操作</p><div galleryFlag itemscope itemtype="http://schema.org/ImageGallery" class="gallery " data-group='default'><div class='fancybox'><a class='fancybox' pjax-fancybox itemscope itemtype="http://schema.org/ImageObject" itemprop="url" href='https://double.aquestian.cn/code/inbolg/wms/%E7%89%A9%E5%93%81%E7%AE%A1%E7%90%86.png' data-fancybox='default' data-caption='物品管理'><img fancybox itemprop="contentUrl" src="https://double.aquestian.cn/code/inbolg/wms/%E7%89%A9%E5%93%81%E7%AE%A1%E7%90%86.png" class="lazyload" data-srcset="https://double.aquestian.cn/code/inbolg/wms/%E7%89%A9%E5%93%81%E7%AE%A1%E7%90%86.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="物品管理"></a><span class='image-caption'>物品管理</span></div></div><p>记录管理</p><div galleryFlag itemscope itemtype="http://schema.org/ImageGallery" class="gallery " data-group='default'><div class='fancybox'><a class='fancybox' pjax-fancybox itemscope itemtype="http://schema.org/ImageObject" itemprop="url" href='https://double.aquestian.cn/code/inbolg/wms/%E5%87%BA%E5%85%A5%E5%BA%93%E8%AF%A6%E6%83%85.png' data-fancybox='default' data-caption='记录管理'><img fancybox itemprop="contentUrl" src="https://double.aquestian.cn/code/inbolg/wms/%E5%87%BA%E5%85%A5%E5%BA%93%E8%AF%A6%E6%83%85.png" class="lazyload" data-srcset="https://double.aquestian.cn/code/inbolg/wms/%E5%87%BA%E5%85%A5%E5%BA%93%E8%AF%A6%E6%83%85.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="记录管理"></a><span class='image-caption'>记录管理</span></div></div></div><div class="story post-story"><h2 id="线上演示地址"><a href="#线上演示地址" class="headerlink" title="线上演示地址"></a>线上演示地址</h2><p><a href="http://43.138.127.183/#" target="_blank" rel="noopener external nofollow noreferrer">http://43.138.127.183/#</a></p></div><div class="story post-story"><h2 id="其它说明"><a href="#其它说明" class="headerlink" title="其它说明"></a>其它说明</h2><p>白嫖党 请绕道</p></div>]]></content>
<summary type="html">springboot出入库管理系统源码分享,前端使用vue-element,后端使用springboot+mybatis-plus。</summary>
<category term="源码分享" scheme="http://www.aquestian.cn/categories/%E6%BA%90%E7%A0%81%E5%88%86%E4%BA%AB/"/>
<category term="源码分享" scheme="http://www.aquestian.cn/tags/%E6%BA%90%E7%A0%81%E5%88%86%E4%BA%AB/"/>
</entry>
<entry>
<title>springboot医疗管理系统系统</title>
<link href="http://www.aquestian.cn/code/Code-Hospital/"/>
<id>http://www.aquestian.cn/code/Code-Hospital/</id>
<published>2023-09-12T16:00:00.000Z</published>
<updated>2020-09-12T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><div class="story post-story"><h2 id="写在前面"><a href="#写在前面" class="headerlink" title="写在前面"></a>写在前面</h2><p>本项目是基于Spring Boot 2.x 开发的医疗管理系统系统。本项目也可以当作毕业设计,期末课程作业等,也可以当作学习、进阶Spring Boot 的资料。</p></div><div class="story post-story"><h2 id="功能描述"><a href="#功能描述" class="headerlink" title="功能描述"></a>功能描述</h2><p>本项目主要包含以下功能模块</p><ul><li>系统管理</li><li>医生管理</li><li>患者管理</li><li>药品管理</li><li>管理员管理</li><li>预约管理</li><li>病史管理</li><li>住院信息管理</li><li>登录/注销功能</li><li>...</li></ul></div><div class="story post-story"><h2 id="开发环境(运行环境)"><a href="#开发环境(运行环境)" class="headerlink" title="开发环境(运行环境)"></a>开发环境(运行环境)</h2><ul><li>系统环境:Windows 11</li><li>开发工具:IntelliJ IDEA 2023.1.2</li><li>Java版本:JDK 1.8</li><li>Mysql版本:8.0</li><li>Maven版本:3.6.3</li></ul></div><div class="story post-story"><h2 id="项目技术栈"><a href="#项目技术栈" class="headerlink" title="项目技术栈"></a>项目技术栈</h2><ul><li>Spring Boot 2.1.4.RELEASE</li><li>Mybatis</li><li>Maven 3.X</li><li>Mysql</li><li>layui</li><li>Jquery</li><li>freemarker</li><li>...</li></ul></div><div class="story post-story"><h2 id="登录地址"><a href="#登录地址" class="headerlink" title="登录地址"></a>登录地址</h2><p>项目访问路径:<a href="http://localhost:8088/" target="_blank" rel="noopener external nofollow noreferrer">http://localhost:8088</a></p><p>管理员 用户名 / 密码</p><p>admin1/ 123456</p></div><div class="story post-story"><h2 id="项目截图"><a href="#项目截图" class="headerlink" title="项目截图"></a>项目截图</h2><p><img src="https://s3.bmp.ovh/imgs/2023/09/15/f4a69961f2bf268c.png" class="lazyload" data-srcset="https://s3.bmp.ovh/imgs/2023/09/15/f4a69961f2bf268c.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="登录页面"></p><p><img src="https://s3.bmp.ovh/imgs/2023/09/15/031f98697024e87f.png" class="lazyload" data-srcset="https://s3.bmp.ovh/imgs/2023/09/15/031f98697024e87f.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="index页面"></p><p><img src="https://s3.bmp.ovh/imgs/2023/09/15/60bf6866e9a9f311.png" class="lazyload" data-srcset="https://s3.bmp.ovh/imgs/2023/09/15/60bf6866e9a9f311.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="dr页面"></p><p><img src="https://s3.bmp.ovh/imgs/2023/09/15/0de5e0df9d041d47.png" class="lazyload" data-srcset="https://s3.bmp.ovh/imgs/2023/09/15/0de5e0df9d041d47.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="住院"></p><p><img src="https://s3.bmp.ovh/imgs/2023/09/15/4e54e21d478f11d5.png" class="lazyload" data-srcset="https://s3.bmp.ovh/imgs/2023/09/15/4e54e21d478f11d5.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="管理员"></p><p><img src="https://s3.bmp.ovh/imgs/2023/09/15/3ba030cb6535b527.png" class="lazyload" data-srcset="https://s3.bmp.ovh/imgs/2023/09/15/3ba030cb6535b527.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="预约"></p></div><div class="story post-story"><h2 id="项目演示视频"><a href="#项目演示视频" class="headerlink" title="项目演示视频"></a>项目演示视频</h2><p>链接: <a href="https://pan.baidu.com/s/1w0wkTAupDs4_qi0Wn3zRag" target="_blank" rel="noopener external nofollow noreferrer">https://pan.baidu.com/s/1w0wkTAupDs4_qi0Wn3zRag</a></p><p>提取码: mhib</p></div><div class="story post-story"><h2 id="联系我们"><a href="#联系我们" class="headerlink" title="联系我们"></a>联系我们</h2><p>如有需要源码可以通过QQ 搜索:289373410联系我! 请备注:医疗管理系统</p></div><div class="story post-story"><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><p>获取代码之后,使用IDEA导入本项目前,请确保你本地环境是已经含有代码所需要运行环境的条件了。</p><p>接着找到对应的sql文件,将其导入到你本地的数据库即可。</p><p>最后修改项目中配置文件中的数据库对应的信息,确认修改完毕,找到对应的Application直接运行吧!</p></div><div class="story post-story"><h2 id="其它说明"><a href="#其它说明" class="headerlink" title="其它说明"></a>其它说明</h2><p>白嫖怪,伸手党 请绕道!!!</p><hr><p>The end.</p></div>]]></content>
<summary type="html">pringboot医疗管理系统系统源码分享,前端使用layui,后端使用springboot+Mybatis。</summary>
<category term="源码分享" scheme="http://www.aquestian.cn/categories/%E6%BA%90%E7%A0%81%E5%88%86%E4%BA%AB/"/>
<category term="源码分享" scheme="http://www.aquestian.cn/tags/%E6%BA%90%E7%A0%81%E5%88%86%E4%BA%AB/"/>
</entry>
<entry>
<title>利用kettle实现数据库之间的数据同步</title>
<link href="http://www.aquestian.cn/blogs/Kettle-Data-Transmission/"/>
<id>http://www.aquestian.cn/blogs/Kettle-Data-Transmission/</id>
<published>2023-05-02T16:00:00.000Z</published>
<updated>2023-05-02T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><div class="story post-story"><h2 id="利用kettle实现数据库之间的数据同步"><a href="#利用kettle实现数据库之间的数据同步" class="headerlink" title="利用kettle实现数据库之间的数据同步"></a>利用kettle实现数据库之间的数据同步</h2><p>如果你需要做不同数据库之间的数据迁移或者抽取部分数据到另一个数据库,并实现定时数据同步(非实时),那么kettle是一个很好的选择。</p><p>以mysql数据库—> oracle数据库的定时同步作为案例:</p></div><div class="story post-story"><h2 id="工具安装和环境准备"><a href="#工具安装和环境准备" class="headerlink" title="工具安装和环境准备"></a>工具安装和环境准备</h2><p>安装mysql数据库和oracle数据库<br>下载pdi-ce-8.2.0.0-342<br>打开目录下data-integration\Spoon.bat ,即可打开keetle软件</p></div><div class="story post-story"><h2 id="清楚数据抽取需求"><a href="#清楚数据抽取需求" class="headerlink" title="清楚数据抽取需求"></a>清楚数据抽取需求</h2><p>抽取数据的mysql数据库表和oracle的表一致,单表对单表抽取<br>根据oracle需求,在mysql写sql,再抽取相应数据到Oracle。<br>是否定时。<br>全量抽取 or 增量抽取。<br>案例需求:根据需求在mysql写sql,增量抽取其数据到Oracle,实现按天定时抽取。</p><blockquote><p>备注:(按月增量),查询当前月份为全量抽取,非当前月份数据增量抽取。例如:今天是10月15日,到月底之前每天全量抽取当月数据,每天更新10月份的数据;11月1号开始,10月份数据不动,只是每天全量抽取更新11月份的数据。<br>所以当月是全量抽取,但增量是基于前一个月的基础上。</p></blockquote><p>首先在mysql数据库 根据需求编写sql。</p></div><div class="story post-story"><h2 id="新建转换"><a href="#新建转换" class="headerlink" title="新建转换"></a>新建转换</h2><h3 id="主对象树-转换-右键新建"><a href="#主对象树-转换-右键新建" class="headerlink" title="主对象树-转换-右键新建"></a>主对象树-转换-右键新建</h3><img src="https://img-blog.csdnimg.cn/b96c0c3cb32a4a2ebc2828d81389f462.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_15,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/b96c0c3cb32a4a2ebc2828d81389f462.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_15,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" /><h3 id="主对象树-DB连接-右键新建"><a href="#主对象树-DB连接-右键新建" class="headerlink" title="主对象树-DB连接-右键新建"></a>主对象树-DB连接-右键新建</h3><img src="https://img-blog.csdnimg.cn/30ba2b272f6b48c687132353e30edc5e.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/30ba2b272f6b48c687132353e30edc5e.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/><h3 id="连接oracle数据库"><a href="#连接oracle数据库" class="headerlink" title="连接oracle数据库:"></a>连接oracle数据库:</h3><img src="https://img-blog.csdnimg.cn/1b38d4382af042c7bb7e443ffb5d8e3a.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/1b38d4382af042c7bb7e443ffb5d8e3a.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/><h3 id="连接mysql数据库:"><a href="#连接mysql数据库:" class="headerlink" title="连接mysql数据库:"></a>连接mysql数据库:</h3><img src="https://img-blog.csdnimg.cn/fc070d1c9f0b4ae5ad90f943af75deef.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/fc070d1c9f0b4ae5ad90f943af75deef.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/><h3 id="核心对象—输入—表输入-拖入界面即可"><a href="#核心对象—输入—表输入-拖入界面即可" class="headerlink" title="核心对象—输入—表输入-拖入界面即可"></a>核心对象—输入—表输入-拖入界面即可</h3><img src="https://img-blog.csdnimg.cn/f170e97480bd4341b1759c1e1ec179ee.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_12,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/f170e97480bd4341b1759c1e1ec179ee.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_12,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/><h3 id="双击打开表输入"><a href="#双击打开表输入" class="headerlink" title="双击打开表输入"></a>双击打开表输入</h3><img src="https://img-blog.csdnimg.cn/1fa0f28df6f144c1ada3df48204fcd1d.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/1fa0f28df6f144c1ada3df48204fcd1d.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/><h3 id="核心对象—输出—插入-x2F-更新—拖入界面即可"><a href="#核心对象—输出—插入-x2F-更新—拖入界面即可" class="headerlink" title="核心对象—输出—插入/更新—拖入界面即可"></a>核心对象—输出—插入/更新—拖入界面即可</h3><img src="https://img-blog.csdnimg.cn/dadca52d0d5a45abb97dd46b28b1dd32.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/dadca52d0d5a45abb97dd46b28b1dd32.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/><h3 id="双击打开表插入-x2F-更新"><a href="#双击打开表插入-x2F-更新" class="headerlink" title="双击打开表插入/更新"></a>双击打开表插入/更新</h3><img src="https://img-blog.csdnimg.cn/7b84d49b4c0f4b91b8254662c0f1fdda.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_13,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/7b84d49b4c0f4b91b8254662c0f1fdda.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_13,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/><h3 id="核心对象—-gt-转换—-gt-字段选择—拖入界面即可"><a href="#核心对象—-gt-转换—-gt-字段选择—拖入界面即可" class="headerlink" title="核心对象—>转换—>字段选择—拖入界面即可"></a>核心对象—>转换—>字段选择—拖入界面即可</h3><p>按住shift连接三者</p><img src="https://img-blog.csdnimg.cn/18d2edf92e97405da0d9f8e3d11aeaeb.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/18d2edf92e97405da0d9f8e3d11aeaeb.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/><h3 id="双击打开字段选择-点击元数据—获取改变的字段即可"><a href="#双击打开字段选择-点击元数据—获取改变的字段即可" class="headerlink" title="双击打开字段选择(点击元数据—获取改变的字段即可)"></a>双击打开字段选择(点击元数据—获取改变的字段即可)</h3><img src="https://img-blog.csdnimg.cn/2999787e001d460bbb6c1c4aae4a6a98.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/2999787e001d460bbb6c1c4aae4a6a98.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/><h3 id="注意Encoding设置为UTF-8-否则抽取的数据会乱码"><a href="#注意Encoding设置为UTF-8-否则抽取的数据会乱码" class="headerlink" title="注意Encoding设置为UTF-8,否则抽取的数据会乱码"></a>注意Encoding设置为UTF-8,否则抽取的数据会乱码</h3><img src="https://img-blog.csdnimg.cn/d26e80a2a37b47c8a43b15f633446fd7.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_13,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/d26e80a2a37b47c8a43b15f633446fd7.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_13,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/><h3 id="核心对象—-gt-脚本—-gt-执行sql脚本—拖入界面即可"><a href="#核心对象—-gt-脚本—-gt-执行sql脚本—拖入界面即可" class="headerlink" title="核心对象—>脚本—>执行sql脚本—拖入界面即可"></a>核心对象—>脚本—>执行sql脚本—拖入界面即可</h3><img src="https://img-blog.csdnimg.cn/a8508fb7e66042b39da7411180193f9b.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_12,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/a8508fb7e66042b39da7411180193f9b.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_12,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/><h3 id="双击打开执行sql脚本"><a href="#双击打开执行sql脚本" class="headerlink" title="双击打开执行sql脚本"></a>双击打开执行sql脚本</h3><p>由于我们需要按月做增量抽取,本月数据做全量抽取。所以在抽本月数据之前要先删除oracle库目标表中之前抽取的本月数据。<br><img src="https://img-blog.csdnimg.cn/ccecbe5b61d34f1fa89253cf3ecb2201.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_18,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/ccecbe5b61d34f1fa89253cf3ecb2201.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_18,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/></p><h3 id="点击运行此转换—即可完成一次数据抽取"><a href="#点击运行此转换—即可完成一次数据抽取" class="headerlink" title="点击运行此转换—即可完成一次数据抽取"></a>点击运行此转换—即可完成一次数据抽取</h3><img src="https://img-blog.csdnimg.cn/53e14e55b2564630b26d1cba2f129bc7.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/53e14e55b2564630b26d1cba2f129bc7.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/></div><div class="story post-story"><h2 id="新建作业"><a href="#新建作业" class="headerlink" title="新建作业"></a>新建作业</h2><h3 id="主对象树-作业-右键新建"><a href="#主对象树-作业-右键新建" class="headerlink" title="主对象树-作业-右键新建"></a>主对象树-作业-右键新建</h3><img src="https://img-blog.csdnimg.cn/330178468cbe4a218ebc98d38507a85e.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_17,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/330178468cbe4a218ebc98d38507a85e.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_17,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/><h3 id="核心对象—Start-x2F-作业-x2F-成功—拖入界面并连接"><a href="#核心对象—Start-x2F-作业-x2F-成功—拖入界面并连接" class="headerlink" title="核心对象—Start/作业/成功—拖入界面并连接"></a>核心对象—Start/作业/成功—拖入界面并连接</h3><img src="https://img-blog.csdnimg.cn/8e267fdfb6b440bfaf0ba7c95820ad9a.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/8e267fdfb6b440bfaf0ba7c95820ad9a.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/><h3 id="双击打开作业"><a href="#双击打开作业" class="headerlink" title="双击打开作业"></a>双击打开作业</h3><p>浏览—选择上一步的转换文件目录<br><img src="https://img-blog.csdnimg.cn/51d565591e9842599d9462dc1e44c137.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_15,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/51d565591e9842599d9462dc1e44c137.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_15,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/></p><p>双击打开Start<br>设置按天 定时抽取(重复)<br><img src="https://img-blog.csdnimg.cn/a672180e7218435ca8702682fddd4807.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_10,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/a672180e7218435ca8702682fddd4807.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_10,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/></p><p>点击run 定时抽取数据到oracle,即可完成<br><img src="https://img-blog.csdnimg.cn/34d58d0acedc417aa1ebbccc6d91d150.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_15,color_FFFFFF,t_70,g_se,x_16#pic_center" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/34d58d0acedc417aa1ebbccc6d91d150.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQ2FuZHkuZ09vZG1Pcm5pbmc=,size_15,color_FFFFFF,t_70,g_se,x_16#pic_center" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="/></p></div>]]></content>
<summary type="html">如果你需要做不同数据库之间的数据迁移或者抽取部分数据到另一个数据库,并实现定时数据同步(非实时),那么kettle是一个很好的选择。</summary>
<category term="数据处理" scheme="http://www.aquestian.cn/categories/%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/"/>
<category term="kettle" scheme="http://www.aquestian.cn/tags/kettle/"/>
</entry>
<entry>
<title>netty websocket ssl Received fatal alert:certificate_unknown</title>
<link href="http://www.aquestian.cn/blogs/Netty-WebSocket/"/>
<id>http://www.aquestian.cn/blogs/Netty-WebSocket/</id>
<published>2023-03-01T16:00:00.000Z</published>
<updated>2023-03-01T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><div class="story post-story"><h2 id="自签证书"><a href="#自签证书" class="headerlink" title="自签证书"></a>自签证书</h2><p>win+r cmd<br><img src="https://img-blog.csdnimg.cn/img_convert/3baee4b8b079c5109196a8cff0e9e339.png" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/img_convert/3baee4b8b079c5109196a8cff0e9e339.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /><br /></p><p>生成自己jks文件,指向自己要生成jks的文件位置下,我直接生成到项目resources下</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">#换成自己的本地ip</span><br><span class="line">keytool -genkey -alias server -keyalg RSA -validity 3650 -keystore D:\code\my_code\netty-demo-m\src\main\resources\mystore.jks -ext san=ip:192.168.3.7,ip:127.0.0.1,dns:localhost -storepass 1234567</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/img_convert/d05ec243994a9201d9bea6a5d073b6df.png" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/img_convert/d05ec243994a9201d9bea6a5d073b6df.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><blockquote><p>keytool -list -keystore mystore.jks -v //查看信息</p></blockquote><p>生成证书</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">keytool -alias server -exportcert -keystore D:\code\my_code\netty-demo-m\src\main\resources\mystore.jks -file D:\code\my_code\netty-demo-m\src\main\resources\mystore.cer -storepass 1234567</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/img_convert/19ad09da62b9a1dfc97d19d8358cd5bc.png" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/img_convert/19ad09da62b9a1dfc97d19d8358cd5bc.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>成功生成证书<br><img src="https://img-blog.csdnimg.cn/img_convert/38ccafef3cea235d1131cd86bb229d4a.png" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/img_convert/38ccafef3cea235d1131cd86bb229d4a.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p></div><div class="story post-story"><h2 id="项目运行"><a href="#项目运行" class="headerlink" title="项目运行"></a>项目运行</h2><p>将jks文件考入项目resources下<br><img src="https://img-blog.csdnimg.cn/img_convert/7f69a93212c77b058a766ae9dae906dd.png" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/img_convert/7f69a93212c77b058a766ae9dae906dd.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><h3 id="yaml配置:"><a href="#yaml配置:" class="headerlink" title="yaml配置:"></a>yaml配置:</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">server:</span><br><span class="line"> port: <span class="number">8080</span></span><br><span class="line"> ssl:</span><br><span class="line"> key-store: classpath:mystore.jks</span><br><span class="line"> key-store-password: <span class="number">1234567</span></span><br><span class="line"> key-store-type: JKS</span><br><span class="line"># key-alias: server</span><br><span class="line"> enabled: <span class="literal">true</span></span><br></pre></td></tr></table></figure><h3 id="netty证书加载"><a href="#netty证书加载" class="headerlink" title="netty证书加载"></a>netty证书加载</h3><p>这里我就只上关键代码了</p><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">initChannel</span><span class="params">(SocketChannel ch)</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"> <span class="keyword">if</span> (openssl){ <span class="comment">//true</span></span><br><span class="line"> <span class="type">SSLEngine</span> <span class="variable">sslEngine</span> <span class="operator">=</span> getServerSslContext().createSSLEngine();</span><br><span class="line"> sslEngine.setNeedClientAuth(<span class="literal">false</span>);</span><br><span class="line"> sslEngine.setUseClientMode(<span class="literal">false</span>);</span><br><span class="line"> <span class="type">SslHandler</span> <span class="variable">sslHandler</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SslHandler</span>(sslEngine);</span><br><span class="line"> ch.pipeline().addLast(sslHandler);</span><br><span class="line"> }</span><br><span class="line"> ch.pipeline().addLast(<span class="string">"http-codec"</span>, <span class="keyword">new</span> <span class="title class_">HttpServerCodec</span>()); <span class="comment">// HTTP编码解码器</span></span><br><span class="line"> ch.pipeline().addLast(<span class="string">"aggregator"</span>, <span class="keyword">new</span> <span class="title class_">HttpObjectAggregator</span>(<span class="number">65536</span>)); <span class="comment">// 把HTTP头、HTTP体拼成完整的HTTP请求</span></span><br><span class="line"> ch.pipeline().addLast(<span class="string">"http-chunked"</span>, <span class="keyword">new</span> <span class="title class_">ChunkedWriteHandler</span>()); <span class="comment">// 方便大文件传输,不过实质上都是短的文本数据</span></span><br><span class="line"> ch.pipeline().addLast(<span class="string">"websocket-handler"</span>,webSocketServerHandler);</span><br><span class="line"> ch.pipeline().addLast(<span class="string">"http-handler"</span>,websocketNettyRequestHandler);</span><br><span class="line">}</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> SSLContext <span class="title function_">getServerSslContext</span><span class="params">()</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"> </span><br><span class="line"> <span class="type">DefaultResourceLoader</span> <span class="variable">resourceLoader</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DefaultResourceLoader</span>();</span><br><span class="line"> org.springframework.core.io.<span class="type">Resource</span> <span class="variable">resource</span> <span class="operator">=</span> resourceLoader.getResource(<span class="string">"classpath:mystore.jks"</span>); </span><br><span class="line"> <span class="type">InputStream</span> <span class="variable">inputStream</span> <span class="operator">=</span> resource.getInputStream();</span><br><span class="line"> </span><br><span class="line"> log.info(<span class="string">"加载了密码: {}"</span>, sslPassword);</span><br><span class="line"> </span><br><span class="line"> <span class="type">char</span>[] passArray = sslPassword.toCharArray();</span><br><span class="line"> <span class="type">SSLContext</span> <span class="variable">sslContext</span> <span class="operator">=</span> SSLContext.getInstance(<span class="string">"SSLv3"</span>);</span><br><span class="line"> <span class="type">KeyStore</span> <span class="variable">ks</span> <span class="operator">=</span> KeyStore.getInstance(<span class="string">"JKS"</span>);</span><br><span class="line"> <span class="comment">//加载keytool 生成的文件</span></span><br><span class="line"> ks.load(inputStream, passArray);</span><br><span class="line"> <span class="type">KeyManagerFactory</span> <span class="variable">kmf</span> <span class="operator">=</span> KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());</span><br><span class="line"> kmf.init(ks, passArray);</span><br><span class="line"> sslContext.init(kmf.getKeyManagers(), <span class="literal">null</span>, <span class="literal">null</span>);</span><br><span class="line"> inputStream.close();</span><br><span class="line"> <span class="keyword">return</span> sslContext;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>不添加信任netty websocket ssl Received fatal alert: certificate_unknown。<br><img src="https://img-blog.csdnimg.cn/img_convert/a8aaeea4c977e04fae5636c0d794109f.png" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/img_convert/a8aaeea4c977e04fae5636c0d794109f.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><h3 id="错误原因"><a href="#错误原因" class="headerlink" title="错误原因"></a>错误原因</h3><p>这并不是程序的问题,这是证书本身的问题,主机并不承认这个证书导致的。<br><img src="https://img-blog.csdnimg.cn/img_convert/2d1ab8cfe4bb1bc585713c8805198189.png" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/img_convert/2d1ab8cfe4bb1bc585713c8805198189.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><h3 id="对证书添加信任"><a href="#对证书添加信任" class="headerlink" title="对证书添加信任"></a>对证书添加信任</h3><p>打开证书<br><img src="https://img-blog.csdnimg.cn/img_convert/aeee6ed1f0fa3d8e4b906f68b9a3f232.png" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/img_convert/aeee6ed1f0fa3d8e4b906f68b9a3f232.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>计算机添加信任</p><p>点击安装证书 - 选择本地计算机 - 将所有的证书都放入下列存储 - 受信任的根证书颁发机构<br><img src="https://img-blog.csdnimg.cn/img_convert/ce27cec8054ff074541b167f6017bba8.png" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/img_convert/ce27cec8054ff074541b167f6017bba8.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>添加完成后就不会有不信任了。<br><img src="https://img-blog.csdnimg.cn/img_convert/4fec8e96a34ff81c1a58d437d4559cd7.png" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/img_convert/4fec8e96a34ff81c1a58d437d4559cd7.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>导入证书到信任库中</p><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">keytool -import -alias server -keystore mycacert -file D:\code\my_code\netty-demo-m\src\main\resources\mystore.cer -storepass changeit</span><br></pre></td></tr></table></figure><p><img src="https://img-blog.csdnimg.cn/img_convert/b3f54fad1a0f05aef80fe49ed1f0a558.png" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/img_convert/b3f54fad1a0f05aef80fe49ed1f0a558.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="><br>在java bin 目录下会出现<br><img src="https://img-blog.csdnimg.cn/img_convert/4bc000af58b31f234bcad9d7472833dd.png" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/img_convert/4bc000af58b31f234bcad9d7472833dd.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p><p>再次运行<br><img src="https://img-blog.csdnimg.cn/img_convert/0900967055648e0655031e6f4d331412.png" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/img_convert/0900967055648e0655031e6f4d331412.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="></p></div><div class="story post-story"><h2 id="注意"><a href="#注意" class="headerlink" title="注意"></a>注意</h2><p>值得一提的是,自签的证书有且之能在本机使用,如将A机生成的证书拷贝B机使用也会出现同样的错误。</p></div>]]></content>
<summary type="html">netty整合websocket支持自签证书出现netty websocket ssl Received fatal</summary>
<category term="Netty" scheme="http://www.aquestian.cn/categories/netty/"/>
<category term="Netty" scheme="http://www.aquestian.cn/tags/netty/"/>
<category term="WebSocket" scheme="http://www.aquestian.cn/tags/websocket/"/>
</entry>
<entry>
<title>我的程序人生——第五年</title>
<link href="http://www.aquestian.cn/life/Life-Five-Year/"/>
<id>http://www.aquestian.cn/life/Life-Five-Year/</id>
<published>2022-12-30T16:00:00.000Z</published>
<updated>2022-12-30T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><div class="story post-story"><h2 id="程序人生第五年"><a href="#程序人生第五年" class="headerlink" title="程序人生第五年"></a>程序人生第五年</h2><p> 我一直很喜欢《我的团长我的团》这部影视作品,几乎每年都会重温一到两遍,故事尤为精彩的一段就是虞师三堂会审团长的这一段。开头团长讲述着自己的生平从北颠沛流离,一直到禅达。团长说他从戎以来,是从败仗中学会的打战。团长说他只是想让事情有他本来该有的样子。团长还说他从戎前,招魂的生意却是个好营生,除此之外好像也没有什么可以做的了。看似油嘴滑舌,胡搅蛮缠的表演,正如他们如尘土般轻薄。他有什么罪?烦啦说他真正的带领他们抗击日寇冲锋陷阵;兽医说他不知天命;马大志大喊冤枉;不辣说中华要灭亡湖南人先死绝;迷龙说有些瘪犊子给他安了莫须有的罪名;阿译说要向他一样犯下这样的“罪”。是的,虽然你我生于和平的年底,但在现实的碎片里,折射出的星星点点,还是过去的模样。大厦崩塌,随波逐流成了唯一的选择。我尊敬邓小平同志,更崇拜毛主席,我们慢慢老去,他们就更加光芒万丈。</p><p> 利用出差之便,我带着他乡遇故知的情怀去了这三座城市——郑州,杭州,深圳。中原绿城的中庸之道,江南月色断桥残血般的惆怅,改革开放时不我待的世界之窗。郑州——我见到了我高中的大哥,他带我尝了河南特色,有一说一,烩面我确实不太喜欢,胡辣汤配油条那是一绝。赶得巧啊,大玉米没黑灯 :) 。灯火通明的城市里不难看出郑州想要彰显出传统的华夏文化,这种文化的底蕴是流淌的黄河,古往今来的血脉传承。杭州——我的另一个老哥,我到了已经晚上了,虽然时间晚但不能耽误我们吃西湖醋鱼和东坡肉啊!吃完饭,趁着朦朦夜色,西湖边上溜溜食儿吧。上有天堂下有苏杭不是没有道理的,日益月薪的城市变化依旧保留着一抹天青色。深圳——另外俩哥们,我们并没有找到能彰显本地特色的美食 :( 。我特地去了莲花山公园去看了尊敬的邓小平同志。我还没有去过上海,但深圳就是一座与时俱进,包罗万象的城市,最能体现邓小平同志思想格局的城市。</p><p> 在北海的石化疫情爆发了,铁栅栏围满了整个村落,人们哄抢超市的各种吃食,俩天一次核酸检测。开始的时候还好,但过了三天后,事情变得不简单了,餐馆全部歇业了,持续的高温天气超市买回来的东西变质了,政府送来的物资也是越来越少了,我只能找饭店老板每天蹭一顿饭。是的,我都躺在睡觉,如果能睡着的话,睡着会让我忘记饥饿,或者说饿感来的慢一些。最让我气愤的就是我的通行证明,半个月办不下来。</br></br> 8月1号,我给政府打电话办通行手续。</br> “8月5号就会解封,届时就封控半个月了就解封了。”</br> 8月5号没有解封。</br> 8月6号我又继续拨通了政府的电话。</br> 政府登记了我的信息,让我等消息。</br> “8号政府说我的核酸过期了办不了。”</br> 我7号的核酸中午1点,我的电话在8号下午4点,电话那丫头片子跟我卡bug。</br> 8月8号我再申请,手续不受理,我一气之下通过各种渠道举报了村主任,镇政府,区政府。</br> 8月9号在举报的加持下,政府有了回应,是镇长亲自来电,并要安排通行车辆。</br> 8月10号我又又提交申请。</br> “没有提供随行通行车辆司机的信息,办不了。”</br> 8月11号我又通过各种渠道联系到一个车队司机。并且我们单位领导把公司担保手续通知到政府。</br> 8月12号,核酸结果一出,携带其他相关手续我一并给到政府,继续申请。</br> 8月12号晚上,屋外滂沱大雨,终于在晚上9点时候,通行证办理成功了。令人无语的是,通行证仅限今天使用,晚上9点,外边下大雨,就三小时我怎么走!我又又又联系了政府。</br> “不能保证给你办俩天的通行证!”</br> 我紧急联系了司机,司机也怕下雨路上危险不愿意来。软磨硬泡之下,于晚上11点,通行证变为限12,13号使用。</br> 13号一早我预约了上午10点的车,为了避免出村大门时核酸过期,我特地7点趟着到膝盖的雨水到大门口问了。一会我核酸8点过期,我9点出门是否可以,如果不可以那我现在就走。</br> 政府说没事一会过来就行,先登记了。</br> 9点再到大门口,哼!我真是信了邪了,还是以核酸过期一小时不然出门,又卡bug。上午10点,在门口群众怨声载道中可算是脱离这个鬼村子。</br> </p> <p> 这一年,如空中飞鸟,美丽自由;地上蝼蚁,不值一提;水中游鱼,随波逐流。</p></div>]]></content>
<summary type="html">疫情之下。</summary>
<category term="程序人生" scheme="http://www.aquestian.cn/categories/%E7%A8%8B%E5%BA%8F%E4%BA%BA%E7%94%9F/"/>
<category term="程序人生" scheme="http://www.aquestian.cn/tags/%E7%A8%8B%E5%BA%8F%E4%BA%BA%E7%94%9F/"/>
</entry>
<entry>
<title>mongodb索引及运用。</title>
<link href="http://www.aquestian.cn/blogs/Docker-mongoDBIndexes/"/>
<id>http://www.aquestian.cn/blogs/Docker-mongoDBIndexes/</id>
<published>2022-08-22T16:00:00.000Z</published>
<updated>2022-08-22T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><div class="story post-story"><h2 id="查看索引"><a href="#查看索引" class="headerlink" title="查看索引"></a>查看索引</h2><pre><div class="hljs"><code class="lang-sql"># getIndexes() 查看集合的所有索引db.col.getIndexes()# getIndexKeys() 查看集合中的所有索引键db.col.getIndexKeys()# totalIndexSize() 查看集合中索引的总大小db.col.totalIndexSize()# getIndexSpecs() 查看集合各索引的详细信息db.col.getIndexSpecs()</code></div></pre></div><div class="story post-story"><h2 id="创建索引"><a href="#创建索引" class="headerlink" title="创建索引"></a>创建索引</h2><p>(mongo3.0以上版本)</p><pre><div class="hljs"><code class="lang-sql">createIndex() 创建索引db.col.createIndex(keys, options)</code></div></pre><p>col 为你自己的集合名</p><p>Key 值为你要创建的索引字段,1 为指定按升序创建索引,-1 按降序来创建索引。</p><p>createIndex() 接收可选参数,可选参数列表如下:</p><table><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>background</td><td>Boolean</td><td>建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加"background" 可选参数。 “background” 默认值为false。</td></tr><tr><td>unique</td><td>Boolean</td><td>建立的索引是否唯一。指定为true创建唯一索引。默认值为false。</td></tr><tr><td>name</td><td>string</td><td>索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。</td></tr><tr><td>dropDup</td><td>Boolean</td><td>3.0+版本已废弃。在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false.</td></tr><tr><td>sparse</td><td>Boolean</td><td>对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档,默认值为 false。</td></tr><tr><td>expireAfterSeconds</td><td>integer</td><td>指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。</td></tr><tr><td>v</td><td>index version</td><td>索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。</td></tr><tr><td>weights</td><td>document</td><td>索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。</td></tr><tr><td>default_language</td><td>string</td><td>对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语。</td></tr><tr><td>language_override</td><td>string</td><td>对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language。</td></tr></tbody></table><p>实例</p><p>创建一个普通索引,key表示字段名,1表示升序排序,-1表示降序。</p><pre><div class="hljs"><code class="lang-sql"># 创建一个普通索引,key表示字段名,<span class="hljs-number">1</span>表示升序排序,<span class="hljs-number">-1</span>表示降序。db.col.createIndex({"name":<span class="hljs-number">1</span>})</n># 设置使用多个字段创建聚合索引(关系型数据库中称作复合索引)db.col.createIndex({"name":<span class="hljs-number">1</span>,"age":<span class="hljs-number">-1</span>})</n># 在后台创建索引,通过在创建索引时加 background:<span class="hljs-literal">true</span> 的选项,让创建工作在后台执行db.col.createIndex({"name":<span class="hljs-number">1</span>,"age":<span class="hljs-number">-1</span>}, {background: <span class="hljs-literal">true</span>})</code></div></pre><p>在后台创建索引的原因:<br />在前台创建索引期间会锁定数据库,会导致其它操作无法进行数据读写,在后台创建索引,会定期释放写锁,从而保证其它操作的运行,但是后台操作会在耗时更长,尤其是在频繁进行写入的服务器上。</p><p>所以创建索引应该注意以下几点:(<a href="https://www.jianshu.com/p/06d9d5c66d28" target="_blank">MongoDB:创建索引需要注意的事项 - 简书</a>)</p><ol><li><strong>数据前把索引创建好</strong></li><li><strong>如果已有数据在,要在后台创建索引</strong></li><li><strong>创建索引最好创建索引名称</strong></li></ol></div><div class="story post-story"><h2 id="复杂索引创建"><a href="#复杂索引创建" class="headerlink" title="复杂索引创建"></a>复杂索引创建</h2><p>复合索引在上边创建索引已经提到。</p><h3 id="多键索引"><a href="#多键索引" class="headerlink" title="多键索引"></a>多键索引</h3><p>为了索引保存数组值的字段,MongoDB为数组中的每个元素创建一个索引键。这些多键索引支持对数组字段的有效查询。可以在既包含标量值[1](例如字符串,数字)又包含嵌套文档的数组上构造多键索引。</p><pre><div class="hljs"><code class="lang-sql">#多键索引创建 <span class="hljs-operator"><</span>field<span class="hljs-operator">></span> 表示数组db.coll.createIndex( { <span class="hljs-operator"><</span>field<span class="hljs-operator">></span>: <span class="hljs-operator"><</span> <span class="hljs-number">1</span> <span class="hljs-keyword">or</span> <span class="hljs-number">-1</span> <span class="hljs-operator">></span> } )</code></div></pre><h3 id="间隙索引创建"><a href="#间隙索引创建" class="headerlink" title="间隙索引创建"></a>间隙索引创建</h3><p>稀疏索引仅包含具有索引字段的文档条目,即使索引字段包含空值也是如此。索引会跳过缺少索引字段的所有文档。索引是“稀疏的”,因为它不包括集合的所有文档。相反,非稀疏索引包含集合中的所有文档,为那些不包含索引字段的文档存储空值。</p><pre><div class="hljs"><code class="lang-sql"># 创建一个间隙索引db.col.createIndex({"name":<span class="hljs-number">1</span>}, { sparse: <span class="hljs-literal">true</span> })</code></div></pre><h3 id="部分索引创建"><a href="#部分索引创建" class="headerlink" title="部分索引创建"></a>部分索引创建</h3><p>部分索引仅索引集合中符合指定过滤器表达式的文档。</p><pre><div class="hljs"><code class="lang-sql"># 创建age大于<span class="hljs-number">5</span>的部分索引db.col.createIndex( { sex: <span class="hljs-number">1</span>, name: <span class="hljs-number">1</span> }, { partialFilterExpression: { age: { $gt: <span class="hljs-number">5</span> } } })</code></div></pre></div><div class="story post-story"><h2 id="更新索引"><a href="#更新索引" class="headerlink" title="更新索引"></a>更新索引</h2><pre><div class="hljs"><code class="lang-sql"># reIndex() 在name字段上重建倒序索引db.col.reIndex({"name":<span class="hljs-number">-1</span>})</code></div></pre></div><div class="story post-story"><h2 id="删除索引"><a href="#删除索引" class="headerlink" title="删除索引"></a>删除索引</h2><pre><div class="hljs"><code class="lang-sql">#dropIndex() 删除集合指定的索引db.col.dropIndex("索引名称")#dropIndexes() 删除集合全部的索引db.col.dropIndexes()</code></div></pre></div><div class="story post-story"><h2 id="Springboot-创建mongodb-索引"><a href="#Springboot-创建mongodb-索引" class="headerlink" title="Springboot 创建mongodb 索引"></a>Springboot 创建mongodb 索引</h2><h3 id="注解创建索引"><a href="#注解创建索引" class="headerlink" title="注解创建索引"></a>注解创建索引</h3><p>例子:</p><p>单个字段索引创建</p><pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@Data</span><span class="hljs-meta">@Document("person")</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">MongoEntity</span> { <span class="hljs-meta">@Indexed</span> <span class="hljs-keyword">private</span> String name;</n> <span class="hljs-keyword">private</span> String age;</n> <span class="hljs-keyword">private</span> String sex;<p>}<br></code></div></pre></p><p>多字段创建索引</p><pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@Data</span><span class="hljs-meta">@Document("person")</span><span class="hljs-meta">@CompoundIndexes({ //创建一个名为compound的复合索引 @CompoundIndex(name = "compound", def = "{'age' : 1, 'sex': 1}")})</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">MongoEntity</span> { <span class="hljs-meta">@Indexed</span> <span class="hljs-keyword">private</span> String name;</n> <span class="hljs-keyword">private</span> String age;</n> <span class="hljs-keyword">private</span> String sex;<p>}</p><p></code></div></pre></p><p>间隙索引</p><pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@CompoundIndexes({ //创建一个名为compound的复合索引 @CompoundIndex(name = "compound", def = "{'age' : 1, 'sex': 1}",sparse = true)})</span></code></div></pre><p>部分索引</p><p>官方文档没有提供有关于partialFilterExpression构造的说明。</p><h3 id="mongoTemplate构建索引"><a href="#mongoTemplate构建索引" class="headerlink" title="mongoTemplate构建索引"></a>mongoTemplate构建索引</h3><p>例子</p><p>单个索引</p><pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@Test</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">template</span><span class="hljs-params">()</span> { <span class="hljs-type">Index</span> <span class="hljs-variable">index</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Index</span>(); index.on(<span class="hljs-string">"name"</span>, Sort.Direction.ASC); mongoTemplate.indexOps(<span class="hljs-string">"person"</span>).ensureIndex(index);</n> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>;i<<span class="hljs-number">5</span>;i++){ <span class="hljs-type">Person</span> <span class="hljs-variable">person</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>(); person.setName(<span class="hljs-string">"赵"</span>+i); person.setAge(<span class="hljs-string">"2"</span>+i); person.setSex(<span class="hljs-string">"男"</span>); personService.save(person); } }</code></div></pre><p>多个索引,我百度之后连续.on()即可以创建,但我尝试之后只有第一个索引成功。</p><pre><div class="hljs"><code class="lang-java"> <span class="hljs-meta">@Test</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">template</span><span class="hljs-params">()</span> { <span class="hljs-type">Index</span> <span class="hljs-variable">index</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Index</span>(); index.on(<span class="hljs-string">"name"</span>, Sort.Direction.ASC) .on(<span class="hljs-string">"age"</span>, Sort.Direction.ASC) <span class="hljs-comment">//不生效</span> .on(<span class="hljs-string">"sex"</span>, Sort.Direction.ASC).sparse(); <span class="hljs-comment">//不生效</span> mongoTemplate.indexOps(<span class="hljs-string">"person"</span>).ensureIndex(index); </n> <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>;i<<span class="hljs-number">5</span>;i++){ <span class="hljs-type">Person</span> <span class="hljs-variable">person</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Person</span>(); person.setName(<span class="hljs-string">"赵"</span>+i); person.setAge(<span class="hljs-string">"2"</span>+i); person.setSex(<span class="hljs-string">"男"</span>); personService.save(person); } }</code></div></pre><p>间隙索引即.sarse()</p><p>部分索引</p><p>暂无。</p><p>mongoTemplate提供了增,删,删除全部,重建,查询这个五种接口。可以逐个尝试。</p><pre><div class="hljs"><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">IndexOperations</span> {<p> <span class="hljs-keyword">void</span> <span class="hljs-title function_">ensureIndex</span><span class="hljs-params">(IndexDefinition indexDefinition)</span>;</p><p> <span class="hljs-keyword">void</span> <span class="hljs-title function_">dropIndex</span><span class="hljs-params">(String name)</span>;</p><p> <span class="hljs-keyword">void</span> <span class="hljs-title function_">dropAllIndexes</span><span class="hljs-params">()</span>;</p><p> <span class="hljs-keyword">void</span> <span class="hljs-title function_">resetIndexCache</span><span class="hljs-params">()</span>;</p><p> List<IndexInfo> <span class="hljs-title function_">getIndexInfo</span><span class="hljs-params">()</span>;<br>}<br></code></div></pre></p><p></p></div>]]></content>
<summary type="html">mongodb 查看、创建、修改、删除索引。</summary>
<category term="MongoDB" scheme="http://www.aquestian.cn/categories/mongodb/"/>
<category term="MongoDB" scheme="http://www.aquestian.cn/tags/mongodb/"/>
</entry>
<entry>
<title>Java连接MongoDB聚合分组查询。</title>
<link href="http://www.aquestian.cn/blogs/Docker-mongoDBJointQuestion/"/>
<id>http://www.aquestian.cn/blogs/Docker-mongoDBJointQuestion/</id>
<published>2022-07-12T16:00:00.000Z</published>
<updated>2022-07-12T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><p>之前的文章说到<a href="/blogs/Docker-MongoDBJoint" target="_blank">MongoDB聚合查询实现多表联查。</a>其实是还是有一些遗留问题的,这个文章就是在之前的文章上做个补存。咱们通过MySql和MongoDB做个对比。</p><div class="story post-story"><h2 id="单条件分组求和"><a href="#单条件分组求和" class="headerlink" title="单条件分组求和"></a>单条件分组求和</h2><h3 id="MySql数据库"><a href="#MySql数据库" class="headerlink" title="MySql数据库"></a>MySql数据库</h3><p>java代码此处就忽略了</p><p>类似MySql的失去了语句如下</p><pre><div class="hljs"><code class="lang-sql"><span class="hljs-keyword">select</span> goodsName,<span class="hljs-keyword">sum</span>(net)<span class="hljs-keyword">from</span> weightingDataDetail <span class="hljs-keyword">group</span> <span class="hljs-keyword">by</span> goodsName</code></div></pre><p>sql执行成功后返回的数据应该是</p><table><thead><tr><th>goodsName</th><th>net</th></tr></thead><tbody><tr><td>物料1</td><td>300</td></tr><tr><td>物料2</td><td>500</td></tr></tbody></table><p>是可以直接映射到对象返回给前端直接渲染的。</p><h3 id="MongoDB数据库"><a href="#MongoDB数据库" class="headerlink" title="MongoDB数据库"></a>MongoDB数据库</h3><p>Java代码</p><pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@Test</span><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sum</span><span class="hljs-params">()</span> </span>{ </n> Aggregation agg = <span class="hljs-keyword">null</span>; </n> agg = Aggregation.newAggregation( group(<span class="hljs-string">"goodsName"</span>)<span class="hljs-comment">//设置分组字段</span> .sum(<span class="hljs-string">"net"</span>).as(<span class="hljs-string">"net"</span>), project(<span class="hljs-string">"goodsName"</span>,<span class="hljs-string">"net"</span>) ); </n> AggregationResults<WeightingDataDetail> results = mongoTemplate.aggregate(agg, <span class="hljs-string">"weightingDataDetail"</span>, WeightingDataDetail.class); </n> WeightingDataDetail weightingDataDetail = results.getMappedResults().get(<span class="hljs-number">0</span>); </n> System.err.println(JSON.toJSONString(weightingDataDetail));}</code></div></pre><p><ins>MongoDB这时候的sql为:</ins></p><pre><div class="hljs"><code class="lang-sql">db.weightingDataDetail.aggregate( [{ "$group": { "_id":"$goodsName", "net": { "$sum": "$net" } } }, { "$project": { "goodsName": "$_id.goodsName", "net": 1, } }])</code></div></pre><p>sql执行成功后返回的数据是</p><table><thead><tr><th>_id</th><th>net</th></tr></thead><tbody><tr><td>物料1</td><td>300</td></tr><tr><td>物料2</td><td>500</td></tr></tbody></table><p><strong>这时候映射到对象上物料在id上,这样前端是不能直接渲染,而且也不符合现实所需要的,但多条件分组时,就不会映射在id上了,很坑。</strong><br />需要把mongDB的sql改为:</p><pre><div class="hljs"><code class="lang-sql">db.weightingDataDetail.aggregate( [{ "$group": { "_id": { "goodsName": "$goodsName", }, "net": { "$sum": "$net" } } }, { "$project": { "goodsName": "$_id.goodsName", "net": 1, } }])</code></div></pre><p>这时候运行结果就对了:</p><table><thead><tr><th>_id</th><th>net</th><th>goodsName</th></tr></thead><tbody><tr><td>Document</td><td>300</td><td>物料1</td></tr><tr><td>Document</td><td>500</td><td>物料2</td></tr></tbody></table><p>这样才能完全映射到对象上。</p><p>怎么才能用java构建出<br /><blockquote>“_id”: {<br />“goodsName”: “$goodsName”,<br />}<br /></blockquote><p>这种条件,就成了关键。</p><p>于是通过“曲线救国”的方式找到了如下办法:</p><h4 id="方式一"><a href="#方式一" class="headerlink" title="方式一"></a>方式一</h4><p>将"_id"起个别名,换成要返回的字段。<br />sql如下:</p><pre><div class="hljs"><code class="lang-sql">db.weightingDataDetail.aggregate( [{ "$group": { "_id": "$goodsName", "net": { "$sum": "$net" } } }, { "$project": { "goodsName": "$_id", "net": "$net" } }])</code></div></pre><p>运行结果如下</p><table><thead><tr><th>_id</th><th>net</th><th>goodsName</th></tr></thead><tbody><tr><td>物料1</td><td>300</td><td>物料1</td></tr><tr><td>物料2</td><td>500</td><td>物料2</td></tr></tbody></table><p>Java代码如下</p><pre><div class="hljs"><code class="lang-java"> <span class="hljs-meta">@Test</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sum</span><span class="hljs-params">()</span> </span>{ </n> Aggregation agg = <span class="hljs-keyword">null</span>; </n> agg = Aggregation.newAggregation( group(<span class="hljs-string">"goodsName"</span>)<span class="hljs-comment">//设置分组字段</span> .sum(<span class="hljs-string">"net"</span>).as(<span class="hljs-string">"net"</span>), project(<span class="hljs-string">"goodsName"</span>,<span class="hljs-string">"net"</span>) .andExpression(<span class="hljs-string">"_id"</span>).as(<span class="hljs-string">"goodsName"</span>) <span class="hljs-comment">//将id起别名</span> .andExpression(<span class="hljs-string">"net"</span>).as(<span class="hljs-string">"net"</span>) <span class="hljs-comment">//或者这样起别名</span> .and(<span class="hljs-string">"_id"</span>).as(<span class="hljs-string">"goodsName"</span>) ); </n> AggregationResults<WeightingDataDetail> results = mongoTemplate.aggregate(agg, <span class="hljs-string">"weightingDataDetail"</span>, WeightingDataDetail.class); </n> WeightingDataDetail weightingDataDetail = results.getMappedResults().get(<span class="hljs-number">0</span>); </n> System.err.println(JSON.toJSONString(weightingDataDetail)); }</code></div></pre><p>起别名还可以使用previousOperation,一般配合and使用,这里就不展示sql了;官方解释:</p><p><strong>选择n字段并为ID字段创建一个别名,该别名是由前一个组操作(因此调用previousOperation())生成的,其名称为标记。</strong><br />java代码如下</p><pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@Test</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sum</span><span class="hljs-params">()</span> </span>{ </n> Aggregation agg = <span class="hljs-keyword">null</span>; </n> agg = Aggregation.newAggregation( group(<span class="hljs-string">"goodsName"</span>)<span class="hljs-comment">//设置分组字段</span> .sum(<span class="hljs-string">"net"</span>).as(<span class="hljs-string">"net"</span>), project(<span class="hljs-string">"goodsName"</span>,<span class="hljs-string">"net"</span>).and(<span class="hljs-string">"goodsName"</span>).previousOperation() ); </n> AggregationResults<WeightingDataDetail> results = mongoTemplate.aggregate(agg, <span class="hljs-string">"weightingDataDetail"</span>, WeightingDataDetail.class); </n> WeightingDataDetail weightingDataDetail = results.getMappedResults().get(<span class="hljs-number">0</span>); </n> System.err.println(JSON.toJSONString(weightingDataDetail)); }</code></div></pre><h4 id="方式二"><a href="#方式二" class="headerlink" title="方式二"></a>方式二</h4><p>将分组条件变为多条件,分组一个压根不存在的条件。<br />sql如下:</p><pre><div class="hljs"><code class="lang-sql">db.weightingDataDetail.aggregate( [ { "$group": { "_id": { "goodsName": "$goodsName", "1": "$1" }, "net": { "$sum": "$net" } } }, { "$project": { "goodsName": "$_id.goodsName", "net": 1, "1": "$_id.1" } }])</code></div></pre><p>这样也是满足的,但是在MySql中这么做肯定是会报错的,不知道这个"1"是个啥。</p><table><thead><tr><th>_id</th><th>net</th><th>goodsName</th></tr></thead><tbody><tr><td>Document</td><td>300</td><td>物料1</td></tr><tr><td>Document</td><td>500</td><td>物料2</td></tr></tbody></table><p>java代码如下:</p><pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@Test</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sum</span><span class="hljs-params">()</span> </span>{ </n> Aggregation agg = <span class="hljs-keyword">null</span>; </n> agg = Aggregation.newAggregation( group(<span class="hljs-string">"goodsName"</span>,<span class="hljs-string">"1"</span>)<span class="hljs-comment">//设置分组字段</span> .sum(<span class="hljs-string">"net"</span>).as(<span class="hljs-string">"net"</span>), project(<span class="hljs-string">"goodsName"</span>,<span class="hljs-string">"net"</span>) ); </n> AggregationResults<WeightingDataDetail> results = mongoTemplate.aggregate(agg, <span class="hljs-string">"weightingDataDetail"</span>, WeightingDataDetail.class); </n> WeightingDataDetail weightingDataDetail = results.getMappedResults().get(<span class="hljs-number">0</span>); </n> System.err.println(JSON.toJSONString(weightingDataDetail)); }</code></div></pre><h4 id="方式三"><a href="#方式三" class="headerlink" title="方式三"></a>方式三</h4><p>可以使用first和last,前提是不适用sort的前提下,不适用排序,first和$last,会默认取出所有的,也会指定到返回的字段上。</p><blockquote><p>$frist<br />返回将表达式应用到按键共享同一组文档的一组文档中的第一个文档所得到的值。仅在文档按定义的顺序排列时才有意义。</p></blockquote><blockquote><p>$last<br />返回将表达式应用于在一组按字段共享同一组文档的最后一个文档中得出的值。仅在文档按定义的 Sequences 排列时才有意义。</p></blockquote><p>sql如下:</p><pre><div class="hljs"><code class="lang-sql">db.weightingDataDetail.aggregate( [{ "$group": { "_id": "$goodsName", "net": { "$sum": "$net" }, "goodsName": { "$first": "$goodsName" // "$last": "$goodsName" } } }, { "$project": { "goodsName": 1, "net": 1 } }])</code></div></pre><table><thead><tr><th>_id</th><th>net</th><th>goodsName</th></tr></thead><tbody><tr><td>Document</td><td>300</td><td>物料1</td></tr><tr><td>Document</td><td>500</td><td>物料2</td></tr></tbody></table><p>java代码如下:</p><pre><div class="hljs"><code class="lang-java"> <span class="hljs-meta">@Test</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sum</span><span class="hljs-params">()</span> </span>{ </n> Aggregation agg = <span class="hljs-keyword">null</span>; </n> agg = Aggregation.newAggregation( group(<span class="hljs-string">"goodsName"</span>)<span class="hljs-comment">//设置分组字段</span> .sum(<span class="hljs-string">"net"</span>).as(<span class="hljs-string">"net"</span>) .first(<span class="hljs-string">"goodsName"</span>).as(<span class="hljs-string">"goodsName"</span>), project(<span class="hljs-string">"goodsName"</span>,<span class="hljs-string">"net"</span>) ); </n> AggregationResults<WeightingDataDetail> results = mongoTemplate.aggregate(agg, <span class="hljs-string">"weightingDataDetail"</span>, WeightingDataDetail.class); </n> WeightingDataDetail weightingDataDetail = results.getMappedResults().get(<span class="hljs-number">0</span>); </n> System.err.println(JSON.toJSONString(weightingDataDetail)); }</code></div></pre><p>其实这三种方式我倾向第一种起别名。</p></div><div class="story post-story"><h2 id="返回指定字段特殊情况"><a href="#返回指定字段特殊情况" class="headerlink" title="返回指定字段特殊情况"></a>返回指定字段特殊情况</h2><p>多返回一个字段,前提是这个字段在分组条件里是唯一的,比如goodsName对应的orderType只有一种,不会出现一种goodsName有俩个orderType。</p><p>MySql sql如下</p><p>select goodsName,orderType,sum(net)from weightingDataDetail group by goodsName</p><p>值得注意的是mongo要像MySql这样返回分组以外的字段,这个字段必须在group条件下,才能作为返回条件。</p><p>可以使用返回指定字段方式三,不排序的情况下多加一种,也是可以的。<br />mongo sql如下,</p><pre><div class="hljs"><code class="lang-sql">db.weightingDataDetail.aggregate( [{ "$group": { "_id": "$goodsName", "net": { "$sum": "$net" }, "orderType": { "$first": "$orderType" // "$last": "$goodsName" } } }, { "$project": { "goodsName": 1, "net": 1, "orderType":1 } }])</code></div></pre><table><thead><tr><th>_id</th><th>net</th><th>orderType</th></tr></thead><tbody><tr><td>物料1</td><td>300</td><td>1</td></tr><tr><td>物料2</td><td>500</td><td>2</td></tr></tbody></table><p>结合一二种方式就可以返回指定的字段。<br />java代码如下</p><pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@Test</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sum</span><span class="hljs-params">()</span> </span>{ </n> Aggregation agg = <span class="hljs-keyword">null</span>; </n> agg = Aggregation.newAggregation( group(<span class="hljs-string">"goodsName"</span>)<span class="hljs-comment">//设置分组字段</span> .sum(<span class="hljs-string">"net"</span>).as(<span class="hljs-string">"net"</span>) .first(<span class="hljs-string">"orderType"</span>).as(<span class="hljs-string">"orderType"</span>), project(<span class="hljs-string">"goodsName"</span>,<span class="hljs-string">"net"</span>,<span class="hljs-string">"orderType"</span>) .and(<span class="hljs-string">"_id"</span>).as(<span class="hljs-string">"goodsName"</span>) .and(<span class="hljs-string">"orderType"</span>).as(<span class="hljs-string">"orderType"</span>) ); </n> AggregationResults<WeightingDataDetail> results = mongoTemplate.aggregate(agg, <span class="hljs-string">"weightingDataDetail"</span>, WeightingDataDetail.class); </n> WeightingDataDetail weightingDataDetail = results.getMappedResults().get(<span class="hljs-number">0</span>); </n> System.err.println(JSON.toJSONString(weightingDataDetail)); }</code></div></pre><p>MongoDB是很强大的,我只是用了其中一种方式去构建聚合查询,它还有别的构建方式,后续再一点点学习。</p></div>]]></content>
<summary type="html">Java连接MongoDB聚合分组查询返回指定参数存在的一些问题,通过MySql和MongoDB做个对比,了解问题所在。</summary>
<category term="MongoDB" scheme="http://www.aquestian.cn/categories/mongodb/"/>
<category term="MongoDB" scheme="http://www.aquestian.cn/tags/mongodb/"/>
</entry>
<entry>
<title>MongoDB聚合查询。</title>
<link href="http://www.aquestian.cn/blogs/Docker-mongoDBJoint/"/>
<id>http://www.aquestian.cn/blogs/Docker-mongoDBJoint/</id>
<published>2022-05-11T16:00:00.000Z</published>
<updated>2022-05-11T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><div class="story post-story"><h2 id="查询场景"><a href="#查询场景" class="headerlink" title="查询场景"></a>查询场景</h2><p>mongodb 字段的参数类型不一致不能进行联查的,比如,id默认为ObjectId,另外一张表存的id为String类型,这时候不可以联查;比如存的数据是BigDecimal类型,那么java里聚合查询sum也是不可以的。所以如果表之间,或者构造器构造的字段与数据库的字段类型不一致,那么数据是查不出的。</p></div><div class="story post-story"><h2 id="数据结构"><a href="#数据结构" class="headerlink" title="数据结构"></a>数据结构</h2><p>从表1(车牌表)</p><pre><div class="hljs"><code class="lang-java"><span class="hljs-meta">@Data</span><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Truck</span></span>{ <span class="hljs-meta">@Id</span> <span class="hljs-keyword">protected</span> String id; </n> <span class="hljs-comment">/** * 运输公司ID(主表id) * * <span class="hljs-doctag">@notExist</span> */</span> <span class="hljs-keyword">private</span> String transportId; </n> <span class="hljs-comment">/** * 车牌号 * * <span class="hljs-doctag">@condition</span> * <span class="hljs-doctag">@notExist</span> */</span> <span class="hljs-keyword">private</span> String truckNo; </n> <span class="hljs-comment">/** * 创建时间 * * <span class="hljs-doctag">@notView</span> */</span> <span class="hljs-keyword">private</span> String createTime; </n> <span class="hljs-comment">/** * 运输单位(关联表的字段) */</span> <span class="hljs-keyword">private</span> String unitName; </n> <span class="hljs-comment">/** * 邀请码(关联表的字段) */</span> <span class="hljs-keyword">private</span> String inviteCode; <p>}<br></code></div></pre></p><p>我只显示关键字段,多余字段不展示,这次处理的是三表联查。上边这个表是从1表,不是主表,把它放在第一个是因为这个表是作为返回使用的。</p></div><div class="story post-story"><h2 id="从表2(邀请码表)"><a href="#从表2(邀请码表)" class="headerlink" title="从表2(邀请码表)"></a>从表2(邀请码表)</h2><p>注:邀请人员进入运输单位的表,无需关注我的实际业务。</p><pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">/** * 邀请码管理 * <span class="hljs-doctag">@access</span>=inviteCode * <span class="hljs-doctag">@parent</span>=appcommon * <span class="hljs-doctag">@parentName</span>=日常业务管理 */</span><span class="hljs-meta">@Data</span><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InviteCode</span></span>{ </n> <span class="hljs-meta">@Id</span> <span class="hljs-keyword">protected</span> String id; </n> <span class="hljs-comment">/** * 邀请码 * <span class="hljs-doctag">@condition</span> * <span class="hljs-doctag">@notExist</span> */</span> <span class="hljs-keyword">private</span> String code; </n> <span class="hljs-comment">/** * 所属运输单位id */</span> <span class="hljs-keyword">private</span> String belongTransportId; <p>}<br></code></div></pre></p></div><div class="story post-story"><h2 id="主表(运输单位表)"><a href="#主表(运输单位表)" class="headerlink" title="主表(运输单位表)"></a>主表(运输单位表)</h2><pre><div class="hljs"><code class="lang-java"><span class="hljs-comment">/** * 运输单位 */</span><span class="hljs-meta">@Data</span><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TransportUnit</span></span>{ <span class="hljs-meta">@Id</span> <span class="hljs-keyword">protected</span> String id; <span class="hljs-comment">/** * 单位名称 * * <span class="hljs-doctag">@condition</span> * <span class="hljs-doctag">@notExist</span> */</span> <span class="hljs-keyword">private</span> String unitName; <span class="hljs-comment">/** * 创建人(邀请人) * * <span class="hljs-doctag">@notView</span> */</span> <span class="hljs-keyword">private</span> String creator; }</code></div></pre><p>三个表我去了一些没用的内容,保留了三表联查的关键字段。</p></div><div class="story post-story"><h2 id="MongoDB-sql语句实现"><a href="#MongoDB-sql语句实现" class="headerlink" title="MongoDB sql语句实现"></a>MongoDB sql语句实现</h2><p>从表结构中可以看出,运输单位表作为主表需要关联其他俩个表。从返回表里可以看到我们想要返回内容。</p><p>要注意一点的是,为啥以运输单位作为主表,不仅仅是因为主id在这个表中,而且ObjectId转String好转换,反之处理比较麻烦。</p><pre><div class="hljs"><code class="lang-sql">db.transportUnit.aggregate([ { $project: { id: { $toString: "$_id" }, unitName: 1, } }, { $lookup: { from: "truck", localField: "id", foreignField: "transportId", as: "truck" } }, { $unwind: "$truck" }, { $lookup: { from: "inviteCode", localField: "id", foreignField: "belongTransportId", as: "inviteCode" } }, { $unwind: "$inviteCode" }, { $project:{ title:1, truck:{ unitName:"$unitName", truckNo:1, code: '$inviteCode.code', transportId:1, creator: 1, createTime: 1, } } },]);</code></div></pre><p><strong>解释一下sql:</strong></p><p><strong>第一个lookup后使用了unwind将单个Bson拆为Bson数组,这点不可缺少,不然第二层lookup会关联不上。这里使用了project来将ObjectId转为String,当然也是通过这个返回指定字段的。因为之前使用了unwind,最后使用了group再进行一次压缩聚合。</strong></p><p>查询结果:</p><p><img src="https://img-blog.csdnimg.cn/20210526184535747.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20210526184535747.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p></div><div class="story post-story"><h2 id="Java实现"><a href="#Java实现" class="headerlink" title="Java实现"></a>Java实现</h2><pre><div class="hljs"><code class="lang-java"><span class="hljs-function"><span class="hljs-keyword">public</span> PageInfo<Truck> <span class="hljs-title">findAllByLike</span><span class="hljs-params">(Truck truck, <span class="hljs-keyword">int</span> page, <span class="hljs-keyword">int</span> size)</span> <span class="hljs-keyword">throws</span> GenericException </span>{ String truckNo = truck.getTruckNo(); String transportName = truck.getTransportName(); Criteria criteria; criteria = Criteria.where(<span class="hljs-string">"id"</span>).not(); <span class="hljs-keyword">if</span> (StringUtils.isNotEmpty(truckNo)){ criteria.and(<span class="hljs-string">"truckNo"</span>).regex(truckNo); } <span class="hljs-keyword">if</span> (StringUtils.isNotEmpty(transportName)){ criteria.and(<span class="hljs-string">"unitName"</span>).regex(transportName); } Aggregation agg = Aggregation.newAggregation( project(<span class="hljs-string">"id"</span>).andExpression(<span class="hljs-string">"toString(_id)"</span>).as(<span class="hljs-string">"id"</span>) .and(<span class="hljs-string">"unitName"</span>).as(<span class="hljs-string">"unitName"</span>), lookup(Fields.field(<span class="hljs-string">"truck"</span>),Fields.field(<span class="hljs-string">"id"</span>),Fields.field(<span class="hljs-string">"transportId"</span>),Fields.field(<span class="hljs-string">"truck"</span>)), unwind(<span class="hljs-string">"truck"</span>), lookup(<span class="hljs-string">"inviteCode"</span>,<span class="hljs-string">"id"</span>,<span class="hljs-string">"belongTransportId"</span>,<span class="hljs-string">"inviteCode"</span>), unwind(<span class="hljs-string">"inviteCode"</span>), project(<span class="hljs-string">"unitName"</span>) .and(<span class="hljs-string">"truck.transportId"</span>).as(<span class="hljs-string">"transportId"</span>) .and(<span class="hljs-string">"inviteCode.code"</span>).as(<span class="hljs-string">"inviteCode"</span>) .and(<span class="hljs-string">"truck.creator"</span>).as(<span class="hljs-string">"creator"</span>) .and(<span class="hljs-string">"truck.createTime"</span>).as(<span class="hljs-string">"createTime"</span>) .and(<span class="hljs-string">"truck.truckNo"</span>).as(<span class="hljs-string">"truckNo"</span>), match(criteria), skip((page)*size), limit(size) ); Aggregation agg1 = Aggregation.newAggregation( project(<span class="hljs-string">"id"</span>).andExpression(<span class="hljs-string">"toString(_id)"</span>).as(<span class="hljs-string">"id"</span>) .and(<span class="hljs-string">"unitName"</span>).as(<span class="hljs-string">"unitName"</span>), lookup(Fields.field(<span class="hljs-string">"truck"</span>),Fields.field(<span class="hljs-string">"id"</span>),Fields.field(<span class="hljs-string">"transportId"</span>),Fields.field(<span class="hljs-string">"truck"</span>)), unwind(<span class="hljs-string">"truck"</span>), lookup(<span class="hljs-string">"inviteCode"</span>,<span class="hljs-string">"id"</span>,<span class="hljs-string">"belongTransportId"</span>,<span class="hljs-string">"inviteCode"</span>), unwind(<span class="hljs-string">"inviteCode"</span>), project(<span class="hljs-string">"unitName"</span>) .and(<span class="hljs-string">"truck.transportId"</span>).as(<span class="hljs-string">"transportId"</span>) .and(<span class="hljs-string">"inviteCode.code"</span>).as(<span class="hljs-string">"inviteCode"</span>) .and(<span class="hljs-string">"truck.creator"</span>).as(<span class="hljs-string">"creator"</span>) .and(<span class="hljs-string">"truck.createTime"</span>).as(<span class="hljs-string">"createTime"</span>) .and(<span class="hljs-string">"truck.truckNo"</span>).as(<span class="hljs-string">"truckNo"</span>), match(criteria) ); AggregationResults<Truck> results = mongoTemplate.aggregate(agg, <span class="hljs-string">"transportUnit"</span>, Truck.class); AggregationResults<Truck> results1 = mongoTemplate.aggregate(agg1, <span class="hljs-string">"transportUnit"</span>, Truck.class); List<Truck> trucks = results.getMappedResults(); List<Truck> mappedResults = results1.getMappedResults(); System.err.println(results.getMappedResults().size()); PageInfo<Truck> pageInfo = <span class="hljs-keyword">new</span> PageInfo<>(trucks); pageInfo.setTotal(mappedResults.size()); <span class="hljs-keyword">return</span> pageInfo; }</code></div></pre><p>这里有个问题,就是聚合查询,分页的情况下无法返回总条数,所以得通过相同的条件,部分也单独查一次总条数。</p><p>注意:match查询条件必须放查询联查之后,好比sql where条件放查询结果之后。</p></div><div class="story post-story"><h2 id="另外一种方式查询"><a href="#另外一种方式查询" class="headerlink" title="另外一种方式查询"></a>另外一种方式查询</h2><p>不使用project的方式查询进行类型转换比较麻烦,使用addFields也可以实现。</p><p>sql:</p><pre><div class="hljs"><code class="lang-sql">db.transportUnit.aggregate([ { $addFields: { id: { $toString: '$_id' } } }, { $lookup: { from: "truck", localField: "id", foreignField: "transportId", as: "truck" } }, { $unwind: "$truck" }, { $lookup: { from: "inviteCode", localField: "id", foreignField: "belongTransportId", as: "inviteCode" } }, { $unwind: "$inviteCode" }, { $project: { title: 1, truck: { unitName: "$unitName", truckNo: 1, code: '$inviteCode.code', transportId: 1, creator: 1, createTime: 1, } } }, <p>]);<br></code></div></pre></p><p>查询结果一致,我就不展示了。</p><p>可能是我对mongodb不太熟悉,另外一种虽然查出来了但是构造起来有点麻烦,我只实现了个大概。</p><pre><div class="hljs"><code class="lang-java"> MongoCollection<Document> collection= mongoTemplate.getCollection(<span class="hljs-string">"transportUnit"</span>); List<Document> documentArrayList= <span class="hljs-keyword">new</span> ArrayList<>(); </n> collection.aggregate( Arrays.asList(<span class="hljs-comment">// Aggregates.match(Filters.eq("_id", new ObjectId())),</span> Aggregates.addFields(<span class="hljs-keyword">new</span> Field<>(<span class="hljs-string">"id"</span>,<span class="hljs-keyword">new</span> Document(<span class="hljs-string">"$toString"</span>,<span class="hljs-string">"$_id"</span>))), Aggregates.lookup(<span class="hljs-string">"truck"</span>,<span class="hljs-string">"id"</span>,<span class="hljs-string">"transportId"</span>,<span class="hljs-string">"truck"</span>), Aggregates.unwind(<span class="hljs-string">"$truck"</span>), Aggregates.lookup(<span class="hljs-string">"inviteCode"</span>,<span class="hljs-string">"id"</span>,<span class="hljs-string">"belongTransportId"</span>,<span class="hljs-string">"inviteCode"</span>)) ).forEach((Block<? <span class="hljs-keyword">super</span> Document>) documentArrayList::add); </n> <span class="hljs-keyword">if</span> (documentArrayList.size()><span class="hljs-number">0</span>){ System.err.println(documentArrayList); }<p></code></div></pre></p><p></p><p>能够写出这篇文章全归功于:<a href="https://blog.csdn.net/nyzzht123/article/details/109209847" target="_blank">https://blog.csdn.net/nyzzht123/article/details/109209847</a> 感谢</p></div>]]></content>
<summary type="html">MongoDB聚合查询实现多表联查,类型转换,返回指定参数。</summary>
<category term="MongoDB" scheme="http://www.aquestian.cn/categories/mongodb/"/>
<category term="MongoDB" scheme="http://www.aquestian.cn/tags/mongodb/"/>
</entry>
<entry>
<title>Docker搭建MongoDB副本集</title>
<link href="http://www.aquestian.cn/blogs/Docker-mongoDB/"/>
<id>http://www.aquestian.cn/blogs/Docker-mongoDB/</id>
<published>2022-04-09T16:00:00.000Z</published>
<updated>2022-04-09T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><div class="story post-story"><h2 id="docker拉取mongo"><a href="#docker拉取mongo" class="headerlink" title="docker拉取mongo"></a>docker拉取mongo</h2><pre><div class="hljs"><code class="lang-js">docker pull mongo</code></div></pre></div><div class="story post-story"><h2 id="安装mongo副本集"><a href="#安装mongo副本集" class="headerlink" title="安装mongo副本集"></a>安装mongo副本集</h2><p>配置及端口号配置信息,启动三个以上mongo服务,节点指向一个"rs"</p><pre><div class="hljs"><code class="lang-js">docker run -itd --name m0 -p <span class="hljs-number">27000</span>:<span class="hljs-number">27017</span> mongo --replSet <span class="hljs-string">"rs"</span> <p>docker run -itd --name m1 -p <span class="hljs-number">27001</span>:<span class="hljs-number">27017</span> mongo --replSet <span class="hljs-string">"rs"</span></p><p>docker run -itd --name m2 -p <span class="hljs-number">27002</span>:<span class="hljs-number">27017</span> mongo --replSet <span class="hljs-string">"rs"</span><br></code></div></pre></p><p>启动成功后可以通过docker ps查看容器id</p><pre><div class="hljs"><code class="lang-js">docker ps</code></div></pre><p>可以通过俩种方式进入容器中的mongo内部。</p><h3 id="进入容器方式一"><a href="#进入容器方式一" class="headerlink" title="进入容器方式一"></a>进入容器方式一</h3><pre><div class="hljs"><code class="lang-js">docker exec -it 容器ID /bin/bash mongo</code></div></pre><h3 id="进入容器方式二"><a href="#进入容器方式二" class="headerlink" title="进入容器方式二"></a>进入容器方式二</h3><pre><div class="hljs"><code class="lang-js">docker exec -it m0 mongo admin</code></div></pre><p><img src="https://img-blog.csdnimg.cn/20210801185638132.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20210801185638132.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /><br />如上图则进入容器内部。</p><p><strong>注意我这里选了m0作为我的主数据库,其余m1,m2为从数据库。</strong></p><h3 id="对节点进行配置"><a href="#对节点进行配置" class="headerlink" title="对节点进行配置"></a>对节点进行配置</h3><pre><div class="hljs"><code class="lang-js"><span class="hljs-keyword">var</span> config={ <span class="hljs-attr">_id</span>:<span class="hljs-string">"rs"</span>, <span class="hljs-attr">members</span>:[ {<span class="hljs-attr">_id</span>:<span class="hljs-number">0</span>,<span class="hljs-attr">host</span>:<span class="hljs-string">"你服务器ip:27000"</span>}, {<span class="hljs-attr">_id</span>:<span class="hljs-number">1</span>,<span class="hljs-attr">host</span>:<span class="hljs-string">"你服务器ip:27001"</span>}, {<span class="hljs-attr">_id</span>:<span class="hljs-number">2</span>,<span class="hljs-attr">host</span>:<span class="hljs-string">"你服务器ip:27002"</span>}]};</code></div></pre><p><s>如果你是本地安装,这里建议不安装副本集,一旦IP发送变化,副本集数据库就不好使了。</s></p><h3 id="执行配置"><a href="#执行配置" class="headerlink" title="执行配置"></a>执行配置</h3><pre><div class="hljs"><code class="lang-js">rs.initiate(config)</code></div></pre><p><img src="https://img-blog.csdnimg.cn/20210801190120241.png" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20210801190120241.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /><br />执行成功之后,可以通过</p><p>rs.conf() 查看是否配置成功和信息,</p><p>rs.status() 查看各节点状态。</p></div><div class="story post-story"><h2 id="创建数据库并设置访问数据库用户权限"><a href="#创建数据库并设置访问数据库用户权限" class="headerlink" title="创建数据库并设置访问数据库用户权限"></a>创建数据库并设置访问数据库用户权限</h2><p>创建数据库</p><pre><div class="hljs"><code class="lang-js">use ylgroup</code></div></pre><p>添加数据</p><pre><div class="hljs"><code class="lang-js">db.ylgroup.insert({<span class="hljs-string">"name"</span>:<span class="hljs-string">"张三"</span>})</code></div></pre><p>配置数据库用户访问权限</p><pre><div class="hljs"><code class="lang-js">db.createUser({<span class="hljs-attr">user</span>:<span class="hljs-string">'root'</span>,<span class="hljs-attr">pwd</span>:<span class="hljs-string">'admin'</span>,<span class="hljs-attr">roles</span>:[{<span class="hljs-attr">role</span>:<span class="hljs-string">'userAdmin'</span>,<span class="hljs-attr">db</span>:<span class="hljs-string">'ylgroup'</span>}]});</code></div></pre><blockquote><p>附:MongoDB基本的角色<br />1.数据库用户角色:read、readWrite;<br />2.数据库管理角色:dbAdmin、dbOwner、userAdmin;<br />3.集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;<br />4.备份恢复角色:backup、restore;<br />5.所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase<br />6.超级用户角色:root</p></blockquote></div><div class="story post-story"><h2 id="客户端连接"><a href="#客户端连接" class="headerlink" title="客户端连接"></a>客户端连接</h2><p><img src="https://img-blog.csdnimg.cn/20210801191840592.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20210801191840592.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /><br /><img src="https://img-blog.csdnimg.cn/20210801191856298.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20210801191856298.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p></div>]]></content>
<summary type="html">Docker部署mongoDB副本集,MongoDB 4.0 以后开始支持事务。</summary>
<category term="Docker" scheme="http://www.aquestian.cn/categories/docker/"/>
<category term="Docker" scheme="http://www.aquestian.cn/tags/docker/"/>
<category term="MongoDB" scheme="http://www.aquestian.cn/tags/mongodb/"/>
</entry>
<entry>
<title>Java阻塞队列与非阻塞队列</title>
<link href="http://www.aquestian.cn/blogs/Java-Queue/"/>
<id>http://www.aquestian.cn/blogs/Java-Queue/</id>
<published>2022-02-23T16:00:00.000Z</published>
<updated>2022-02-23T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><div class="story post-story"><h2 id="什么是阻塞与非阻塞"><a href="#什么是阻塞与非阻塞" class="headerlink" title="什么是阻塞与非阻塞"></a>什么是阻塞与非阻塞</h2><p>阻塞和非阻塞指的是调用者在等待返回结果时的状态。阻塞时,在调用结果返回前,当前线程会被挂起,并在得到结果之后返回。非阻塞时,如果不能立刻得到结果,则该调用者不会阻塞当前线程。因此对应非阻塞的情况,调用者需要定时轮询查看处理状态。同步和异步指具体的通信机制。同步时调用者等待返回结果。异步时,被调用者通过回调等形式通知调用者。</p></div><div class="story post-story"><h2 id="Java阻塞和释放阻塞的几种实现方式"><a href="#Java阻塞和释放阻塞的几种实现方式" class="headerlink" title="Java阻塞和释放阻塞的几种实现方式"></a>Java阻塞和释放阻塞的几种实现方式</h2><ol><li>sleep() 方法</li></ol><p>sleep(毫秒),指定以毫秒为单位的时间,使线程在该时间内进入线程阻塞状态,期间得不到cpu的时间片,等到时间过去了,线程重新进入可执行状态。(暂停线程,不会释放锁)</p><ol start="2"><li>suspend() 和 resume() 方法</li></ol><p>挂起和唤醒线程,suspend e()使线程进入阻塞状态,只有对应的resume e()被调用的时候,线程才会进入可执行状态。(不建议用,容易发生死锁)</p><ol start="3"><li>yield() 方法</li></ol><p>会使的线程放弃当前分得的cpu时间片,但此时线程任然处于可执行状态,随时可以再次分得cpu时间片。yield()方法只能使同优先级的线程有执行的机会。调用 yield()的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程。(暂停当前正在执行的线程,并执行其他线程,且让出的时间不可知)</p><ol start="4"><li>join()方法</li></ol><p>也叫线程加入。是当前线程A调用另一个线程B的join()方法,当前线程转A入阻塞状态,直到线程B运行结束,线程A才由阻塞状态转为可执行状态。</p><ol start="5"><li>wait() 和 notify() 方法</li></ol><p>两个方法搭配使用,wait()使线程进入阻塞状态,调用notify()时,线程进入可执行状态。wait()内可加或不加参数,加参数时是以毫秒为单位,当到了指定时间或调用notify()方法时,进入可执行状态。属于Object类,而不属于Thread类,wait()会先释放锁住的对象,然后再执行等待的动作。由于wait()所等待的对象必须先锁住,因此,它只能用在同步化程序段或者同步化方法内,否则,会抛出异常IllegalMonitorStateException。</p></div><div class="story post-story"><h2 id="Java阻塞和释放阻塞的例子"><a href="#Java阻塞和释放阻塞的例子" class="headerlink" title="Java阻塞和释放阻塞的例子"></a>Java阻塞和释放阻塞的例子</h2><p><a href="https://www.twle.cn/c/yufei/javatm/javatm-basic-blockingqueue.html" target="_blank">Java BlockingQueue 详解</a></p><table><thead><tr><th></th><th>抛出异常</th><th>特殊值</th><th>阻塞</th><th>超时</th></tr></thead><tbody><tr><td>插入</td><td>add(e)</td><td>offer(e)</td><td>put(e)</td><td>offer(e, time, unit)</td></tr><tr><td>移除</td><td>remove()</td><td>poll()</td><td>take()</td><td>poll(time, unit)</td></tr><tr><td>检查</td><td>element()</td><td>peek()</td><td>不可用</td><td>不可用</td></tr></tbody></table><p>这里使用重点使用了wait() 和 notify() 方法, BlockingQueue里的put(),take()方法。</p><pre><code class="lang-Java">import java.util.concurrent.BlockingQueue;import java.util.concurrent.LinkedBlockingQueue;</n>public class BlockingQueueTest { private static final int count = 10;</n> //生产者 public static class ProductThread implements Runnable { private BlockingQueue<Integer> queue;</n> public ProductThread(BlockingQueue<Integer> queue) { this.queue = queue; }</n> public void run(){ while(true){ synchronized (queue) { try { while (queue.size() == 10) { System.out.println("队列已满"); queue.notify(); queue.wait(); } queue.offer(5); System.out.println(Thread.currentThread()+"生产了一个产品---队列已有元素:"+queue.size()+"个,剩余:"+ (count - queue.size())); Thread.sleep(1000); }catch (InterruptedException e) { queue.notify(); } } } } }</n> //消费者 public static class ConsumeThread implements Runnable { private BlockingQueue<Integer> queue;</n> public ConsumeThread(BlockingQueue<Integer> queue) { this.queue = queue; }</n> public void run(){ while(true){ synchronized (queue) { try { while (queue.size() == 0) { System.out.println("队列为空"); queue.notify(); queue.wait(); } queue.take(); System.out.println(Thread.currentThread()+"消费了一个产品---队列已有元素:"+queue.size()+"个,剩余:"+ (count - queue.size())); Thread.sleep(1000); }catch (InterruptedException e) { queue.notify(); } } } } }</n> public static void main(String[] args) { //大小为10的循环数组阻塞队列 BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(count);</n> new Thread(new ProductThread(queue)).start();</n> new Thread(new ConsumeThread(queue)).start();</n> }}</code></pre></br><p><img src="https://img-blog.csdnimg.cn/5a6f627418334792aaaa85ba2a2abfd8.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA562UIOahiA==,size_20,color_FFFFFF,t_70,g_se,x_16" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/5a6f627418334792aaaa85ba2a2abfd8.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA562UIOahiA==,size_20,color_FFFFFF,t_70,g_se,x_16" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p><p>它会依次建创建好的队列中加入元素,元素已满时,生产者ProductThread阻塞,释放消费者ConsumeThread释放,依次交替阻塞释放。如果想更好的理解阻塞还是释放,可以注释掉其中一个<strong>queue.notify()</strong>;,或者注释掉<strong>queue.wait();</strong>。</p></div>]]></content>
<summary type="html">阻塞和非阻塞指的是调用者在等待返回结果时的状态。阻塞时,在调用结果返回前,当前线程会被挂起,并在得到结果之后返回。非阻塞时,如果不能立刻得到结果,则该调用者不会阻塞当前线程。</summary>
<category term="Java实例" scheme="http://www.aquestian.cn/categories/java%E5%AE%9E%E4%BE%8B/"/>
<category term="队列" scheme="http://www.aquestian.cn/tags/%E9%98%9F%E5%88%97/"/>
</entry>
<entry>
<title>我的程序人生——第四年</title>
<link href="http://www.aquestian.cn/life/Life-Fourth-Year/"/>
<id>http://www.aquestian.cn/life/Life-Fourth-Year/</id>
<published>2021-11-25T16:00:00.000Z</published>
<updated>2021-11-25T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><div class="story post-story"><h2 id="程序人生第四年"><a href="#程序人生第四年" class="headerlink" title="程序人生第四年"></a>程序人生第四年</h2><p>21年11月25日上午,在出差所在地,辽阔的大草原上,发生了一起车祸。嗯~~,往事放心底吧!有感而发,也给经常出门在外的自己写个总结。</p><p>去年11月来的新公司,一直到去年过年,都很平淡,期间我忙里偷闲拿到了驾照。年后,工作一下变得紧张匆忙起来,项目得在3月份中旬上线,而年前写的业务逻辑与现实逻辑大相径庭,基本需要推翻重新写了,也怪自己大意忽略了很多细节上的内容。没办法,上线日期不变,只能是加班加点的改。到了约定日期,也只能是硬着头皮强行上线了。不出所料,现场出了大状况,都乱成一锅粥了,电话都快被打爆了,第一次感到这种扑面而来的压力,当时我都快头皮抓破了。每况愈下,项目只能是停止上线,择日改好了再重新上线。经过几天的查漏补缺,项目总算上线了,那段时间我最怕的就是电话铃声响起来,但现场还是有不同的业务,于是忽,就有了我生平第一次出差的经历。出差的第一站———河北平权,说实话,刚开始我很抵触出差的,不过还好第一次出差也就三天,但这新环境着实让人有点无所适从。在这里我也见识到了我所面临的客户群体是谁,除了司机还有本地矿业的计量员,他们的文化水平是比较低的,有的甚至键盘都不会用。一开始,我个人的想法就是满足客户递交上来的技术协议即可,至于你们用的方便不方便跟我没有关系。现在来看,自己的这种自私行为不能说完全错,但这很明显,有能力解决不去解决,这种行为真是令人不齿。</p><p>第二站我出差的目的地是河北迁安,距离第一次出差过了一个月吧。有了第一次后,第二次出差就没有那么反感了,但多少还是会反感的。这一次实打实的来解决问题来了,本来已经是做了一路准备的,刚来下午,我就想跑路了。一个大姐笔记本上好几篇洋洋洒洒一堆要让我改的,不停的说着:“还有···,还有···”,我真是受够了这股唐山话了。话不投机半句多,把本放那儿我一个个记下啦!迁安这个地方很有意思,全国前五的县级市,跟我汾阳市一个级别的。我们领导跟我说,迁安市是把城边的一条河,挖成个湖,又把湖中心填上改了别墅,别墅呢是迁安市首富的府邸,上他们家得经过层层检查,这湖比河宽呐,又再湖上建了几座“跨江大桥”。汾阳市,山鸡岂能配凤凰,不配相提并论。接近尾声准备打道回府的时候,半路杀出个程咬金!“运维?什么运维,别把这拖油瓶挂我脖子上。”这是鄙人原话,此话一出,给我们领导都整无语了。没错,甲方单位招了一个“运维”,来跟我对接,我还得负责教她一些运维上的东西,话不投机半句多!</p><p>这里我想多用一点笔墨描写一下我的领导们—— 一群对钓鱼这个活动的“狂热份子”。这些领导身上我是可以看到他们独具特色的闪光点,但总而言之,他们是职场上经历过风雨的人,都是被社会或者生活抹平了棱角的人。他们的脾性值得我去学习,有人说这样会导致个性不足,其实普通人就做自己力所能及的事情就可以了,没必要彰显自己的个性,更不需要成为焦点。当然钓鱼确实是一件乐事,垂钓者需要是太公钓鱼的心态。</p><p>七月,我奔赴厦门,这是我第一次去到这么远的地方。这次远行,我能感受到公司对于新人培养的重视程度,一是让我熟悉不同地方不同客户的业务需求,二是邀请我加入阿米巴经验管理课程学习班,我这个新人做的一般,在学习方面确实没有落实到位。除去工作,我感触最深的就是我与宝岛台湾隔海相望。乘坐厦门地铁,听着闽南话报站名,驶过一座大桥才能到达厦门岛上,要上鼓浪屿还得再买一张登岛的船票。鼓浪屿我最先去到的是日光岩,它是鼓浪屿的最高点,也是隔海望向台湾海峡的最好的瞭望点,也是郑成功亲自提名的宝地。皓月园也令人印象深刻,毕竟我这种远离大海的“旱鸭子”,这次我勇敢地尝试了在太平洋畔洗脚。而后我又惬意的坐上“海上看金门”的游轮,一路喝着茶,海鸥保驾护航,临近金门岛时,远远的看见岛上醒目的八个大红字——三民主义,统一中国,当然了,当年我们也毫不示弱在对岸写了八个大字——一国两制,统一中国。事实证明,孙中山这一套理论,不能说一窍不通,起码是一地鸡毛吧。如果我是一位勇士,我应该纵身一跃扎进海里,一个猛子冲过去再来一个鲤鱼打挺翻身上岸,给这八个字来个大翻新—— 一国两制,统一中国。岛内的某些人士,我可去你的吧。我是坐高铁一路北上的,可以说是从最南边到最北边了吧,我证明了,祖国幅员辽阔!</p><p>在内蒙古,我又领略了美丽的大草原,这才是牛羊它们真正的天堂啊,随便吃,吃饱躺着消化。拿起手机随手一拍,都是可以作为电脑桌面的背景,处处是镜头。这一次来内蒙主要是为了调研需求,我也没想到我干起了产品的事情,也是第一次做流程图,第一次出方案,第一次做设计报告,冥冥中路又走宽了。此后我还在秋季,冬季也就是现在,统共三次踏上这片草原,领略三季的草原变化,也见识了大自然的鬼斧神工。</p><p>这里我想感谢那些积极配合客户,在抛出问题的同时,还能一起想解决问题的方案!(我还是得呼吁一下,客户少找我一次。大姐。听到了吗?话不投机半句多,如果能有一礼拜不找我,我就把你的铃声还回去!)</p><p>回顾一下这一年,我对技术倒是没有特别高的要求了,反而在项目中锻炼了自己的业务能力。涨了不少见识,对事对物也更有见地,可以从宏观角度看待问题,言行举止也成熟了,给自己打个分的话能给一个75分吧,值得给自己点个赞!</p><p>回到文章开头,这个司机师傅还是离开了这个世界。有感而发,希望为了生活出门在外,一路奔波的你我,都能平安回家。</p></div>]]></content>
<summary type="html">旅途。</summary>
<category term="程序人生" scheme="http://www.aquestian.cn/categories/%E7%A8%8B%E5%BA%8F%E4%BA%BA%E7%94%9F/"/>
<category term="程序人生" scheme="http://www.aquestian.cn/tags/%E7%A8%8B%E5%BA%8F%E4%BA%BA%E7%94%9F/"/>
</entry>
<entry>
<title>MySQL 递归查询</title>
<link href="http://www.aquestian.cn/blogs/MySQL-Recursion/"/>
<id>http://www.aquestian.cn/blogs/MySQL-Recursion/</id>
<published>2021-11-09T16:00:00.000Z</published>
<updated>2021-11-09T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><div class="story post-story"><h2 id="写在前面"><a href="#写在前面" class="headerlink" title="写在前面"></a>写在前面</h2><p>众所周知,java中递归查询,需要和数据库进行多次交互,不论是向上查询还是向下查询,所以不如进行一次交互就完成查询。据我了解,Oracle实现递归查询非常的方便,但mysql不行,需要自定义函数来完成。</p></div><div class="story post-story"><h2 id="创建表-Dept"><a href="#创建表-Dept" class="headerlink" title="创建表(Dept)"></a>创建表(Dept)</h2><pre><div class="hljs"><code class="lang-m">DROP TABLE IF EXISTS `dept`;CREATE TABLE `dept` ( `id` varchar(<span class="hljs-number">10</span>) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, `name` varchar(<span class="hljs-number">255</span>) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `pid` varchar(<span class="hljs-number">10</span>) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE) ENGINE <span class="hljs-built_in">=</span> InnoDB CHARACTER SET <span class="hljs-built_in">=</span> utf8mb4 COLLATE <span class="hljs-built_in">=</span> utf8mb4_general_ci ROW_FORMAT <span class="hljs-built_in">=</span> Dynamic;INSERT INTO `dept`(`id`, `name`, `pid`) VALUES (<span class="hljs-string">'1000'</span>, <span class="hljs-string">'总公司'</span>, NULL);INSERT INTO `dept`(`id`, `name`, `pid`) VALUES (<span class="hljs-string">'1001'</span>, <span class="hljs-string">'北京分公司'</span>, <span class="hljs-string">'1000'</span>);INSERT INTO `dept`(`id`, `name`, `pid`) VALUES (<span class="hljs-string">'1002'</span>, <span class="hljs-string">'上海分公司'</span>, <span class="hljs-string">'1000'</span>);INSERT INTO `dept`(`id`, `name`, `pid`) VALUES (<span class="hljs-string">'1003'</span>, <span class="hljs-string">'北京研发部'</span>, <span class="hljs-string">'1001'</span>);INSERT INTO `dept`(`id`, `name`, `pid`) VALUES (<span class="hljs-string">'1004'</span>, <span class="hljs-string">'北京财务部'</span>, <span class="hljs-string">'1001'</span>);INSERT INTO `dept`(`id`, `name`, `pid`) VALUES (<span class="hljs-string">'1005'</span>, <span class="hljs-string">'北京市场部'</span>, <span class="hljs-string">'1001'</span>);INSERT INTO `dept`(`id`, `name`, `pid`) VALUES (<span class="hljs-string">'1006'</span>, <span class="hljs-string">'北京研发一部'</span>, <span class="hljs-string">'1003'</span>);INSERT INTO `dept`(`id`, `name`, `pid`) VALUES (<span class="hljs-string">'1007'</span>, <span class="hljs-string">'北京研发二部'</span>, <span class="hljs-string">'1003'</span>);INSERT INTO `dept`(`id`, `name`, `pid`) VALUES (<span class="hljs-string">'1008'</span>, <span class="hljs-string">'北京研发一部一小组'</span>, <span class="hljs-string">'1006'</span>);INSERT INTO `dept`(`id`, `name`, `pid`) VALUES (<span class="hljs-string">'1009'</span>, <span class="hljs-string">'北京研发一部二小组'</span>, <span class="hljs-string">'1006'</span>);INSERT INTO `dept`(`id`, `name`, `pid`) VALUES (<span class="hljs-string">'1010'</span>, <span class="hljs-string">'北京研发二部一小组'</span>, <span class="hljs-string">'1007'</span>);INSERT INTO `dept`(`id`, `name`, `pid`) VALUES (<span class="hljs-string">'1011'</span>, <span class="hljs-string">'北京研发二部二小组'</span>, <span class="hljs-string">'1007'</span>);INSERT INTO `dept`(`id`, `name`, `pid`) VALUES (<span class="hljs-string">'1012'</span>, <span class="hljs-string">'北京市场一部'</span>, <span class="hljs-string">'1005'</span>);INSERT INTO `dept`(`id`, `name`, `pid`) VALUES (<span class="hljs-string">'1013'</span>, <span class="hljs-string">'上海研发部'</span>, <span class="hljs-string">'1002'</span>);INSERT INTO `dept`(`id`, `name`, `pid`) VALUES (<span class="hljs-string">'1014'</span>, <span class="hljs-string">'上海研发一部'</span>, <span class="hljs-string">'1013'</span>);INSERT INTO `dept`(`id`, `name`, `pid`) VALUES (<span class="hljs-string">'1015'</span>, <span class="hljs-string">'上海研发二部'</span>, <span class="hljs-string">'1013'</span>);</code></div></pre><p>创建完成后入下图</p><p><img src="https://img-blog.csdnimg.cn/20200918131602627.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200918131602627.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p><p>首先熟悉一下,mysql find_in_set函数。</p><h3 id="find-in-set-函数"><a href="#find-in-set-函数" class="headerlink" title="find_in_set 函数"></a>find_in_set 函数</h3><p>函数语法:find_in_set(str,strlist)</p><p>str 代表要查询的字符串 , strlist 是一个以逗号分隔的字符串,如 (‘a,b,c’)。<br />此函数用于查找 str 字符串在字符串 strlist 中的位置,返回结果为 1 ~ n 。若没有找到,则返回0。</p><p>举个例子:</p><pre><div class="hljs"><code class="lang-m">select FIND_IN_SET(<span class="hljs-string">'b'</span>,<span class="hljs-string">'a,b,c,d'</span>); </code></div></pre><p><img src="https://img-blog.csdnimg.cn/20200918131852215.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200918131852215.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p><p>此外,在对表数据进行查询时,它还有一种用法,如下:</p><pre><div class="hljs"><code class="lang-m">select * from dept <span class="hljs-keyword">where</span> FIND_IN_SET(id,<span class="hljs-string">'1000,1001,1002'</span>); </code></div></pre><p><img src="https://img-blog.csdnimg.cn/20200918132054756.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200918132054756.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p><p>以向下递归查询所有子节点为例,可以找到一个包含当前节点和所有子节点的以逗号拼接的字符串 strlist,传进 find_in_set 函数。就可以查询出所有需要的递归数据了。</p><p>那么,现在问题就转化为怎样构造这样的一个字符串 strlist。</p>### concat concat_ws group_concat函数<p><strong>一、字符串拼接函数中,最基本的就是 concat 了。它用于连接N个字符串,如,</strong></p><pre><div class="hljs"><code class="lang-m">select CONCAT(<span class="hljs-string">'M'</span>,<span class="hljs-string">'Y'</span>,<span class="hljs-string">'S'</span>,<span class="hljs-string">'Q'</span>,<span class="hljs-string">'L'</span>) from dual; </code></div></pre><p>结果为 ‘MYSQL’ 字符串。<br /><img src="https://img-blog.csdnimg.cn/2020091813233162.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/2020091813233162.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p><p><strong>二、concat 是以逗号为默认的分隔符,而 concat_ws 则可以指定分隔符,第一个参数传入分隔符,如以下划线分隔。</strong></p><pre><div class="hljs"><code class="lang-m">select concat_ws(<span class="hljs-string">'_'</span>,<span class="hljs-string">'M'</span>,<span class="hljs-string">'Y'</span>,<span class="hljs-string">'S'</span>,<span class="hljs-string">'Q'</span>,<span class="hljs-string">'L'</span>) from dual; </code></div></pre><p><img src="https://img-blog.csdnimg.cn/20200918132441756.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200918132441756.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p><p><strong>三、group_concat 函数更强大,可以分组的同时,把字段以特定分隔符拼接成字符串。</strong></p><p>用法:group_concat( [distinct] 要连接的字段 [order by 排序字段 asc/desc ] [separator ‘分隔符’] )</p><p>可以看到有可选参数,可以对将要拼接的字段值去重,也可以排序,指定分隔符。若没有指定,默认以逗号分隔。</p><p>对于 dept 表,我们可以把表中的所有 id 以逗号拼接。(这里没有用到 group by 分组字段,则可以认为只有一组)</p><pre><div class="hljs"><code class="lang-m">select group_concat(id) from dept; </code></div></pre><p><img src="https://img-blog.csdnimg.cn/20200918132626736.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200918132626736.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p></div><div class="story post-story"><h2 id="MySQL-自定义函数实现递归查询"><a href="#MySQL-自定义函数实现递归查询" class="headerlink" title="MySQL 自定义函数实现递归查询"></a>MySQL 自定义函数实现递归查询</h2><p>可以发现以上已经把字符串拼接的问题也解决了。那么,问题就变成怎样构造有递归关系的字符串了。</p><p>我们可以自定义一个函数,通过传入根节点id,找到它的所有子节点。</p><h3 id="向下递归。"><a href="#向下递归。" class="headerlink" title="向下递归。"></a>向下递归。</h3><p>创建自定义函数</p><pre><div class="hljs"><code class="lang-m">create function get_child_list(in_id varchar(<span class="hljs-number">10</span>)) returns varchar(<span class="hljs-number">1000</span>) begin declare ids varchar(<span class="hljs-number">1000</span>) default <span class="hljs-string">''</span>; declare tempids varchar(<span class="hljs-number">1000</span>); <p>set tempids <span class="hljs-built_in">=</span> in_id;<br>while tempids <span class="hljs-keyword">is</span> <span class="hljs-built_in">not</span> null do<br>set ids <span class="hljs-built_in">=</span> CONCAT_WS(<span class="hljs-string">','</span>,ids,tempids);<br>select GROUP_CONCAT(id) into tempids from dept <span class="hljs-keyword">where</span> FIND_IN_SET(pid,tempids)><span class="hljs-number">0</span>;<br>end while;<br>return ids;<br>end<br></code></div></pre></p><ol><li><p>create function get_child_list 创建函数。并且参数传入一个根节点的子节点id,需要注意一定要注明参数的类型和长度,如这里是 varchar(10)。returns varchar(1000) 用来定义返回值参数类型。</p></li><li><p>begin 和 end 中间包围的就是函数体。用来写具体的逻辑。</p></li><li><p>declare 用来声明变量,并且可以用 default 设置默认值。这里定义的 ids 即作为整个函数的返回值,是用来拼接成最终我们需要的以逗号分隔的递归串的。而 tempids 是为了记录下边 while 循环中临时生成的所有子节点以逗号拼接成的字符串。</p></li><li><p>set 用来给变量赋值。此处把传进来的根节点赋值给 tempids 。</p></li><li><p>while do … end while; 循环语句,循环逻辑包含在内。注意,end while 末尾需要加上分号。<br />循环体内,先用 CONCAT_WS 函数把最终结果 ids 和 临时生成的 tempids 用逗号拼接起来。然后以FIND_IN_SET(pid,tempids)>0 为条件,遍历在 tempids 中的所有 pid ,寻找以此为父节点的所有子节点 id ,并且通过 GROUP_CONCAT(id) into tempids 把这些子节点 id 都用逗号拼接起来,并覆盖更新 tempids 。等下次循环进来时,就会再次拼接 ids ,并再次查找所有子节点的所有子节点。循环往复,一层一层的向下递归遍历子节点。直到判断 tempids 为空,说明所有子节点都已经遍历完了,就结束整个循环。</p></li><li><p>return ids; 用于把 ids 作为函数返回值返回。</p></li></ol><p>自定义函数做好之后,我们就可以用它来递归查询我们需要的数据了。如,我查询北京研发部的所有子节点。<br /><img src="https://img-blog.csdnimg.cn/20200918133706820.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200918133706820.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p><h3 id="向上递归"><a href="#向上递归" class="headerlink" title="向上递归"></a>向上递归</h3><p>创建自定义函数</p><pre><div class="hljs"><code class="lang-m">create function get_parent_list(in_id varchar(<span class="hljs-number">10</span>)) returns varchar(<span class="hljs-number">1000</span>) begin declare ids varchar(<span class="hljs-number">1000</span>); declare tempid varchar(<span class="hljs-number">10</span>); <p>set tempid <span class="hljs-built_in">=</span> in_id;<br>while tempid <span class="hljs-keyword">is</span> <span class="hljs-built_in">not</span> null do<br>set ids <span class="hljs-built_in">=</span> CONCAT_WS(<span class="hljs-string">','</span>,ids,tempid);<br>select pid into tempid from dept <span class="hljs-keyword">where</span> id<span class="hljs-built_in">=</span>tempid;<br>end while;<br>return ids;<br>end<br></code></div></pre></p><p>查找北京研发二部一小组,以及它的递归父节点,如下:<br /><img src="https://img-blog.csdnimg.cn/20200918134223204.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200918134223204.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p></div><div class="story post-story"><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><p>我们用到了 group_concat 函数来拼接字符串。但是,需要注意它是有长度限制的,默认为 1024 字节。可以通过 show variables like “group_concat_max_len”; 来查看。</p><p>注意,单位是字节,不是字符。在 MySQL 中,单个字母占1个字节,而我们平时用的 utf-8下,一个汉字占3个字节。</p><p>这个对于递归查询还是非常致命的。因为一般递归的话,关系层级都比较深,很有可能超过最大长度。(尽管一般拼接的都是数字字符串,即单字节)</p><p>所以,我们有两种方法解决这个问题:</p><ol><li><p>修改 MySQL 配置文件 my.cnf ,增加 group_concat_max_len = 102400 #你要的最大长度 。</p></li><li><p>执行以下任意一个语句。SET GLOBAL group_concat_max_len=102400; 或者 SET SESSION group_concat_max_len=102400;</br><br />他们的区别在于,global是全局的,任意打开一个新的会话都会生效,但是注意,已经打开的当前会话并不会生效。而 session 是只会在当前会话生效,其他会话不生效。</br><br />共同点是,它们都会在 MySQL 重启之后失效,以配置文件中的配置为准。所以,建议直接修改配置文件。102400 的长度一般也够用了。假设一个id的长度为10个字节,也能拼上一万个id了。</p></li></ol><p>除此之外,使用 group_concat 函数还有一个限制,就是不能同时使用 limit 。如,<br /><img src="https://img-blog.csdnimg.cn/20200918134342949.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200918134342949.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p><p>本来只想查5条数据来拼接,现在不生效了。</p><p>不过,如果需要的话,可以通过子查询来实现:<br /><img src="https://img-blog.csdnimg.cn/20200918134407983.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200918134407983.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_10,color_FFFFFF,t_40" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p><p>转载于:<a href="https://mp.weixin.qq.com/s/0xpbQQEaYrSRJRCt02gRdQ" target="_blank">IT牧场</a></p></div>]]></content>
<summary type="html">MySQL 递归查询,创建一个存储过程实现,查询子节点,父节点只需要调用这个存储过程即可。</summary>
<category term="MySQL" scheme="http://www.aquestian.cn/categories/mysql/"/>
<category term="MySQL" scheme="http://www.aquestian.cn/tags/mysql/"/>
</entry>
<entry>
<title>面试官:Spring和SpringBoot有哪些区别?</title>
<link href="http://www.aquestian.cn/blogs/Question-Spring-SpringBoot/"/>
<id>http://www.aquestian.cn/blogs/Question-Spring-SpringBoot/</id>
<published>2021-08-10T16:00:00.000Z</published>
<updated>2021-08-10T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><div class="story post-story"><h2 id="什么是Spring"><a href="#什么是Spring" class="headerlink" title="什么是Spring"></a>什么是Spring</h2><p>作为Java开发人员,大家都Spring都不陌生,简而言之,Spring框架为开发Java应用程序提供了全面的基础架构支持。它包含一些很好的功能,如依赖注入和开箱即用的模块,如:Spring JDBC 、Spring MVC 、Spring Security、 Spring AOP 、Spring ORM 、Spring Test,这些模块缩短应用程序的开发时间,提高了应用开发的效率例如,在Java Web开发的早期阶段,我们需要编写大量的代码来将记录插入到数据库中。但是通过使用Spring JDBC模块的JDBCTemplate,我们可以将操作简化为几行代码。</p>## 什么是Spring Boot<p>Spring Boot基本上是Spring框架的扩展,它消除了设置Spring应用程序所需的XML配置,为更快,更高效的开发生态系统铺平了道路。</p><h3 id="Spring-Boot中的一些特征"><a href="#Spring-Boot中的一些特征" class="headerlink" title="Spring Boot中的一些特征"></a>Spring Boot中的一些特征</h3><ol><li>创建独立的Spring应用。</li><li>嵌入式Tomcat、Jetty、 Undertow容器(无需部署war文件)。</li><li>提供的starters 简化构建配置</li><li>尽可能自动配置spring应用。</li><li>提供生产指标,例如指标、健壮检查和外部化配置</li><li>完全没有代码生成和XML配置要求</li></ol></div><div class="story post-story"><h2 id="从配置分析区别"><a href="#从配置分析区别" class="headerlink" title="从配置分析区别"></a>从配置分析区别</h2><h3 id="Maven依赖"><a href="#Maven依赖" class="headerlink" title="Maven依赖"></a>Maven依赖</h3><p>首先,让我们看一下使用Spring创建Web应用程序所需的最小依赖项</p><pre><code class="lang-"><dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.1.0.RELEASE</version></dependency><dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.0.RELEASE</version></dependency></code></pre><p>与Spring不同,Spring Boot只需要一个依赖项来启动和运行Web应用程序:</p><pre><code class="lang-"><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.0.6.RELEASE</version></dependency></code></pre><p>在进行构建期间,所有其他依赖项将自动添加到项目中。</p><p>另一个很好的例子就是测试库。我们通常使用Spring Test,JUnit,Hamcrest和Mockito库。在Spring项目中,我们应该将所有这些库添加为依赖项。但是在Spring Boot中,我们只需要添加spring-boot-starter-test依赖项来自动包含这些库。</p><p>Spring Boot为不同的Spring模块提供了许多依赖项。一些最常用的是:</p><blockquote><p>spring-boot-starter-data-jpa<br />spring-boot-starter-security<br />spring-boot-starter-test<br />spring-boot-starter-web<br />spring-boot-starter-thymeleaf</p></blockquote><p>有关starter的完整列表,请查看Spring文档。</p><h3 id="MVC配置"><a href="#MVC配置" class="headerlink" title="MVC配置"></a>MVC配置</h3><p>让我们来看一下Spring和Spring Boot创建JSP Web应用程序所需的配置。</p><p>Spring需要定义调度程序servlet,映射和其他支持配置。我们可以使用 web.xml 文件或Initializer类来完成此操作:</p><p>web.xml</p><pre><div class="hljs"><code class="lang-xml"><span class="php"><span class="hljs-meta"><?</span>xml version=<span class="hljs-string">"1.0"</span> encoding=<span class="hljs-string">"UTF-8"</span><span class="hljs-meta">?></span></span><span class="hljs-tag"><<span class="hljs-name">web-app</span> <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">"http://www.w3.org/2001/XMLSchema-instance"</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://java.sun.com/xml/ns/javaee"</span> <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"WebApp_ID"</span> <span class="hljs-attr">version</span>=<span class="hljs-string">"3.0"</span>></span> <span class="hljs-tag"><<span class="hljs-name">servlet</span>></span> <span class="hljs-comment"><!--名称 --></span> <span class="hljs-tag"><<span class="hljs-name">servlet-name</span>></span>springmvc<span class="hljs-tag"></<span class="hljs-name">servlet-name</span>></span> <span class="hljs-comment"><!-- Servlet类 --></span> <span class="hljs-tag"><<span class="hljs-name">servlet-class</span>></span>org.springframework.web.servlet.DispatcherServlet<span class="hljs-tag"></<span class="hljs-name">servlet-class</span>></span> <span class="hljs-comment"><!-- 启动顺序,数字越小,启动越早 --></span> <span class="hljs-tag"><<span class="hljs-name">load-on-startup</span>></span>1<span class="hljs-tag"></<span class="hljs-name">load-on-startup</span>></span> <span class="hljs-tag"><<span class="hljs-name">init-param</span>></span> <span class="hljs-comment"><!--SpringMVC配置参数文件的位置 --></span> <span class="hljs-tag"><<span class="hljs-name">param-name</span>></span>contextConfigLocation<span class="hljs-tag"></<span class="hljs-name">param-name</span>></span> <span class="hljs-comment"><!--默认名称为ServletName-servlet.xml --></span> <span class="hljs-tag"><<span class="hljs-name">param-value</span>></span>classpath*:springmvc-servlet.xml<span class="hljs-tag"></<span class="hljs-name">param-value</span>></span> <span class="hljs-tag"></<span class="hljs-name">init-param</span>></span> <span class="hljs-tag"></<span class="hljs-name">servlet</span>></span> <span class="hljs-comment"><!--所有请求都会被springmvc拦截 --></span> <span class="hljs-tag"><<span class="hljs-name">servlet-mapping</span>></span> <span class="hljs-tag"><<span class="hljs-name">servlet-name</span>></span>springmvc<span class="hljs-tag"></<span class="hljs-name">servlet-name</span>></span> <span class="hljs-tag"><<span class="hljs-name">url-pattern</span>></span>/<span class="hljs-tag"></<span class="hljs-name">url-pattern</span>></span> <span class="hljs-tag"></<span class="hljs-name">servlet-mapping</span>></span><span class="hljs-tag"></<span class="hljs-name">web-app</span>></span></code></div></pre><pre><div class="hljs"><code class="lang-xml"><span class="php"><span class="hljs-meta"><?</span>xml version=<span class="hljs-string">"1.0"</span> encoding=<span class="hljs-string">"UTF-8"</span><span class="hljs-meta">?></span></span><span class="hljs-tag"><<span class="hljs-name">beans</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.springframework.org/schema/beans"</span> <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">"http://www.w3.org/2001/XMLSchema-instance"</span> <span class="hljs-attr">xmlns:context</span>=<span class="hljs-string">"http://www.springframework.org/schema/context"</span> <span class="hljs-attr">xmlns:mvc</span>=<span class="hljs-string">"http://www.springframework.org/schema/mvc"</span> <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd"</span>></span> <span class="hljs-comment"><!-- 自动扫描包,实现支持注解的IOC --></span> <span class="hljs-tag"><<span class="hljs-name">context:component-scan</span> <span class="hljs-attr">base-package</span>=<span class="hljs-string">"com.xxx.xxx"</span> /></span> <span class="hljs-comment"><!-- Spring MVC不处理静态资源 --></span> <span class="hljs-tag"><<span class="hljs-name">mvc:default-servlet-handler</span> /></span> <span class="hljs-comment"><!-- 支持mvc注解驱动 --></span> <span class="hljs-tag"><<span class="hljs-name">mvc:annotation-driven</span> /></span> <span class="hljs-comment"><!-- 视图解析器 --></span> <span class="hljs-tag"><<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"org.springframework.web.servlet.view.InternalResourceViewResolver"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"internalResourceViewResolver"</span>></span> <span class="hljs-comment"><!-- 前缀 --></span> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"prefix"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"/WEB-INF/view/"</span> /></span> <span class="hljs-comment"><!-- 后缀 --></span> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"suffix"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">".jsp"</span> /></span> <span class="hljs-tag"></<span class="hljs-name">bean</span>></span><span class="hljs-tag"></<span class="hljs-name">beans</span>></span></code></div></pre><p>Initializer类</p><pre><code class="lang-">public class MyWebAppInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext container) { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.setConfigLocation("com.xxx.xxx"); container.addListener(new ContextLoaderListener(context)); ServletRegistration.Dynamic dispatcher = container .addServlet("dispatcher", new DispatcherServlet(context)); dispatcher.setLoadOnStartup(1); dispatcher.addMapping("/"); }}</code></pre><p>还需要将@EnableWebMvc注释添加到@Configuration类,并定义一个视图解析器来解析从控制器返回的视图:</p><pre><code class="lang-">@EnableWebMvc@Configurationpublic class ClientWebConfig implements WebMvcConfigurer { @Bean public ViewResolver viewResolver() { InternalResourceViewResolver bean = new InternalResourceViewResolver(); bean.setViewClass(JstlView.class); bean.setPrefix("/WEB-INF/view/"); bean.setSuffix(".jsp"); return bean; }}</code></pre><p>再来看SpringBoot一旦我们添加了Web启动程序,Spring Boot只需要在application配置文件中配置几个属性来完成如上操作:</p><pre><code class="lang-">spring.mvc.view.prefix=/WEB-INF/jsp/spring.mvc.view.suffix=.jsp</code></pre><p>上面的所有Spring配置都是通过一个名为auto-configuration的过程添加Boot web starter来自动包含的。</p><p>这意味着Spring Boot将查看应用程序中存在的依赖项,属性和bean,并根据这些依赖项,对属性和bean进行配置。当然,如果我们想要添加自己的自定义配置,那么Spring Boot自动配置将会退回。</p><h3 id="配置模板引擎"><a href="#配置模板引擎" class="headerlink" title="配置模板引擎"></a>配置模板引擎</h3><p>现在我们来看下如何在Spring和Spring Boot中配置Thymeleaf模板引擎。</p><p>在Spring中,我们需要为视图解析器添加thymeleaf-spring5依赖项和一些配置:</p><pre><code class="lang-">@Configuration@EnableWebMvcpublic class MvcWebConfig implements WebMvcConfigurer { @Autowired private ApplicationContext applicationContext; @Bean public SpringResourceTemplateResolver templateResolver() { SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); templateResolver.setApplicationContext(applicationContext); templateResolver.setPrefix("/WEB-INF/views/"); templateResolver.setSuffix(".html"); return templateResolver; } @Bean public SpringTemplateEngine templateEngine() { SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver()); templateEngine.setEnableSpringELCompiler(true); return templateEngine; } @Override public void configureViewResolvers(ViewResolverRegistry registry) { ThymeleafViewResolver resolver = new ThymeleafViewResolver(); resolver.setTemplateEngine(templateEngine()); registry.viewResolver(resolver); }}</code></pre><p><strong>SpringBoot1X只需要spring-boot-starter-thymeleaf的依赖项来启用Web应用程序中的Thymeleaf支持。<br />但是由于Thymeleaf3.0中的新功能,我们必须将thymeleaf-layout-dialect 添加为SpringBoot2XWeb应用程序中的依赖项。配置好依赖,我们就可以将模板添加到src/main/resources/templates文件夹中,SpringBoot将自动显示它们。</strong></p><h3 id="应用程序启动引导配置"><a href="#应用程序启动引导配置" class="headerlink" title="应用程序启动引导配置"></a>应用程序启动引导配置</h3><p><strong>Spring和Spring Boot中应用程序引导的基本区别在于servlet。<br />Spring使用web.xml 或SpringServletContainerInitializer作为其引导入口点。<br />Spring Boot仅使用Servlet 3功能来引导应用程序,下面让我们详细来了解下</strong></p><p>Spring 引导配置</p><p>Spring支持传统的web.xml引导方式以及最新的Servlet 3+方法。</p><p>配置web.xml方法启动的步骤</p><ol><li>Servlet容器(服务器)读取web.xml</li><li>web.xml中定义的DispatcherServlet由容器实例化</li><li>DispatcherServlet通过读取WEB-INF / {servletName} -servlet.xml来创建WebApplicationContext。最后,DispatcherServlet注册在应用程序上下文中定义的bean</li></ol><p>使用Servlet 3+方法的Spring启动步骤</p><p><strong>容器搜索实现ServletContainerInitializer的类并执行SpringServletContainerInitializer找到实现所有类WebApplicationInitializer``WebApplicationInitializer创建具有XML或上下文@Configuration类WebApplicationInitializer创建DispatcherServlet与先前创建的上下文。</strong></p><p>SpringBoot 引导配置</p><p>Spring Boot应用程序的入口点是使用@SpringBootApplication注释的类</p><pre><code class="lang-">@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}</code></pre><p>默认情况下,Spring Boot使用嵌入式容器来运行应用程序。在这种情况下,Spring Boot使用public static void main入口点来启动嵌入式Web服务器。此外,它还负责将Servlet,Filter和ServletContextInitializer bean从应用程序上下文绑定到嵌入式servlet容器。<br />Spring Boot的另一个特性是它会自动扫描同一个包中的所有类或Main类的子包中的组件。</p><p>Spring Boot提供了将其部署到外部容器的方式。我们只需要扩展SpringBootServletInitializer即可:</p><pre><code class="lang-">/** * War部署 * * @author SanLi * Created by [email protected] on 2018/4/15 */public class ServletInitializer extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(Application.class); } @Override public void onStartup(ServletContext servletContext) throws ServletException { super.onStartup(servletContext); servletContext.addListener(new HttpSessionEventPublisher()); }}</code></pre><p>这里外部servlet容器查找在war包下的META-INF文件夹下MANIFEST.MF文件中定义的Main-class,SpringBootServletInitializer将负责绑定Servlet,Filter和ServletContextInitializer。</p></div><div class="story post-story"><h2 id="打包和部署"><a href="#打包和部署" class="headerlink" title="打包和部署"></a>打包和部署</h2><p>最后,让我们看看如何打包和部署应用程序。这两个框架都支持Maven和Gradle等通用包管理技术。但是在部署方面,这些框架差异很大。例如,Spring Boot Maven插件在Maven中提供Spring Boot支持。它还允许打包可执行jar或war包并就地运行应用程序。</p><p>在部署环境中Spring Boot 对比Spring的一些优点包括:</p><ul><li>提供嵌入式容器支持</li><li>使用命令java -jar独立运行jar</li><li>在外部容器中部署时,可以选择排除依赖关系以避免潜在的jar冲突</li><li>部署时灵活指定配置文件的选项</li><li>用于集成测试的随机端口生成</li></ul></div><div class="story post-story"><h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><p>简而言之,我们可以说Spring Boot只是Spring本身的扩展,使开发,测试和部署更加方便。</p><br><p>转载:<a href="https://www.jianshu.com/p/ffe5ebe17c3a" target="_blank">https://www.jianshu.com/p/ffe5ebe17c3a</a></p></div>]]></content>
<summary type="html">我们可以说Spring Boot只是Spring本身的扩展,使开发,测试和部署更加方便,但面试这么回答面试官不答应的...。</summary>
<category term="面试题" scheme="http://www.aquestian.cn/categories/%E9%9D%A2%E8%AF%95%E9%A2%98/"/>
<category term="SpringBoot" scheme="http://www.aquestian.cn/tags/springboot/"/>
<category term="Spring" scheme="http://www.aquestian.cn/tags/spring/"/>
</entry>
<entry>
<title>Linux服务器启动后自动启动Jar包</title>
<link href="http://www.aquestian.cn/blogs/Linux-Start-Jar/"/>
<id>http://www.aquestian.cn/blogs/Linux-Start-Jar/</id>
<published>2021-06-27T16:00:00.000Z</published>
<updated>2021-06-27T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><div class="story post-story"><h2 id="在任意一个路径中创建startup-sh"><a href="#在任意一个路径中创建startup-sh" class="headerlink" title="在任意一个路径中创建startup.sh"></a>在任意一个路径中创建startup.sh</h2></h2><h3 id="创建startup-sh"><a href="#创建startup-sh" class="headerlink" title="创建startup.sh"></a>创建startup.sh</h3><p>vim /home/startup.sh # 将环境配置写进去 不清楚自己配置的可以用 more /etc/profile 在最下方查看</p><p><img src="https://img-blog.csdnimg.cn/6e3a5160c9e74411bdacdf40d1d44989.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA562UIOahiA==,size_20,color_FFFFFF,t_70,g_se,x_16" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/6e3a5160c9e74411bdacdf40d1d44989.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA562UIOahiA==,size_20,color_FFFFFF,t_70,g_se,x_16" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="https://img-blog.csdnimg.cn/6e3a5160c9e74411bdacdf40d1d44989.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA562UIOahiA==,size_20,color_FFFFFF,t_70,g_se,x_16" /></p><p>脚本如下:</p><blockquote><p>#将环境配置写进去 不清楚自己配置的可以用 more /etc/profile查看<br />JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.232.b09-0.el7_7.x86_64<br />PATH=$PATH:$JAVA_HOME/bin </br><br />#服务器启动10秒后运行<br />sleep 10s </br><br />#jar包启动命令 找到jar包对应路径<br />nohup java -jar /gbq/boot-gbq-web-0.0.1-SNAPSHOT.jar >/gbq/daan.log 2>1&</p></blockquote><h3 id="给startup-sh添加权限"><a href="#给startup-sh添加权限" class="headerlink" title="给startup.sh添加权限"></a>给startup.sh添加权限</h3><p>chmod +x /home/startup.sh</p><h3>添加开机启动</h3><p>vim /etc/rc.local</p><p>在rc.local中加上一行</p><p>/home/startup.sh</p><p>添加完之后可以reboot重启服务器,之后再使用ps -ef | grep java查看是否启动成功</p><p><strong>为啥会在服务器启动10秒之后才执行这个脚本</strong><br>有一些环境如Docker搭建的环境,Docker服务也是需要时间启动,包括内部容器等,等它们启动完成后再启动Jar包,这样可以确保Jar包启动时环境都已经存在。</p></div>]]></content>
<summary type="html">Linux服务器启动后自动启动Jar包。</summary>
<category term="Linux" scheme="http://www.aquestian.cn/categories/linux/"/>
<category term="Linux" scheme="http://www.aquestian.cn/tags/linux/"/>
</entry>
<entry>
<title>Docker搭建SqlServer2017</title>
<link href="http://www.aquestian.cn/blogs/Docker-SqlServer2017/"/>
<id>http://www.aquestian.cn/blogs/Docker-SqlServer2017/</id>
<published>2021-06-10T16:00:00.000Z</published>
<updated>2021-06-10T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><div class="story post-story"><h2 id="前提条件"><a href="#前提条件" class="headerlink" title="前提条件"></a>前提条件</h2><p>前提条件(至少2 GB的磁盘空间。至少2 GB的RAM)。<br />详见:<a href="https://docs.microsoft.com/zh-cn/sql/linux/sql-server-linux-docker-container-deployment?view=sql-server-ver15&pivots=cs1-bash" target="_blank">https://docs.microsoft.com/zh-cn/sql/linux/sql-server-linux-docker-container-deployment?view=sql-server-ver15&pivots=cs1-bash</a></p></div><div class="story post-story"><h2 id="安装部署"><a href="#安装部署" class="headerlink" title="安装部署"></a>安装部署</h2><p>拉取镜像</p><pre><code>docker pull mcr.microsoft.com/mssql/server:2017-latest</code></pre><p>运行镜像</p><pre><code>docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=MyPassWord123" -p 1433:1433 --name sql1 -d mcr.microsoft.com/mssql/server:2017-latest</code></pre><p>这里设置了密码为MyPassWord123<br />查看镜像是否启动成功</p><pre><code>docker ps</code></pre></div>]]></content>
<summary type="html">Docker搭建SqlServer2017,2017以下版本不支持。</summary>
<category term="Docker" scheme="http://www.aquestian.cn/categories/docker/"/>
<category term="Docker" scheme="http://www.aquestian.cn/tags/docker/"/>
<category term="SqlServer" scheme="http://www.aquestian.cn/tags/sqlserver/"/>
</entry>
<entry>
<title>在Window上彻底卸载Docker</title>
<link href="http://www.aquestian.cn/blogs/Windows-Delete-Docker/"/>
<id>http://www.aquestian.cn/blogs/Windows-Delete-Docker/</id>
<published>2021-05-16T16:00:00.000Z</published>
<updated>2021-05-16T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><blockquote><p>在windows10上卸载docker后再重装会提示已安装,但之前已经卸载了,为什么还是会这样提示呢?<br />是因为docker卸载之后并没有将注册表信息删掉,所以在重装的时候还是会索引到的。<br />下面告诉大家一个卸载干净的方法</p></blockquote><div class="story post-story"><h2 id="新建一个-a-ps1-的文件"><a href="#新建一个-a-ps1-的文件" class="headerlink" title="新建一个 a.ps1 的文件"></a>新建一个 a.ps1 的文件</h2><pre><code class="lang-">$ErrorActionPreference = "SilentlyContinue"kill -force -processname 'Docker for Windows', com.docker.db, vpnkit, com.docker.proxy, com.docker.9pdb, moby-diag-dl, dockerdtry {<br />./MobyLinux.ps1 -Destroy<br />} Catch {}service = Get-WmiObject -Class Win32_Service -Filter "Name='com.docker.service'"if (service) { service.StopService() }if (service) { $service.Delete() }<br />Start-Sleep -s 5<br />Remove-Item -Recurse -Force “~/AppData/Local/Docker”<br />Remove-Item -Recurse -Force “~/AppData/Roaming/Docker”<br />if (Test-Path “C:\ProgramData\Docker”) { takeown.exe /F “C:\ProgramData\Docker” /R /A /D Y }<br />if (Test-Path “C:\ProgramData\Docker”) { icacls "C:\ProgramData\Docker&quot; /T /C /grant Administrators:F }<br />Remove-Item -Recurse -Force “C:\ProgramData\Docker”<br />Remove-Item -Recurse -Force “C:\Program Files\Docker”<br />Remove-Item -Recurse -Force “C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Docker”<br />Remove-Item -Force “C:\Users\Public\Desktop\Docker for Windows.lnk”<br />Get-ChildItem HKLM:\software\microsoft\windows\currentversion\uninstall | % {Get-ItemProperty $<em>.PSPath} | ? { $</em>.DisplayName -eq “Docker” } | Remove-Item -Recurse -Force<br />Get-ChildItem HKLM:\software\classes\installer\products | % {Get-ItemProperty $<em>.pspath} | ? { $</em>.ProductName -eq “Docker” } | Remove-Item -Recurse -Force<br />Get-Item ‘HKLM:\software\Docker Inc.’ | Remove-Item -Recurse -Force<br />Get-ItemProperty HKCU:\software\microsoft\windows\currentversion\Run -name “Docker for Windows” | Remove-Item -Recurse -Force<br />#Get-ItemProperty HKCU:\software\microsoft\windows\currentversion\UFH\SHC | ForEach-Object {Get-ItemProperty $<em>.PSPath} | Where-Object { $</em>.ToString().Contains(“Docker for Windows.exe”) } | Remove-Item -Recurse -Force $<em>.PSPath<br />#Get-ItemProperty HKCU:\software\microsoft\windows\currentversion\UFH\SHC | Where-Object { $(Get-ItemPropertyValue $</em>) -Contains “Docker” }<br /></code></pre></p></div><div class="story post-story"><h2 id="执行a-ps1"><a href="#执行a-ps1" class="headerlink" title="执行a.ps1"></a>执行a.ps1</h2><p>将以上内容写进去,然后以管理员身份打开powershell ,并执行</p><pre><code class="lang-">./a.ps1</code></pre><p>如果提示如下错误:<br /><img src="https://double.aquestian.cn/blog/2021-08-28-08-34-17-dockerdel-1.png" class="lazyload" data-srcset="https://double.aquestian.cn/blog/2021-08-28-08-34-17-dockerdel-1.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /><br />执行</p><pre><code class="lang-">set-executionpolicy remotesigned</code></pre><p><img src="https://double.aquestian.cn/blog/2021-08-28-08-36-38-dockerdel-2.png" class="lazyload" data-srcset="https://double.aquestian.cn/blog/2021-08-28-08-36-38-dockerdel-2.png" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p><p>再次执行a.ps1,成功删除。</p></div>]]></content>
<summary type="html">Window上彻底卸载Docker,本文在Window10、11基础上操作。</summary>
<category term="Docker" scheme="http://www.aquestian.cn/categories/docker/"/>
<category term="Docker" scheme="http://www.aquestian.cn/tags/docker/"/>
</entry>
<entry>
<title>springboot校园社团管理系统源码分享</title>
<link href="http://www.aquestian.cn/code/Code-Seven/"/>
<id>http://www.aquestian.cn/code/Code-Seven/</id>
<published>2021-04-22T16:00:00.000Z</published>
<updated>2021-04-22T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><div class="story post-story"><h2 id="项目描述"><a href="#项目描述" class="headerlink" title="项目描述"></a>项目描述</h2><p>springboot校园社团管理系统源码分享,前端使用layui.js,后端使用springboot+mybatis。</p></div><div class="story post-story"><h2 id="运行环境"><a href="#运行环境" class="headerlink" title="运行环境"></a>运行环境</h2><p>jdk8+tomcat8+mysql5.7+IntelliJ IDEA+maven</p></div><div class="story post-story"><h2 id="项目技术"><a href="#项目技术" class="headerlink" title="项目技术"></a>项目技术</h2><p>spring boot+spring mvc+mybatis+jquery+layui</p></div><div class="story post-story"><h2 id="项目截图"><a href="#项目截图" class="headerlink" title="项目截图"></a>项目截图</h2><p><img style="width:450px;height:900px" src="https://img-blog.csdnimg.cn/20200909135739888.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_13,color_FFFFFF,t_40" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200909135739888.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_13,color_FFFFFF,t_40" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p></div><div class="story post-story"><h2 id="运行截图"><a href="#运行截图" class="headerlink" title="运行截图"></a>运行截图</h2><p>localhost:8080 下边为部分截图<br /><img style="width:500px;height:400px" src="https://img-blog.csdnimg.cn/20200909135901619.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_8,color_FFFFFF,t_20" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200909135901619.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_8,color_FFFFFF,t_20" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p><p><img src="https://img-blog.csdnimg.cn/20200909140256162.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_40" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200909140256162.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_40" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p><p><img src="https://img-blog.csdnimg.cn/2020090914052676.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_40" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/2020090914052676.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_40" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p><p><img src="https://img-blog.csdnimg.cn/20200909140622278.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_40" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200909140622278.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_40" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p><p><img src="https://img-blog.csdnimg.cn/20200909140714446.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_40" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200909140714446.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_40" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" /></p></div>]]></content>
<summary type="html">springboot校园社团管理系统源码分享,前端使用layui.js,后端使用springboot+mybatis。</summary>
<category term="源码分享" scheme="http://www.aquestian.cn/categories/%E6%BA%90%E7%A0%81%E5%88%86%E4%BA%AB/"/>
<category term="源码分享" scheme="http://www.aquestian.cn/tags/%E6%BA%90%E7%A0%81%E5%88%86%E4%BA%AB/"/>
</entry>
<entry>
<title>SpringCloud 学习——网关服务Zuul</title>
<link href="http://www.aquestian.cn/blogs/SpringCould-Zuul/"/>
<id>http://www.aquestian.cn/blogs/SpringCould-Zuul/</id>
<published>2021-04-19T16:00:00.000Z</published>
<updated>2021-04-19T16:00:00.000Z</updated>
<content type="html"><![CDATA[<meta name="referrer" content="no-referrer" /><div class="story post-story"><h2 id="Spring-Cloud-Zuul介绍"><a href="#Spring-Cloud-Zuul介绍" class="headerlink" title="Spring Cloud Zuul介绍"></a>Spring Cloud Zuul介绍</h2><p>Zuul是Netflix开源的微服务网关,可以和Eureka、Ribbon、Hystrix等组件配合使用,Spring Cloud对Zuul进行了整合与增强,Zuul默认使用的HTTP客户端是Apache HTTPClient,也可以使用RestClient或okhttp3.OkHttpClient。 <strong>Zuul的主要功能是路由转发和过滤器</strong>。路由功能是微服务的一部分,如下图所示,/test/*转发到到demo服务。zuul默认和Ribbon结合实现了负载均衡的功能.。</p><p><img src="https://img-blog.csdnimg.cn/20200331140854143.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200331140854143.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="https://img-blog.csdnimg.cn/20200331140854143.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" /></p><p>Zuul使用一系列不同类型的过滤器,使我们能够快速灵活地将功能应用于我们的边缘服务。这些过滤器可帮助我们执行以下功能</p><ol><li>身份验证和安全性 - 确定每个资源的身份验证要求并拒绝不满足这些要求的请求</li><li>洞察和监控 - 在边缘跟踪有意义的数据和统计数据,以便为我们提供准确的生产视图</li><li>动态路由 - 根据需要动态地将请求路由到不同的后端群集</li><li>压力测试 - 逐渐增加群集的流量以衡量性能。</li><li>Load Shedding - 为每种类型的请求分配容量并删除超过限制的请求静态响应处理 - 直接在边缘构建一些响应,而不是将它们转发到内部集群</li></ol></div><div class="story post-story"><h2 id="Zuul实现路由转发和过滤器"><a href="#Zuul实现路由转发和过滤器" class="headerlink" title="Zuul实现路由转发和过滤器"></a>Zuul实现路由转发和过滤器</h2><h3 id="consumer-zuul子项目搭建"><a href="#consumer-zuul子项目搭建" class="headerlink" title="consumer-zuul子项目搭建"></a>consumer-zuul子项目搭建</h3><p>继续在之前的聚合工程中创建子项目,consumer-zuul</p><p>项目结构</p><p><img src="https://img-blog.csdnimg.cn/20200331141340342.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200331141340342.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="https://img-blog.csdnimg.cn/20200331141340342.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" /></p><p>pom文件</p><p>只需要引入zuul包即可</p><pre><code class="lang-"> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency></code></pre><p>yml配置</p><pre><code class="lang-">server: port: 13000eureka: client: service-url: defaultZone: http://eureka01:8800/eureka/,http://eureka02:8810/eureka/<p>#构建路由地址<br>zuul:<br>routes:<br>#这里可以自定义<br>demo1:<br>#匹配的路由规则<br>path: /consumer-zuul-a/**<br>#路由的目标服务名<br>serviceId: provider<br>demo2:<br>#匹配的路由规则<br>path: /consumer-zuul-b/**<br>#路由的目标服务名<br>serviceId: consumer-feign</p><p>spring:<br>application:<br>name: consumer-zuul<br>main:<br>allow-bean-definition-overriding: true<br></code></pre></p><p>启动类</p><p>加入注解 @EnableZuulProxy</p><pre><code class="lang-">@SpringBootApplication@EnableZuulProxypublic class ConsumerZuulApplication { public static void main(String[] args) { SpringApplication.run(ConsumerZuulApplication.class, args); }}</code></pre><p>启动<br />同时启动yml对应的服务</p><p><img src="https://img-blog.csdnimg.cn/20200331141911655.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200331141911655.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="https://img-blog.csdnimg.cn/20200331141911655.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" /></p></div><div class="story post-story"><h2 id="Zuul实现过滤器"><a href="#Zuul实现过滤器" class="headerlink" title="Zuul实现过滤器"></a>Zuul实现过滤器</h2><p>ServiceFilter类</p><pre><code class="lang-">@Componentpublic class ServiceFilter extends ZuulFilter { @Override public String filterType() { //filterType 为过滤类型,可选值有 pre(路由之前)、routing(路由之时)、post(路由之后)、error(发生错误时调用)。 return "pre"; } @Override public int filterOrder() { //filterOrdery 为过滤的顺序,如果有多个过滤器,则数字越小越先执行 return 0; } @Override public boolean shouldFilter() { //shouldFilter 表示是否过滤,这里可以做逻辑判断,true 为过滤,false 不过滤 return true; } @Override public Object run() throws ZuulException { //run 为过滤器执行的具体逻辑,在这里可以做很多事情,比如:权限判断、合法性校验等。 //这里写校验代码 RequestContext context = RequestContext.getCurrentContext(); HttpServletRequest request = context.getRequest(); String name = request.getParameter("name"); if(!"12345".equals(name)){ context.setSendZuulResponse(false); context.setResponseStatusCode(401); try { context.getResponse().setCharacterEncoding("UTF-8"); context.getResponse().getWriter().write("名字错了"); }catch (Exception e){} } return null; }}</code></pre><p>运行</p><p><img src="https://img-blog.csdnimg.cn/20200331142312338.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" class="lazyload" data-srcset="https://img-blog.csdnimg.cn/20200331142312338.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="https://img-blog.csdnimg.cn/20200331142312338.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzU3MjQy,size_16,color_FFFFFF,t_70" /></p></div>]]></content>
<summary type="html">Spring Cloud 学习——网关服务Zuul</summary>
<category term="SpringCloud" scheme="http://www.aquestian.cn/categories/springcloud/"/>
<category term="SpringCloud" scheme="http://www.aquestian.cn/tags/springcloud/"/>
<category term="Zuul" scheme="http://www.aquestian.cn/tags/zuul/"/>
</entry>
</feed>