-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
1255 lines (1141 loc) · 114 KB
/
Copy pathatom.xml
File metadata and controls
1255 lines (1141 loc) · 114 KB
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
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>terrence mu's blog</title>
<link href="/atom.xml" rel="self"/>
<link href="http://yoursite.com/"/>
<updated>2018-02-25T15:04:47.000Z</updated>
<id>http://yoursite.com/</id>
<author>
<name>terrence mu</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>Spring boot in Action 笔记</title>
<link href="http://yoursite.com/2018/02/18/springbootinaction/"/>
<id>http://yoursite.com/2018/02/18/springbootinaction/</id>
<published>2018-02-18T02:18:50.000Z</published>
<updated>2018-02-25T15:04:47.000Z</updated>
<content type="html"><![CDATA[<h5 id="Spring-boot-提供的四个核心功能"><a href="#Spring-boot-提供的四个核心功能" class="headerlink" title="Spring boot 提供的四个核心功能"></a>Spring boot 提供的四个核心功能</h5><ul>
<li>auto config - 声明式的标识,如@Bean来实现实例的自动注入。</li>
<li>starter pom - 利用maven的传递依赖,组合常用的库。避免了多个库之间的存在的可能不兼容问题。</li>
<li>命令行界面 - Spring boot CLI</li>
<li>Actuator 提供如应用程序运行时内部运行的监控</li>
</ul>
<p>Spring boot CLI命令初始化项目: spring init -dweb,jpa,security - -build maven -p war -x</p>
<p>-d后面跟依赖的信息。把CLI生成的项目解压到当前目录,使用 - - extract 或者 -x参数。</p>
<p>spring help init 查看帮助</p>
<p>sping init -l 列出init参数</p>
<h5 id="Spring-boot-自动配置"><a href="#Spring-boot-自动配置" class="headerlink" title="Spring boot 自动配置"></a>Spring boot 自动配置</h5><p>@ConditionalOnMissingBean注解,可以用于覆盖自动配置。</p>
<p>如@ConditionalOnMissingBean(ABC.class)如果当前不存在ABC类型,添加该注解的bean就会生效。</p>
<p>Spring Boot能从多种属性源获得属性,具体如下,优先级从高到低,</p>
<ul>
<li>命令行参数 </li>
<li>java:comp/env里的JNDI属性 </li>
<li>JVM系统属性 </li>
<li>操作系统环境变量</li>
<li>随机生成的带random.*前缀的属性(在设置其他属性时,可以引用它们,比如${random. long}) </li>
<li>应用程序以外的application.properties或者appliaction.yml文件 </li>
<li>打包在应用程序内的application.properties或者appliaction.yml文件 </li>
<li>通过@PropertySource标注的属性源 </li>
</ul>
<p>application.properties和application.yml文件能放在以下四个位置,优先级从高到低 </p>
<ul>
<li>外置,在相对于应用程序运行目录的/config子目录里。 </li>
<li>外置,在应用程序运行的目录里。 </li>
<li>内置,在config包内。 </li>
<li>内置,在Classpath根目录。<br>另外,如果你在同一优先级位置同时有application.properties和application.yml,那么application.yml里的属性会覆盖application.properties里的属性。</li>
</ul>
<p>Spring boot默认的系统是logback,如果需要用别的日志系统,需要在starter中排除掉自动依赖,再重新单独引入。</p>
<pre><code><dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
</code></pre><p>如引入log4j</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><dependency></div><div class="line"> <groupId>org.springframework.boot</groupId></div><div class="line"> <artifactId>spring-boot-starter-log4j</artifactId></div><div class="line"></dependency></div></pre></td></tr></table></figure>
<p>Spring boot 官方提供的starter</p>
<p>Spring-boot-starter SpringBoot核心Starter,包含自动配置,日志,yaml配置文件的支持。</p>
<p>Spring-boot-starter-actuator 准生产特性,用来监控和管理应用</p>
<p>Spring-boot-starter-remote-shell 提供SSH协议的监控和管理</p>
<p>Spring-boot-starter-remote-amqp 使用Spring-rabbit对AMQP协议支持</p>
<p>Spring-boot-starter-remote-aop 使用Spring-aop和AspectJ面向切面编程支持</p>
<p>Spring-boot-starter-remote-batch Spring batch的支持</p>
<p>Spring-boot-starter-cloud-connectors 对云平台提供服务提供简化的连接方式</p>
<p>Spring-boot-starter-data-elasitcsearch 通过spring-data-elasticsearch对elasticsearch支持</p>
<p>Spring-boot-starter-data-gemfire 通过spring-data-gemfire 对gemfire 支持</p>
<p>Spring-boot-starter-data-jpa 对 JPA支持,包含spring-data-jpa,spring-orm和Hibernate</p>
<p>Spring-boot-starter-data-mangodb 通过spring-data-mangoDB 对mangoDB支持</p>
<p>Spring-boot-starter-data-rest 通过spring-data-rest-webmvc 对spring data repositoty暴露未REST形式的服务</p>
<p>Spring-boot-starter-data-solr 通过spring-data-solr对apache solr数据检索平台的支持</p>
<p>Spring-boot-starter-freemaker 对freemaker模板引擎的支持</p>
<p>Spring-boot-starter-groovy-templates 对Groovy模板引擎的支持</p>
<p>Spring-boot-starter-hateoas 通过spring-hateoas对基于HATEOAS的REST形式的网络服务的支持</p>
<p>Spring-boot-starter-hornetq 通过HornetQ对JMS的支持</p>
<p>Spring-boot-starter-integration 对系统继承框架spring-integeration的支持</p>
<p>Spring-boot-starter-jdbc 对JDBC数据库的支持</p>
<p>Spring-boot-starter-jersey 对Jersey REST形式的网络服务的支持</p>
<p>Spring-boot-starter-atomikos 通过Atomikos对分布式事务的支持</p>
<p>Spring-boot-starter-bitronix 通过Bitronix对分布式事务的支持</p>
<p>Spring-boot-starter-mail 对javax.mail的支持</p>
<p>Spring-boot-starter-mobile 对spring-mobile的支持</p>
<p>Spring-boot-starter-mustache 对Mustache模板引擎的支持</p>
<p>Spring-boot-starter-redis 对键值对内存数据库redis的支持,包含spring-redis</p>
<p>Spring-boot-starter-security 对spring-security的支持</p>
<p>Spring-boot-starter-social-facebook 通过 Spring-social-facebook对facebook的支持</p>
<p>Spring-boot-starter-social-linkin 通过 Spring-social-linkin对linkin的支持</p>
<p>Spring-boot-starter-social-twitter 通过 Spring-social-twitter对twitter的支持</p>
<p>Spring-boot-starter-test 对常用测试框架Junit,Hamcrest和mokito的支持,包含spring-test模块</p>
<p>Spring-boot-starter-thymeleaf 对thymeleaf模板引擎的支持</p>
<p>Spring-boot-starter-velocity 对velocity模板引擎的支持</p>
<p>Spring-boot-starter-web 对web项目开发的支持,包含tomcat和spring-webmvc</p>
<p>Spring-boot-starter-Tomcat spring boot默认的servlet容器Tomcat</p>
<p>Spring-boot-starter-Jetty 使用Jetty作为servlet容器替换tomcat</p>
<p>Spring-boot-starter-Undertow 使用undertow作为servlet容器替换tomcat</p>
<p>Spring-boot-starter-logging spingboot 默认支持日志框架logback</p>
<p>Spring-boot-starter-log4j 对log4j的支持</p>
<p>Spring-boot-starter-websocket 对websocket的支持</p>
<p>Spring-boot-starter-ws 对spring web services的支持</p>
<p>@ConfigurationProperties可以获取application.properties中的数据,通过prefix属性指定properties的配置的前缀。具体可以参见ConfigurationProperties的源码。</p>
<p>通过logging.file=日志目录,logging.level.包名=日志级别</p>
<p>application-{profile}.properties 中的profile用于不同环境的配置。可以在application.properties中设置spring.profiles.active=prod来指定活动的Profile。</p>
<h5 id="Spring-boot-运行原理"><a href="#Spring-boot-运行原理" class="headerlink" title="Spring boot 运行原理"></a>Spring boot 运行原理</h5><p>核心功能是由@EnableAutoConfiguration提供的。它由AutoConfigurationImportSelector通过SpringFactoriesLoader.loadFactoryNames来获取META-INF/spring.factories下的jar包。具体如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div></pre></td><td class="code"><pre><div class="line"># PropertySource Loaders</div><div class="line">org.springframework.boot.env.PropertySourceLoader=\</div><div class="line">org.springframework.boot.env.PropertiesPropertySourceLoader,\</div><div class="line">org.springframework.boot.env.YamlPropertySourceLoader</div><div class="line"></div><div class="line"># Run Listeners</div><div class="line">org.springframework.boot.SpringApplicationRunListener=\</div><div class="line">org.springframework.boot.context.event.EventPublishingRunListener</div><div class="line"></div><div class="line"># Application Context Initializers</div><div class="line">org.springframework.context.ApplicationContextInitializer=\</div><div class="line">org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\</div><div class="line">org.springframework.boot.context.ContextIdApplicationContextInitializer,\</div><div class="line">org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\</div><div class="line">org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer</div><div class="line"></div><div class="line"># Application Listeners</div><div class="line">org.springframework.context.ApplicationListener=\</div><div class="line">org.springframework.boot.ClearCachesApplicationListener,\</div><div class="line">org.springframework.boot.builder.ParentContextCloserApplicationListener,\</div><div class="line">org.springframework.boot.context.FileEncodingApplicationListener,\</div><div class="line">org.springframework.boot.context.config.AnsiOutputApplicationListener,\</div><div class="line">org.springframework.boot.context.config.ConfigFileApplicationListener,\</div><div class="line">org.springframework.boot.context.config.DelegatingApplicationListener,\</div><div class="line">org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\</div><div class="line">org.springframework.boot.logging.ClasspathLoggingApplicationListener,\</div><div class="line">org.springframework.boot.logging.LoggingApplicationListener</div><div class="line"></div><div class="line"># Environment Post Processors</div><div class="line">org.springframework.boot.env.EnvironmentPostProcessor=\</div><div class="line">org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\</div><div class="line">org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor</div><div class="line"></div><div class="line"># Failure Analyzers</div><div class="line">org.springframework.boot.diagnostics.FailureAnalyzer=\</div><div class="line">org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\</div><div class="line">org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\</div><div class="line">org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\</div><div class="line">org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\</div><div class="line">org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\</div><div class="line">org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\</div><div class="line">org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer</div><div class="line"></div><div class="line"># FailureAnalysisReporters</div><div class="line">org.springframework.boot.diagnostics.FailureAnalysisReporter=\</div><div class="line">org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter</div></pre></td></tr></table></figure>
<h4 id="Web相关配置"><a href="#Web相关配置" class="headerlink" title="Web相关配置"></a>Web相关配置</h4><p>自动配置的ViewResolver</p>
<ul>
<li><p>ContentNegotiatingViewResolver</p>
<p>代理不同的viewResolver来处理不同的view,拥有最高的优先级。</p>
</li>
<li><p>BeanNameViewResolver</p>
<p>会查找对应的Bean名称来返回字符串的View渲染视图</p>
</li>
<li><p>InternalResourceViewResolver</p>
<p>通过设置前缀,后缀,以及控制器中的方法来返回视图名的字符串,已得到实际页面。</p>
</li>
</ul>
<p>自动配置静态资源,通过addResourceHandlers方法来定义。</p>
<p>在WebAutoConfigure中定义Formatter,Conveter,HttpMessageConverters。可以自定义HttpMessageConveter,通过@Bean的方式来定义。</p>
<p>替代Spring boot的MVC配置,定义一个配置类并继承WebMvcConfigurerAdapter。</p>
<p>@Configuration</p>
<p>public class WebMvcConfig extends WebMvcConfigureAdapter{</p>
<p> @Override </p>
<p> public void addViewControllers(ViewControllerRegistry registry){</p>
<p> registry.addViewController(“/xx”).setViewName(“/xx”);</p>
<p> }</p>
<p>}</p>
<h4 id="注册Servlet,Filter,Listener"><a href="#注册Servlet,Filter,Listener" class="headerlink" title="注册Servlet,Filter,Listener"></a>注册Servlet,Filter,Listener</h4><ul>
<li>直接声明Spring Bean的方式 @Bean</li>
<li>分别实例ServletRegistrationBean来注册servlet,FilterRegistrationBean注册Filter,ServletListenerRegistrationBean来注册Listener</li>
</ul>
<h4 id="代码配置Servlet容器"><a href="#代码配置Servlet容器" class="headerlink" title="代码配置Servlet容器"></a>代码配置Servlet容器</h4><p>可以实现一个EmbeddedServletContainerCustomizer接口的Bean,如果想直接配置Tomcat,Jetty或者Undertow,可以通过对应的定义来直接定义TomcatEmbeddedServletContainerFactory, JettyEmbeddedServletContainerFactory, UndertowEmbeddedServletContainerFactory。</p>
<h4 id="SSL配置"><a href="#SSL配置" class="headerlink" title="SSL配置"></a>SSL配置</h4><ul>
<li><p>生成证书</p>
<p>keytool生成自签名证书,输入命令keytool -genkey -alias tomcat,在当前目录生成一个.keystore文件。</p>
</li>
<li><p>添加配置</p>
<p>把.keystore复制到根目录,并配置</p>
<p>server.port = 8443</p>
<p>server.ssl.key-store=.keystore</p>
<p>server.ssl.key-store-password=111111</p>
<p>server.ssl.keyStoreType=JKS</p>
<p>server.ssl.keyAlias:tomcat</p>
</li>
<li><p>重定向HTTP到HTTPS</p>
<p>重新设置Http Connector Port 8080到8443。</p>
</li>
</ul>
<p>WebSocket支持,需要引入spring-boot-starter-websocket。</p>
<h4 id="Spring-Cache缓存"><a href="#Spring-Cache缓存" class="headerlink" title="Spring Cache缓存"></a>Spring Cache缓存</h4><ul>
<li>Spring支持CacheManager</li>
</ul>
<p>SimpleCacheManager — 使用简单的Collection来存储缓存,主要用来测试用途</p>
<p>ConcurrentMapCacheManager — 使用ConcurrentMap来存储缓存</p>
<p>NoOpCacheManager — 仅测试用途,不会实际存储操作</p>
<p>EhCacheManager, GuavaCacheManager, HazelcastCacheManager, JCacheCacheManager(支持JSR-107标准的实现), RedisCacheManager。</p>
<ul>
<li>声名式缓存注解</li>
</ul>
<p>@Cacheable 在方法执行前Spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据,若没有则写入。</p>
<p>@CachePut 无论如何都会把返回值写入到缓存</p>
<p>@CacheEvict 将一条或多条数据从缓存中删除</p>
<p>@Caching 可以通过@Caching注解组合多个注解策略在一个方法上</p>
<p>开启声明式缓存</p>
<p>@Configuration</p>
<p>@EnableCaching</p>
<p>public class AppConfig{}</p>
<p>Spring boot 默认使用SimpleCacheConfiguration,即使用ConcurrentMap来做缓存。Spring Boot支持以 spring.cache未前缀来配置缓存。</p>
<p>spring.cache.type=#可选 generic,ehcache,hazelcast,redis,guava,simple,none,infinispan,jcache等</p>
<p>spring.cache.cache-name=#程序启动创建缓存名称</p>
<p>spring.cache.guava.spec=#guava specs</p>
<p>Application上也可开启@EnableCaching。</p>
<h4 id="异步消息的支持"><a href="#异步消息的支持" class="headerlink" title="异步消息的支持"></a>异步消息的支持</h4><p>异步消息中两个很重要的概念,消息代理和目的地。目的地主要包含两种形式:队列和主题,队列用于点对点式的消息通信,主题用于发布/订阅式的消息通信。</p>
<p>Spring为JMS,AMQP提供了@JmsListener和@RabbitListner注解在方法上监听消息代理发布的消息,需要@EnableJms或者@EnableRabbit来开启。</p>
<p>ActiveMQConnectionFactoryFactory来配置ActiveMQ的Bean连接,并通过前缀为spring.activemq的属性来配置对应的参数。</p>
<p>Spring Integration提供基于Spring的EIP的实现,解决不同系统之间的交互问题,通过异步消息驱动来达到系统交互时的系统之间的松耦合。</p>
]]></content>
<summary type="html">
<h5 id="Spring-boot-提供的四个核心功能"><a href="#Spring-boot-提供的四个核心功能" class="headerlink" title="Spring boot 提供的四个核心功能"></a>Spring boot 提供的四个核心功能</
</summary>
<category term="spring boot" scheme="http://yoursite.com/tags/spring-boot/"/>
</entry>
<entry>
<title>Spring key point mark on</title>
<link href="http://yoursite.com/2018/01/29/springmark/"/>
<id>http://yoursite.com/2018/01/29/springmark/</id>
<published>2018-01-29T05:58:51.000Z</published>
<updated>2018-02-25T15:02:51.000Z</updated>
<content type="html"><![CDATA[<p>Spring & Spring boot related mark</p>
<h4 id="Event"><a href="#Event" class="headerlink" title="Event"></a>Event</h4><p>ApplicationEvent - create application event<br>ApplicationListener - listen application event<br>ApplicationContext 继承自 ApplicationEventPublisher - publish applicaton event</p>
<h4 id="Aware"><a href="#Aware" class="headerlink" title="Aware"></a>Aware</h4><p>BeanNameAware - 获取容器中BeanName</p>
<p>BeanFactoryAware - 获得当前bean factory</p>
<p>ApplicationContextAware - 当前的applicationContext,继承类ApplicationObjectSupport</p>
<p>MessageSourceAware - 获取MessageSource,获取文本信息</p>
<p>ApplicationEventPublisherAware - 应用事件发布器,发布事件</p>
<p>ResourceLoaderAware - 获取资源加载器,获取外部资源</p>
<h4 id="Conditional"><a href="#Conditional" class="headerlink" title="Conditional"></a>Conditional</h4><p>condition来match不同的条件,并进行不同的处理。</p>
<h4 id="组合注解"><a href="#组合注解" class="headerlink" title="组合注解"></a>组合注解</h4><p>将多个元注解合并,定义为组合注解,简化配置。</p>
<h4 id="Enable-注解"><a href="#Enable-注解" class="headerlink" title="Enable*注解"></a>Enable*注解</h4><p>@EnableAspectJAutoProxy开启对AspectJ自动代理的支持。</p>
<p>@EnableAsync开启异步方法的支持。</p>
<p>@EnableScheduling 开启计划任务的支持。</p>
<p>@EnableWebMvc开启Web MVC的支持</p>
<p>@EnableConfigurationProperties开启对@ConfigurationProperties注解配置Bean的支持。</p>
<p>@EnableJpaRepositories开启对Spring DataJPA Repository的支持。</p>
<p>@EnableTransactionManagement开启注解事务的支持。</p>
<p>@EnableCaching开启注解式的缓存支持。</p>
<p>所有Enable都包含一个@Import注解,用来导入配置类的。导入了一些自动配置的Bean。这些导入配置的方式主要分为三种类型:</p>
<ul>
<li>直接导入配置类</li>
<li>依据条件选择配置类</li>
<li>动态注册Bean</li>
</ul>
<p>servlet3.0可以通过webApplicationInitializer替代web.xml,实现该接口将会被SpringServletContainerInitializer获取到。</p>
<p>通过重写WebMvcCOnfigureAdapter的addInterceptors方法来注册自定义的拦截器。</p>
<p>@ControllerAdvice用于controller的全局配置,@ExceptionHandler 用于全局处理控制器的异常。</p>
<p>@InitBinder,用来设置WebDataBinder,WebDataBinder用来自动绑定前台请求参数到model中。</p>
<p>@ModelAttribute,绑定键值对到Model中,此处是让全局的@RequestMapping都能获得在此处设置的键值对。</p>
<p>Spring通过MultipartResolver来上传文件。</p>
<p>spring的消息推送</p>
<ol>
<li>RequestMapping中通过produces设置为「text/event-stream」来实现服务端往浏览器的消息推送。</li>
<li>servlet3.0的异步方式,setAsyncSupported为true。</li>
</ol>
<p>@SpringBootApplication 注解组合了@Configuration,@EnableAutoConfiguration,@ComponentScan,</p>
<p>可以通过exclude参数关闭特定的自动配置,如@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})</p>
<p>Banner定制src/main/resources下新建banner.txt。<a href="http://patorjk.com/software/taag生成字符。" target="_blank" rel="noopener">http://patorjk.com/software/taag生成字符。</a></p>
]]></content>
<summary type="html">
<p>Spring &amp; Spring boot related mark</p>
<h4 id="Event"><a href="#Event" class="headerlink" title="Event"></a>Event</h4><p>ApplicationEv
</summary>
<category term="spring, spring boot, key point" scheme="http://yoursite.com/tags/spring-spring-boot-key-point/"/>
</entry>
<entry>
<title>高性能MySQL 学习笔记</title>
<link href="http://yoursite.com/2017/10/28/mysqlstudy/"/>
<id>http://yoursite.com/2017/10/28/mysqlstudy/</id>
<published>2017-10-28T15:59:22.000Z</published>
<updated>2018-01-29T06:01:57.000Z</updated>
<content type="html"><![CDATA[<p>第一章 Mysql架构和历史</p>
<p>MySQL的两种基本锁</p>
<p>表锁和行级锁</p>
<ul>
<li><p>表锁<br>读锁互不排斥,写锁互斥。Mysql 服务器层会根据情况添加表锁,如ALTER TABLE操作。</p>
</li>
<li><p>行级锁<br>主要在数据库的InnoDB,XtraDB等存储引擎中实现。</p>
</li>
</ul>
<p>ACID</p>
<ul>
<li>原子性,一致性,隔离性,持久性。</li>
</ul>
<p>四种隔离级别</p>
<ul>
<li>READ UNCOMMITTED(未提交读)<br>事务中的修改,即使没提交,对其他事务也是可见的。事务未提交,其他事务也可以读取,即为脏读。</li>
<li>READ COMMITTED(提交读)<br>绝大多数数据库的默认隔离级别(MySQL不是)。一个事务的修改在未提交之前对其他事务是不可见的。也可以叫做不可重复读,即两次同样的查询,读取到的结果可能不一致。</li>
<li>REPEATABLE READ(可重复读)<br>可重复读保证了在同一事务中多次读取同样的查询,结果是一致的。它解决了脏读的问题。无法解决幻读的问题。可重复读是MySQL的默认隔离级别。幻读指的是某个事务在读取一定范围内的记录时,另一个事务在该范围内插入了新的记录,当这个事务再次读取时,会产生幻行的问题。InnoDB,XtraDB等引擎,通过多版本并发控制解决了幻读问题。</li>
<li><p>SERIALIZABLE(串行化)<br>强制事务串行执行,解决了幻读和脏读问题。一般性能太差,不会使用。</p>
<p>隔离级别 脏读可能性 不可重复读可能性 幻读可能性 加锁读<br>READ UNCOMMITTED YES YES YES NO<br>READ COMMITTED NO YES YES NO<br>REPEATABLE READ NO NO YES NO<br>SERIALIZABLE NO NO NO YES </p>
</li>
</ul>
<p>死锁</p>
<ul>
<li>死锁处理: InnoDB处理死锁的方式是将持有最少行级排他锁的事务回滚。</li>
</ul>
<p>MySQL中的事务</p>
<ul>
<li>MySQL提供的官方支持事务的引擎有InnoDB和NDB Cluster,第三方的有XtraDB和PBXT。-</li>
<li>MySQL默认采用AUTOCOMMIT模式,无显示指定的情况下默认每一次查询都是一次事务提交。可以通过命令SHOW VARIABLES LIKE ‘AUTOCOMMIT’来获取当前是否开启。没开启则直到显式的调用COMMIT或者ROLLBACK才表示事务结束。<br>注意:存在一些命令会在执行前导致强制执行COMMIT操作的。如DDL中的ALTER TABLE。请检查官方给出的会导致强制提交的语句。</li>
<li>MySQL可以通过执行SET TRANSACTION ISOLATION LEVEL来设置隔离级别,可以设置session级别的或者在配置文件中设置整个数据库级别的。<br>mysql>SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;</li>
</ul>
<p>MySQL服务器层不管理事务,事务由下层的存储引擎实现,所以同一事务中,使用多种存储引擎是不可靠的。</p>
<p>特定语句的加锁方式</p>
<ul>
<li>SELECT …… LOCK IN SHARE MODE</li>
<li>SELECT …… FOR UPDATE</li>
</ul>
<p>MySQL的多版本并发控制(MVCC)</p>
<p>典型的MVCC有乐观并发控制和悲观并发控制。</p>
<p>以InnoDB的MVCC为例,它是通过在每行记录后面保存两个隐藏的列来实现的。两个列分别保存了行的创建时间和过期时间(删除时间)。(注意这里实际存储的是系统版本号,每开始一个新事务,系统版本号都会加1)</p>
<p>SELECT</p>
<ol>
<li>查找<=当前事务版本的数据行,以确保事务读取的行,要么是事务开始前已存在的,要么是当前事务新增或修改过的。</li>
<li>删除的版本未定义或大于当前事务版本,这样可以确保事务读取到的数据在事务开始之前一定未被删除。</li>
</ol>
<p>INSERT</p>
<ul>
<li>新增的行保存当前事务的版本号为行版本号。</li>
</ul>
<p>DELETE</p>
<ul>
<li>删除的行保存当前事务的版本号为行删除标识。</li>
</ul>
<p>UPDATE</p>
<ul>
<li>新增一条记录保存当前事务的版本号为行版本号,同时将当前系统版本号作为原来行的删除标识。</li>
</ul>
<p>MVCC只在REPEATABLE READ和READ COMMITTED两个隔离级别下工作,READ UNCOMMITTED总是会读取最新的数据行,而不是符合当前事务版本的行,而SERIALIZABLE则会对所有读取行都加锁。</p>
<p>MySQL引擎</p>
<p>可以通过命令来获取当前版本支持的引擎。</p>
<p>mysql> show engines</p>
<p>MySQL存储引擎</p>
<p>MySQL创建表,会在数据库子目录下创建一个和表同名的.frm文件,用于保存表的定义。可以通过以下命令查看</p>
<p>mysql>SHOW TABLES STATUS LIKE 表名</p>
<p>InnoDB引擎概览</p>
<ul>
<li>存储在表空间中,4.1后的版本,每个表的数据和索引存放在单独的文件中。</li>
<li>采用MVCC来支持高并发,支持全部四种隔离级别,默认级别为REPEATABLE READ可重复读,并且通过<br>间隙锁(next key locking)策略防止幻读。</li>
<li>InnoDB表是基于聚簇索引建立的,聚簇索引主键查询性能很高,但二级索引(即非主键索引中)必须包含主键列,因而主键列应尽可能的小。</li>
<li>InnoDB可以支持热备份,无需停止读写。</li>
<li>MySQL5.1以后的默认引擎,支持自动崩溃恢复特性。5.1以前是MyISAM为默认引擎。</li>
</ul>
<p>MyISAM引擎概览</p>
<ul>
<li>将表存储在两个文件中,数据文件和索引文件,分别以.MYD和.MYI为扩展名。</li>
<li>支持表级锁,不支持行级锁。读取加共享锁,写入加排他锁。支持并发插入,即在表有读取查询的同时,有插入操作。</li>
<li>支持修复。通过CHECK TABLE mytable来检查表的错误,如果有错误,可以用REPAIR TABLE mytable来进行修复。如果MySQL服务器已经关闭,可以通过myisamchk来检查和修复操作。</li>
<li>索引,MyISAM支持前缀索引,和基于分词创建的全文索引。</li>
<li>支持延迟更新索引键,通过DELAY_KEY_WRITE来设置,只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入到磁盘。如果数据库宕机,可能会导致索引损坏。</li>
<li>MyISAM压缩表比较适合数据导入后,不再进行修改操作的表。</li>
<li>MyISAM最大的性能问题就是表锁问题。</li>
</ul>
<p>Archive引擎概览</p>
<ul>
<li>Archive存储引擎只支持INSERT和SELECT操作,5.1之前也不支持索引。比较适用于日志和数据采集类的应用。</li>
<li>支持行级锁和专用缓冲区,支持一致性读及批量插入对读操作的不可见性。但它不是事务型引擎。</li>
</ul>
<p>Blackhole引擎概览</p>
<ul>
<li>该引擎它并没有实现存储机制,会丢弃所有的插入数据,不做保存,但服务器会记录Blackhole表的日志。可以用于复制数据到备库。</li>
</ul>
<p>CSV引擎概览</p>
<ul>
<li>CSV引擎可以实现普通CSV文件作为MySQL表来读取和操作,因此可以用于一种数据交换机制。</li>
</ul>
<p>Federated引擎概览</p>
<ul>
<li>Federated引擎是访问其他MySQL服务器的一个代理,他创建一个到远程MySQL服务器的客户端连接,并将查询传输到远程服务器执行,提取出需要的数据。</li>
<li>Federated可以在本地数据库中创建一个远端数据表的“软链接”。这样,访问远端数据表就如同访问本地数据表。(远端可以是不同主机上的不同实例)</li>
<li>手动安装命令<br>mysql> install plugin federated soname ‘ha_federated.so’</li>
</ul>
<p>Memory引擎</p>
<ul>
<li>数据保存在内存中,无需磁盘的io操作,重启后,表结构还在,数据清空。</li>
<li>比MyISAM引擎快一个数量级。</li>
<li>支持的场景多样<br>用于查找或者映射表<br>用于缓存周期性聚合结果<br>用于保存数据分析产生的中间数据。</li>
<li>支持Hash索引,查询速度非常快。</li>
<li>表级锁,行固定不支持VARCHAR,不支持BLOB或TEXT。</li>
</ul>
<p>Merge引擎</p>
<ul>
<li>MyISAM的一个变种</li>
<li>多个MyISAM表合并而来的虚拟表</li>
<li>之前用于数据仓库或日志类应用。引入分区功能后,已废弃。</li>
</ul>
<p>NDB集群引擎</p>
<p>MySQL服务器,NDB集群存储引擎,NDB数据库组成MySql集群。</p>
<p>第三方引擎</p>
<p>OLTP类引擎</p>
<p>XtraDB引擎</p>
<ul>
<li>基于InnoDB引擎的改进版,包含在Percona Server和Maria DB中</li>
<li>OLTP类引擎</li>
<li>在性能,可测量性和灵活性上有所提升</li>
</ul>
<p>PBXT引擎</p>
<ul>
<li>OLTP类引擎</li>
<li>支持ACID事务和MVCC</li>
<li>支持引擎级别的复制,外键约束</li>
<li>支持固态存储SSD,优化了大值类型,如BLOB。</li>
</ul>
<p>TokuDB引擎</p>
<ul>
<li>分形树的索引数据结构,与缓存无关,大小超过内存性能也不会下降。</li>
<li>大数据存储引擎,高压缩比,可创建大量索引。</li>
</ul>
<p>RethinkDB</p>
<ul>
<li>为固态存储SSD而设计的。</li>
<li>采用了一种只能追加的写时复制B树作为索引的数据结构</li>
</ul>
<p>面向列的存储引擎</p>
<p>infobright</p>
<ul>
<li>为数据分析和数据仓库设计的面向列的存储引擎。</li>
<li>不支持索引,块结构排序</li>
</ul>
<p>社区存储版本</p>
<p>Aria/Groonga/OQGragh/Q4M/SphinxSE/Spider/VPForMySQL</p>
<p>小结</p>
<ul>
<li>MySQL分层架构,上层是服务器层的服务和查询执行引擎,下层是存储引擎。<br>优先建议用InnoDB引擎,如果用全文索引可以用InnoDB和Sphinx组合,而不用MyISAM。<br>MyISAM比较适合日志类应用。<br>选取MySql引擎的考虑因素,备份/事务/崩溃恢复/特定的特性。<br>日志类应用 MyISAM/Archive引擎比较合适<br>订单类应用 InnoDB</li>
</ul>
<p>第三章 服务器性能剖析</p>
<p>查询响应时间是数据库服务器性能度量的标准。</p>
<p>性能剖析有两种:</p>
<ul>
<li>基于执行时间的分析</li>
<li>基于等待的分析</li>
</ul>
<p>常用的性能剖析命令:</p>
<ul>
<li>Show Profile / Show Profiles</li>
<li>Show Status 某些数据库活动的频繁程度</li>
<li>Show Global Status</li>
<li>Show Processlist</li>
</ul>
<p>Strace 工具调查系统调用情况。</p>
<ul>
<li>strace -cfp $pid of mysqld</li>
</ul>
<p>小结</p>
<ul>
<li>响应时间是定义性能最有效的方法。</li>
<li>测量的最佳起点是应用程序,而非数据库。</li>
<li>完整的测量需要用剖析器来分析大量的待分析数据。</li>
</ul>
<p>第四章 schema与数据类型优化</p>
<p>数据类型的选择</p>
<ul>
<li>更小的通常更好,一般情况下,更小的数据类型更快,占用更少的磁盘,cpu和内存,处理时需要的cpu周期也更少。</li>
<li>简单就好,简单的数据类型会占用更少的cpu周期。如存储时间应该用date,time或datetime而非字符串,存储ip应该用整型。</li>
<li>尽量避免NULL,NULL值很难优化,会占用更多的存储空间。对于要索引的列,尽量避免为null。</li>
<li>数据类型的别名不会有性能损耗,但是肯能会令人不解。</li>
</ul>
<p>整数类型</p>
<ul>
<li>有符号和无符号类型使用相同的存储空间,并具有相同的性能。</li>
<li>MySQL可以为整数类型指定宽度,大多数情况是没有意义的。只是用来显示字符个数,对于存储和计算而言,INT(1)和INT(20)是相同的。</li>
</ul>
<p>实数类型</p>
<ul>
<li>带有小数部分的数字。也可以存储DECIMAL,比BIGINT还大的整数。</li>
<li>MySQL既支持精确类型,也支持不精确类型。</li>
<li>MySQL使用DOUBLE做内部浮点计算的类型,使用DECIMAL来做存储类型。</li>
<li>可以通过乘以响应的倍数来用BIGINT代替DECIMAL。</li>
</ul>
<p>字符串类型</p>
<p>VARCHAR</p>
<ul>
<li>VARCHAR类型可变长字符,如果MySQL表ROW_FORMAT=FIXED,定长存储。</li>
<li>VARCHAR适合的场景,字符串列的最大长度比平均长度大很多,列更新很少,碎片少。使用了UTF-8这样的可变长字符集。</li>
<li>InnoDB会把VARCHAR存储为BLOB。</li>
</ul>
<p>CHAR</p>
<ul>
<li>CHAR类型定长。</li>
<li>不易产生碎片。</li>
</ul>
<p>最好的策略是只分配真正需要的空间。</p>
<p>BOLB和TEXT类型</p>
<ul>
<li>MySQL对TXET或者BLOB的排序与其他类型不同,它只对每个列的最前max_sort_length字节进行排序。如果只需要排序前面一小部分字符,则可以减少max_sort_length的配置,或者使用ORDER BY SUBSTRING(column,length)。</li>
<li>MySQL不能将BOLB和TEXT列全部长度的字符来进行索引。</li>
<li>MySQL在查询时如果使用了BLOB或者TEXT列会使用磁盘临时表,这会导致严重的性能开销。最好的解决方案是尽量避免使用这两种类型。如果不得不用,可以考虑用SUBSTRING(column,length)的方式取足够短的字符,来保证使用的临时表大小,小于max_heap_table_size或tmp_table_size,从而不会由内存临时表转为磁盘临时表。</li>
<li>如果EXPLAIN执行计划的Extra列包含了Using temporary,则说明这个查询使用了隐式临时表。</li>
</ul>
<p>枚举类</p>
<p>MySQL会把枚举值存储为整数,枚举的字符串列表是固定的,如果添加或删除字符串,需要ALTER TABLE。可以考虑用枚举替代字符串。</p>
<p>DATETIME和TIMESTAMP</p>
<p>DATETIME</p>
<ul>
<li>范围1001-9999年,精度为秒</li>
<li>存储格式为YYYYMMDDHHMMSS,与时区无关</li>
<li>存储占8个字节</li>
</ul>
<p>TIMESTAMP</p>
<ul>
<li>1970年1月1日午夜-2038年。</li>
<li>占用4个字节</li>
<li>默认列为NOT NULL。</li>
</ul>
<p>MariaDB支持微秒级别的时间存储。</p>
<p>位数据类型</p>
<p>BIT</p>
<ul>
<li>5.0版本之前BIT是TINYINT的同义词。</li>
<li>可以使用BIT列在一列中存储一个或多个true/false值。</li>
<li>BIT列最大长度是64个位</li>
<li>BIT在MYSQL中当做字符类型,而非数字类型。一般不建议用BIT</li>
<li>如果想在BIT中存储一个true或者false,另一个方法是创建一个可以为空的CHAR(0)列。</li>
</ul>
<p>SET</p>
<ul>
<li>SET数据类型,改变列需要ALTER TABLE,对于大表来说操作比较昂贵。</li>
<li>很难使用索引。</li>
</ul>
<h5 id="选择标识符"><a href="#选择标识符" class="headerlink" title="选择标识符"></a>选择标识符</h5><ul>
<li>一般标识列可能与其他值进行比较,或者寻找其他列,或者作为外键使用。因而选择标识符数据类型时,需要考虑存储类型,以及计算和比较的成本。最好的存储类型是整数类型。</li>
<li>对于标识列来说,ENUM和SET通常都是个糟糕的选择。他们更适合存储固定的信息。</li>
<li>尽量避免字符串作为标识列,因为占空间和速度较慢。MYISAM引擎会对字符串默认做压缩索引的处理,造成查询更慢。</li>
<li>完全随机字符串也会有影响,如MD5(),SHA1()或者UUID()产生的字符串,这些函数产生的新值会任意分布在很大的空间内,导致一些插入和查询语句很慢。IO代价比较高。</li>
<li>如果存储uuid值,最好移除掉-符号,更好的方式是用UNHEX()函数将其转换为16字节的数字存储在BINARY(16)列中。检索时可以通过HEX()函数来格式化为16进制格式。</li>
</ul>
<p>#####MySQL Schema设计中的陷阱</p>
<ul>
<li>太多的列</li>
</ul>
<blockquote>
<p>MySQL存储引擎API工作时需要在服务层和存储引擎层之间通过缓冲格式拷贝数据,然后在服务层将缓冲内容编码成各个列。</p>
</blockquote>
<ul>
<li>太多的关联</li>
</ul>
<blockquote>
<p>MySQL每个关联操作最多只能有61张表。如果希望查询执行的快且并发性好,单个查询最好在12个表以内。</p>
</blockquote>
<ul>
<li>防止过度的使用枚举</li>
<li>不要过度拒绝NULL</li>
</ul>
<p>#####范式和反范式</p>
<ul>
<li><p>范式化的数据库中,每个事实数据会出现并且只出现一次。相反,在反范式化的数据库中,事实数据可能会出现多次,通俗来讲就是我们所说的字段冗余。</p>
</li>
<li><p>范式化的好处</p>
</li>
</ul>
<blockquote>
<p>范式化的更新操作通常比反范式化要快。</p>
<p>需要修改的数据更少。</p>
<p>范式化的表通常更小,可以更好的放在内存,操作速度更快。</p>
<p>多余的数据少,意味着检索列表数据时更少需要distinct或者group by语句。</p>
</blockquote>
<ul>
<li>范式化的缺点</li>
</ul>
<blockquote>
<p>通常需要关联,会造成查询上的代价变高。</p>
</blockquote>
<ul>
<li>反范式的好处</li>
</ul>
<blockquote>
<p>schema所有数据都在一张表中,可以很好的避免关联。</p>
<p>避免了随机IO。</p>
<p>更有效的使用索引。</p>
<p>最常见的反范式的方法是缓存或者复制。</p>
</blockquote>
<p>MySQL本身并不支持物化视图。需要第三方支持。</p>
<p>#####如何加快ALTER TABLE的速度</p>
<p>常见方式:</p>
<ul>
<li><p>现在一台不提供服务的机器上执行ALTER TABLE操作,然后和提供服务的主库进行切换。</p>
</li>
<li><p>影子拷贝的方式。用要求的表结构创建一张和源表无关的新表,然后通过重命名和删表操作交换两张表。可以用一些工具来处理 online schema change或openark。如果改变列可以用ALTER COLUMN的方式来处理。它只会修改.frm文件,而不涉及到表数据,因此非常快。具体地</p>
</li>
</ul>
<blockquote>
<p>创建一张有相同结构的空表做修改。</p>
<p>执行FLUSH TABLES WITH READ LOCK。这将会关闭所有正在使用的表,并且,禁止任何表被打开。</p>
<p>交换.frm文件。</p>
<p>执行UNLOCK TABLES来释放读锁。</p>
<p>DISABLE KEYS只对非唯一索引有效。</p>
</blockquote>
<p>#####总结</p>
<ul>
<li>小而简单总是好的。</li>
<li>尽量避免过度设计。</li>
<li>使用小而简单的合适数据类型,除非真实数据模型中有确切需要,否则尽量避免使用NULL值。</li>
<li>尽量使用相同的数据类型存储相似或相关的值,尤其是要在关联条件中使用的列。</li>
<li>注意可变长字符串,其在临时表和排序时可能导致悲观的按最大长度分配内存。</li>
<li>尽量使用整型定义标识列。</li>
<li>避免使用MYSQL已经遗弃的特性,如指定浮点数的精度或整数的显示宽度等。</li>
<li>小心使用ENUM和SET,不要滥用。</li>
<li>最好避免使用BIT。</li>
</ul>
<h4 id="Chapter-5-创建高性能索引"><a href="#Chapter-5-创建高性能索引" class="headerlink" title="Chapter 5 创建高性能索引"></a>Chapter 5 创建高性能索引</h4><p>索引基础</p>
<p>索引可以包含一个或多个列,列顺序有关,MySQL只能高效地使用索引的最左前缀列。</p>
<p>不同存储引擎索引的工作方式并不一样,并非所有的存储引擎都支持所有类型的索引。</p>
<p>B-Tree索引</p>
<p>大多数MySQL引擎支持BTree索引。Archive引擎除外,5.1版本以前不支持任何索引,以后的版本才开始支持单个自增列的索引。</p>
<p>InnoDB用的是B+Tree。</p>
<p>不同的存储引擎以不同的方式使用B-Tree索引,性能各不相同。MyISAM使用前缀压缩技术使得索引占用更少的空间,InnoDB则按照原有格式存储。MyISAM索引通过数据的物理位置引用被索引的行,而InnoDB则根据主键引用索引的行。</p>
<p>B-Tree即平衡二叉树。有序,且每个叶子到根节点距离相同。</p>
<img src="/2017/10/28/mysqlstudy/btree.png" title="B-Tree">
<p>BTree树搜索是从索引的根节点开始进行,根节点的槽中存放了指向子节点的指针,存储引擎根据这些指针向下查找。树的深度和表的大小直接相关。</p>
<p>索引对多个值进行排序的依据是CREATE TABLE语句中定义索引时列的顺序。</p>
<p>BTree索引适用于全键值,键值范围或最左前缀查找。</p>
<p>因为索引树中的节点是有序的,因而支持按值查找,也支持Order By操作(按顺序查找)</p>
<p>BTree索引限制:</p>
<p>如果不是按照索引的最左列开始查找,则无法使用索引。</p>
<p>不能跳过索引中的列。</p>
<p>如果查询中有某个列的范围查询,则其右边所有列都无法使用索引优化查询。</p>
<p>在优化性能时,可能需要使用相同的列但顺序不同的索引来满足不同类型的查询需求。</p>
<p>哈希索引</p>
<p>哈希索引基于哈希表实现,只有精确匹配索引所有列的查询才有效。MySQL中只有Memory引擎显式的支持hash索引(memory引擎的默认索引类型)。如果多个列的hash值相同,则会用链表的形式存放多个记录到同一个hash条目中。</p>
<p>Hash索引的特点:</p>
<ul>
<li>Hash索引只包含hash值和行指针,而不存储字段值,所以不能使用索引的值来避免读取行。不过,访问内存中的行的速度很快,对性能影响不大。</li>
<li>Hash索引数据并不是按照索引值顺序存储的,也就无法进行排序。</li>
<li>Hash索引不支持部分索引匹配查找,因为Hash索引始终是使用索引列的全部内容来计算Hash值的。如在数据列(A,B)上建立Hash索引,如果查询只有数据列A,则无法使用该索引。</li>
<li>Hash索引只支持等值比较查询,包括=,in,<=>,不支持范围查询。</li>
<li>理论上访问Hash索引速度非常快,除非有很多hash冲突,这时会遍历索引值相同的链表查找。</li>
</ul>
<p>Hash索引的应用场景:<br>如需要查找很多关联表的场景。InnoDB有个自适应hash索引的功能,他会为访问频繁的索引值加一个hash索引,用于加快查找速度,这个用户无法控制,但可以关闭。</p>
<blockquote>
<p>创建自定义Hash值的思路,在BTree基础上创建一个伪Hash索引,它使用Hash值作为二分查找的索引。在where语句中使用hash函数查询。自定义hash值得函数请使用crc32的,不要用sha1或者md5的(太长浪费空间)。但是如果数据量大,crc32会出现大量的hash冲突,这种情况最好自己实现一个64位的hash函数。</p>
</blockquote>
<h5 id="R-Tree-空间索引"><a href="#R-Tree-空间索引" class="headerlink" title="R-Tree 空间索引"></a>R-Tree 空间索引</h5><p>MyISAM支持空间索引,可以用于地理数据存储,数据需要用到Mysql的GIS相关函数。相对不太完善,一般都用PostgreSQL的PostGIS。</p>
<h5 id="全文索引"><a href="#全文索引" class="headerlink" title="全文索引"></a>全文索引</h5><p>查找文本中的关键词,而非直接比较索引值。类似于搜索引擎。匹配方式也和其他索引不一样。相同的列可以同时创建全文索引和Btree索引。</p>
<h5 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h5><p>其他三方数据库引擎的索引,如TokuDB的分形树索引 fractal tree index等。</p>
<h5 id="索引的优缺点"><a href="#索引的优缺点" class="headerlink" title="索引的优缺点"></a>索引的优缺点</h5><ul>
<li>大大减少了服务器需要扫描的数据量</li>
<li>可以帮助服务器避免排序和临时表</li>
<li>可以随机I/O变顺序I/O</li>
</ul>
<p>当且仅当创建索引的代价比索引带来的性能提升小时,这样索引才是有效的。</p>
<h5 id="高效使用索引的注意点"><a href="#高效使用索引的注意点" class="headerlink" title="高效使用索引的注意点"></a>高效使用索引的注意点</h5><ul>
<li><p>独立的列,索引列不能是表达式的一部分,也不能是函数的参数,否则引擎无法解析。</p>
</li>
<li><p>前缀索引和索引选择性,前缀索引可以索引开始的部分字符,这样大大节省了索引空间,提高索引效率,但会降低索引选择性。索引选择性是指,不重复的索引值(即基数)和数据表的记录总数的比值。索引选择性越高,查询效率越高。即可辨识度越高,性能越好,唯一索引选择性是1,性能也是最好的。</p>
</li>
<li><p>对于BLOB,TEXT和很长的VARCHAR列,必须使用前缀索引。MYSQL不允许索引这些列的完整长度。目标是长度尽可能短的情况下,保证选择性尽可能的高,可辨识度高。注意MYSQL无法使用前缀索引做ORDER BY</p>
<p>或GROUP BY,也无法使用前缀索引做覆盖扫描。</p>
</li>
</ul>
<h5 id="多列索引问题"><a href="#多列索引问题" class="headerlink" title="多列索引问题"></a>多列索引问题</h5><ul>
<li>常见的误区:为每个列创建索引,或者按照错误的顺序创建多个索引。</li>
<li>5.0以前的老的MySQL对于where条件中A or B的条件进行全表扫描,除非改成A条件 union B条件。5.0以后查询能够同时使用这两个单列索引进行扫描,再将结果合并。Or条件取并集,And条件取交集,组合前两种情况的联合和相交。</li>
<li>索引合并策略是Mysql5.0版本以后的一个新特性,但是这也意味着表上索引建的不好。当有多个AND条件,通常意味着需要一个包含这多个条件的多列索引。</li>
</ul>
<h5 id="选择索引列的基本法则"><a href="#选择索引列的基本法则" class="headerlink" title="选择索引列的基本法则"></a>选择索引列的基本法则</h5><p>当不需要考虑排序和分组时,将选择性最高的列放在前面。这时索引只优化WHERE条件的查找。如WHERE条件中有A和B,Where A and B,选择A在前还是B在前时,可以先跑一些查询看看两个条件下那个条件查询出来的结果更少,就把哪个条件放在前。如 select sum(A),sum(b) from table。但这种情况有可能比较片面。</p>
<p>因此最好使用select count(distinct 字段A)/count(1) , count(distinct 字段B)/count(1) from table来看那个字段对应的值可辨识度更高,来作为前面的字段。</p>
<p>where子句中排序,分组和范围条件等其他因素,对查询性能造成的影响可能更大。</p>
<h5 id="聚簇索引"><a href="#聚簇索引" class="headerlink" title="聚簇索引"></a>聚簇索引</h5><p>聚簇索引并非单独的索引类型,而是一种数据存储方式。InnoDB的聚簇索引实际上在同一个结构中保存了B-Tree索引和数据行。聚簇表示数据行和相邻键值紧凑的存在一起。因为无法把数据行存放在两个不同的地方,因此一个表理论上只能有一个聚簇索引,不过覆盖索引可以模拟多个聚簇索引的情况。</p>
<p>以InnoDB举例,InnoDB一般通过主键聚集数据,如果未定义主键,InnoDB会选择一个唯一的非空索引代替。如果没有这样的索引,InnoDB会隐式定义一个主键来作为聚簇索引。</p>
<p>聚簇索引本身是个双刃剑,特别是做引擎迁移时尤其要注意性能。</p>
<p>优点:</p>
<ul>
<li>将数据保存在一起,减少磁盘IO。</li>
<li>数据和索引一起放在BTREE上,查询速度更快。</li>
<li>使用覆盖索引扫描的查询可以直接使用页节点中的主键值。</li>
</ul>
<p>缺点:</p>
<ul>
<li>聚簇索引最大限度的提高了IO密集型应用的性能,对于数据全部在内存中的,没有优势。</li>
<li>插入速度严重依赖于插入顺序。按照主键顺序插入是加载数据到InnoDB表的最快方式。如果不是按主键顺序,最后加载完成后,使用Optimize table命令重新组织一下表。</li>
<li>更新索引的代价很昂贵。</li>
<li>基于聚簇索引的表再插入新行,或者主键被更新导致移位时,可能会造成页分裂。</li>
<li>聚簇索引可能导致全表扫面变慢。尤其是行比较稀疏,或者页分裂导致数据存储不连续时。</li>
<li>二级索引(非聚簇索引)可能比想象的更大,因为在二级索引的叶子节点包含了应用行的主键列。</li>
<li>二级索引访问需要两次索引查找,而不是一次。</li>
</ul>
<p>InnoDB和MyISAM保存索引的差异</p>
<img src="/2017/10/28/mysqlstudy/cluster-index.png" title="聚簇索引">
<p>顺序主键可能的问题,高并发插入的热点问题,锁争用严重。</p>
<h5 id="覆盖索引"><a href="#覆盖索引" class="headerlink" title="覆盖索引"></a>覆盖索引</h5><p>如果一个索引包含或者说覆盖所有需要查询的字段值,就称之为覆盖索引。</p>
<ul>
<li>索引条目通常远小于数据行大小,可以极大的减小数据访问量,如果只读取索引的情况下。</li>
<li>因为索引是按照列值顺序存储的,至少单页如此,因而对I/O密集型的范围查询会比从随机从磁盘读取每一行数据的I/O要少的多。</li>
<li>一些存储引擎如MyISAM在内存中只缓存索引,数据则依赖操作系统来缓存,因此要访问数据需要一次系统调用,可能会导致性能问题。</li>
<li>对于InnoDB如果它的二级主键能够覆盖查询,则可以避免对主键索引的二次查询。</li>
</ul>
<p>不是所有类型的索引都可以称为覆盖索引,覆盖索引必须要存储索引列的值,而hash索引,空间索引和全文索引等都不存储存储列的值。MySQL只能使用B-Tree索引做覆盖索引。另外不是索引的引擎都支持覆盖索引,如memory引擎目前是不支持的。</p>
<p>执行计划的extra中如果是using index则表明当前查询使用了覆盖索引查询。如:</p>
<blockquote>
<p>SELECT A,B from TABLE S 正好有A,B字段的索引就会走覆盖索引。</p>
</blockquote>
<p>但是如果SELECT的时候用了*,而非具体的字段,就无法走覆盖索引啦。大多数存储引擎的覆盖索引,都只能覆盖那些只访问索引中部分列的查询。但也可以根据实际情况做一些优化,以利用的更多。如InnoDB的二级主键。</p>
<h5 id="使用索引扫描来排序"><a href="#使用索引扫描来排序" class="headerlink" title="使用索引扫描来排序"></a>使用索引扫描来排序</h5><p>MySQL有两种方式生成顺序结果,排序方式或者根据索引顺序扫描。</p>
<p>如果执行计划中的type列值为index,则表示MySQL使用了索引扫描来做排序。</p>
<p>MySQL可以使用同一个索引即满足排序,又用于行查找。这种是最好的,最好的情况是索引记录就覆盖了查找的全部列,而不需要二次从索引再去查询列信息。</p>
<p>当索引的列顺序和Order by子句的顺序完全一致,且排序方向都一样时,Mysql才用索引对结果做排序。</p>
<p>如果查询关联多张表,则只有当Order By子句引用的字段全部为第一个表时,才能使用索引排序。</p>
<p>考虑索引需要考虑CPU密集型和IO密集型的差别,如MyISAM的压缩索引,对于CPU密集型的随机查找,压缩索引就会很慢。</p>
<h5 id="重复索引和冗余索引"><a href="#重复索引和冗余索引" class="headerlink" title="重复索引和冗余索引"></a>重复索引和冗余索引</h5><p>一般情况下,增加新索引会导致INSERT,UPDATE,DELETE等操作速度变慢,特别是当新增索引后导致达到了内存瓶颈的时候。</p>
<p>Perconapt-index-usage 查询未使用的索引。</p>
<h5 id="碎片化"><a href="#碎片化" class="headerlink" title="碎片化"></a>碎片化</h5><p>行碎片,行间碎片,剩余空间碎片</p>
<p>MyISAM都会有,InnoDB不会有行碎片,它会移动短小的行并重写到一个片段中。</p>
<h5 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h5><p>选择编写索引的原则</p>
<blockquote>
<ol>
<li>单行访问总是很慢的。最好读取快中能包含尽可能多的所需要行,使用索引可以创建位置引用以提升效率。</li>
<li>按顺序访问范围数据是很快的。1.顺序IO不需要多次磁盘寻道,所以比随机IO快很多。2.如果服务器能够按需要顺序读取数据,那么就不再需要额外的排序操作,并且GROUP BY查询也无需在做排序和将行按组进行聚合计算了。</li>
<li>能用覆盖索引尽量用覆盖索引查询所需字段。</li>
</ol>
</blockquote>
<h4 id="查询性能优化"><a href="#查询性能优化" class="headerlink" title="查询性能优化"></a>查询性能优化</h4><ul>
<li><p>查询优化,库表结构优化,索引优化都要考虑和调整。</p>
</li>
<li><p>大部分性能低下的查询都可以通过减少访问数据量的方式来优化。通常用两个步骤来分析:</p>
</li>
</ul>
<p>确认应用程序是否检索了大量超过需要的数据,这意味着访问了太多的行,但有时间也可能是访问了太多的列。</p>
<blockquote>
<ul>
<li>查询了不需要的记录</li>
<li>多表关联返回全部列</li>
<li>SELECT总是查询全部列</li>
<li>重复查询相同的数据</li>
</ul>
<p>确认Mysql服务器层是否在分析大量超过需要的数据行。</p>
<p>分析查询开销的三个指标:响应时间,扫描行数,返回行数。</p>
<ul>
<li>响应时间是服务时间和排队时间之和。</li>
<li>explain中的Type列反应了访问类型。如果查询没有办法找到合适的访问类型,最好的办法就是加一个合适的索引。</li>
</ul>
</blockquote>
<ul>
<li>MySql能够使用如下三种方式应用Where条件</li>
</ul>
<blockquote>
<ul>
<li>在索引中使用where条件来过滤不匹配的记录。存储引擎层完成。</li>
<li>使用索引覆盖扫描来返回记录,直接从索引中过滤不需要的记录并返回命中的结果。服务器层完成。</li>
<li>数据表中返回数据,然后过滤不满足条件的记录。服务器层完成。</li>
</ul>
</blockquote>
<ul>
<li>如果发现查询扫描了大量的数据,只返回了少数的行,则可以从以下几点考虑优化</li>
</ul>
<blockquote>
<ul>
<li><p>使用覆盖索引,查询的列放在索引中,无需再次回表查询。</p>
</li>
<li><p>改变库表结构。</p>
</li>
<li><p>重写这个查询。</p>
<p>1.Mysql运行多个小查询已不是问题。其他条件都相同的情况下,尽可能少的查询当然是更好的。</p>
<p>2.将大查询分解为小查询。</p>
<p>3.分解关联查询的好处:</p>
<p> a. 让缓存的效率更高。</p>
<p> b.将查询分解后,执行单个查询可以较少锁竞争。</p>
<p> c.在应用层做关联,可以更容易对数据库进行拆分,更容易做到高性能扩展。</p>
<p> d.查询本身效率也可能会有所提升。</p>
<p> e.可以减少冗余记录的查询。</p>
</li>
</ul>
</blockquote>
<p> </p>
<h5 id="MySQL-查询"><a href="#MySQL-查询" class="headerlink" title="MySQL 查询"></a>MySQL 查询</h5><p>Mysql查询的基本路径</p>
<img src="/2017/10/28/mysqlstudy/mysqlexec.png" title="Mysql Exceute Trace">
<p>MySQL客户端和服务器之间采用的是半双工通信,任何一个时刻都是要么服务器发送数据给客户端,要么客户端发送数据给服务器,不能同时发生。客户端用一个单独的数据包将查询传给服务器,这也是为什么查询语句很长时,参数max_allowed_packet很重要。相反的,服务端返回给客户端的数据包会分为很多个,客户端必须完整的接受整个返回结果,这也是为什么要加limit的原因。</p>
<h5 id="查询状态"><a href="#查询状态" class="headerlink" title="查询状态"></a>查询状态</h5><p>用SHOW FULL PROCESSLIST命令查询所有的状态。</p>
<ul>
<li>Sleep — 线程正在等待客户端发送新的请求。</li>
<li>Query — 线程正在执行查询或者正在将结果发送给客户端。</li>
<li>Locked — MySQL服务层,该线程正在等待表锁。存储引擎级别实现的锁,如InnoDB的行锁,并不会体现在线程状态中。</li>
<li>Analyzing and statistics — 线程正在收集存储引擎的统计信息,并生成查询的执行计划。</li>
<li>Copying to tmp table [on disk] — 线程正在执行查询,并将结果复制到临时表,一般要么是GROUP BY , FILE SORT,或者UNION等。如果包含on disk标识,表示MySQL正在将一个内存临时表刷入磁盘。</li>
<li>Sorting result — 线程正在对结果集进行排序。</li>
<li>Sending data — 线程可能在多个状态之间传输数据 或者 在生成结果集 或者在向客户端返回数据</li>
</ul>
<h5 id="Mysql-查询优化时选择错误的执行计划的原因"><a href="#Mysql-查询优化时选择错误的执行计划的原因" class="headerlink" title="Mysql 查询优化时选择错误的执行计划的原因"></a>Mysql 查询优化时选择错误的执行计划的原因</h5><ul>
<li><p>统计信息不准确</p>
</li>
<li><p>执行计划中的成本估计不等同于执行成本。</p>
</li>
<li><p>MySQL认为的最优和实际用户的目标并不一定一致。</p>
</li>
<li><p>MySQL从不考虑并发执行的场景。</p>
</li>
<li><p>MySQL也并不是任何时候都是基于成本的优化,有时也会基于一定的规则。</p>
</li>
<li><p>MySQL不考虑不受其控制的操作成本,如执行存储过程或者用户自定义函数等成本。</p>
</li>
<li><p>优化器也无法估算所有的执行计划。</p>
</li>
</ul>
<p>MySQL的优化分为静态优化和动态优化,静态优化可以认为是编译时优化,动态优化可以认为是执行时优化。</p>
<p>MySQL可以处理的优化,有以下几种,</p>
<ul>
<li>重新定义表关联顺序</li>
<li>将外连接转换为内连接</li>
<li>使用等价变化简化和规范表达式</li>
<li>优化count(),min()和max()</li>
<li>预计并转化为常数表达式</li>
<li>覆盖索引查询</li>
<li>子查询优化,减少子查询对数据的访问</li>
<li>提前终止查询</li>
<li>等值传播</li>
<li>列表IN()的比较</li>
</ul>
<p>MySQL的执行计划总是一颗左侧深度优先的树。</p>
<p> </p>
<p> </p>
]]></content>
<summary type="html">
<p>第一章 Mysql架构和历史</p>
<p>MySQL的两种基本锁</p>
<p>表锁和行级锁</p>
<ul>
<li><p>表锁<br>读锁互不排斥,写锁互斥。Mysql 服务器层会根据情况添加表锁,如ALTER TABLE操作。</p>
</li>
<li><p>行级
</summary>
<category term="MySQL,数据库设计" scheme="http://yoursite.com/tags/MySQL-%E6%95%B0%E6%8D%AE%E5%BA%93%E8%AE%BE%E8%AE%A1/"/>
</entry>
<entry>
<title>正则表达式Tips</title>
<link href="http://yoursite.com/2017/08/23/regextips/"/>
<id>http://yoursite.com/2017/08/23/regextips/</id>
<published>2017-08-23T01:09:07.000Z</published>
<updated>2017-08-30T09:12:46.000Z</updated>
<content type="html"><![CDATA[<h3 id="正则表达式引擎"><a href="#正则表达式引擎" class="headerlink" title="正则表达式引擎"></a>正则表达式引擎</h3><p>正则表达式的正则引擎主要分为两大类:DFA和NFA,NFA又细分为传统型NFA,POSIX NFA。</p>
<h4 id="DFA(确定型有穷机)"><a href="#DFA(确定型有穷机)" class="headerlink" title="DFA(确定型有穷机)"></a>DFA(确定型有穷机)</h4><ul>
<li>以文本主导的匹配。匹配规则是从匹配文本入手,从左至右,每个字符的匹配次数不会超过两次。</li>
<li>多条子表达式会在扫描文本时,同时进行匹配</li>
<li>不支持捕获组,各种引用,贪心修饰符等。</li>
<li>时间复杂度是多项式级别的。</li>
<li>可以确保匹配最长的可能的字符串。</li>
<li>使用DFA引擎 awk,MySQL,egrep等</li>
</ul>
<h4 id="NFA-(非确定性有穷自动机)"><a href="#NFA-(非确定性有穷自动机)" class="headerlink" title="NFA (非确定性有穷自动机)"></a>NFA (非确定性有穷自动机)</h4><ul>
<li>以正则表达式主导的匹配。</li>
<li>时间复杂度最好是多项式级别的,最差是指数级别的。</li>
<li>支持捕获组和各种引用等。</li>
<li>采用贪婪匹配回溯的方式匹配。</li>
<li>如果是POSIX NFA,则会在可以确保已经找到可能的最长的匹配之前,将继续回溯。因而POSIX NFA的效率低于传统的NFA效率。</li>
<li>使用传统型NFA的引擎 GUN Emacs,Java,.NET,Ruby,Perl,PHP,Python,Sed,vi等。</li>
<li>使用POSIX NFA的引擎 </li>
<li>使用DFA/NFA混合的引擎 GNU awk,GNU grep/egrep等。</li>
</ul>
<p>注意DFA会在编译阶段对表达式进行分析,生成映射关系,因而编译阶段NFA效率高于DFA。</p>
<h4 id="匹配过程"><a href="#匹配过程" class="headerlink" title="匹配过程"></a>匹配过程</h4><p>如Hello terrence,正则表达式为 /te(brence|rrence|rrencm)/ </p>
<ul>
<li>NFA 匹配</li>
</ul>
<blockquote>
<p>先在字符串中查找t然后匹配其后是否为e ,如果是e则继续,查找其后是否为b,如果不是则匹配其后是否为 r (此时淘汰brence选择项)。然后继续看其后是否依次为r,e,n,c,接着测试是否为 e,是e则匹配成功,不是则测试是否为m。</p>
</blockquote>
<ul>
<li>DFA匹配</li>
</ul>
<blockquote>
<p>从 Hello 中 H 开始依次查找 t,定位到 t ,已知其后为 e ,则查看表达式是否有 e ,此处正好有 e 。然后字符串 e 后为 r ,DFA依次测试表达式,此时 brence 不符合要求淘汰。rrence 和 rrencm 符合要求,然后DFA依次检查字符串,检测到rence 中的 e 时只有rence 分支符合。</p>
</blockquote>
<h4 id="NFA的匹配效率"><a href="#NFA的匹配效率" class="headerlink" title="NFA的匹配效率"></a>NFA的匹配效率</h4><h4 id="Alternation-Can-Be-Expensive"><a href="#Alternation-Can-Be-Expensive" class="headerlink" title="Alternation Can Be Expensive"></a><em>Alternation Can Be Expensive</em></h4><p>Alternation可能会导致更多的回溯。</p>
<p>举例如下:<br>具有Alternation的正则:u|v|w|x|y|z<br>固定的正则:[uvwxyz]</p>
<p>具有Alternation的正则每次匹配失败都需要回朔,固定的正则将一次匹配所有的。<br>如果失败,只匹配一次。即极限情况下,具有Alternation的正则需要回溯的次数是固定正则回溯次数的六倍。</p>
<h4 id="尽可能的明确-或-标识"><a href="#尽可能的明确-或-标识" class="headerlink" title="尽可能的明确^或$标识"></a><em>尽可能的明确^或$标识</em></h4><p>尽量确定行首或行尾的特征,使用^或者$来标识开始或结束,特别是表达式中包含贪婪匹配的元素时。</p>
<p>举例:假如用non-capturing group (?:) 匹配 <a href="http://baidu.com" target="_blank" rel="noopener">http://baidu.com</a><br>正则表达式如下(http?|ftp)://([^/\r\n]+)(/[^\r\n]<em>)?<br>如果我并不关心protocol,可以加入non-capturing group(?:) ,改为(?:http?|ftp)://([^/\r\n]+)(/[^\r\n]</em>)?<br>这样匹配时,会忽略掉protocol,提升效率。</p>
<h4 id="提取重复内容"><a href="#提取重复内容" class="headerlink" title="提取重复内容"></a><em>提取重复内容</em></h4><p>h(?:as|at) vs. (?:has|hat)</p>
<p>重复功能可以提取出来,当作一个函数,从而减少回朔的次数。这里前面的正则表达式效率高于后面的。</p>
<h4 id="将最有可能的匹配放在最前面"><a href="#将最有可能的匹配放在最前面" class="headerlink" title="将最有可能的匹配放在最前面"></a><em>将最有可能的匹配放在最前面</em></h4><p>假如我想匹配各种后缀(com net edu等)结尾的url,正则表达式如下 (?:com|edu|org|net|…)<br>实际上每个后缀的域名数量是不同的,假如 .net .org 的域名很多,为了提高效率我们可以将域名按照数量从高到低排序,以减少回溯次数。原正则表达式则变为 (?:net|org|com|edu|…)。</p>
<h4 id="用lookAround剔除掉部分无效的匹配"><a href="#用lookAround剔除掉部分无效的匹配" class="headerlink" title="用lookAround剔除掉部分无效的匹配"></a><em>用lookAround剔除掉部分无效的匹配</em></h4>]]></content>
<summary type="html">
<h3 id="正则表达式引擎"><a href="#正则表达式引擎" class="headerlink" title="正则表达式引擎"></a>正则表达式引擎</h3><p>正则表达式的正则引擎主要分为两大类:DFA和NFA,NFA又细分为传统型NFA,POSIX NFA。
</summary>
<category term="regex,DFA,NFA" scheme="http://yoursite.com/tags/regex%EF%BC%8CDFA%EF%BC%8CNFA/"/>
</entry>
<entry>
<title>Java Memory Model</title>
<link href="http://yoursite.com/2017/05/13/jmm/"/>
<id>http://yoursite.com/2017/05/13/jmm/</id>
<published>2017-05-13T03:57:31.000Z</published>
<updated>2017-05-14T04:27:49.000Z</updated>
<content type="html"><![CDATA[<p>##Java Memory Model<br>线程之间的通信机制有两种:共享内存和消息传递。</p>
<blockquote>
<ul>
<li>线程之间的公共状态,在共享内存的并发模型里,是通过写-读内存中的公共状态来隐式进行通信。在消息传递的并发模型里,是通过明确的发送消息来显式进行通信。</li>
<li>线程之间的状态同步,在共享内存并发模型里,必须显式地指定某个方法或某段代码需要在线程之间互斥执行。在消息传递的并发模型里,由于消息的发送必须在消息的接收之前,因此同步是隐式的。</li>
</ul>
</blockquote>
<p>Java并发采用的是共享内存模型,线程之间的内存公共状态的读写通信是透明的,状态同步是显式的,保证同步操作时线程之间是互斥的。</p>
<p>JVM内存模型中,程序计数器,虚拟机栈,本地方法栈都是线程私有的,他们存储的信息不存在可见性问题,是线程安全的。堆和方法区是线程共享的,存在可见性问题。</p>
<p>线程之间的通信是由JMM决定的,它决定了一个线程对共享变量的写入何时对另一个线程可见。相当于每个线程都有一个主内存中的变量副本,用于自身的操作。</p>
<p>JMM规范中有两条规定:</p>
<blockquote>
<ul>
<li>线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接从主内存中读写。</li>
<li>不同线程之间无法直接访问其他线程工作内存中的变量,线程间变量值的传递需要通过主内存来完成。</li>
</ul>
</blockquote>
<p><strong><em>happen-before原则</em></strong><br>一个线程中的每个操作,happens-before 于该线程中的任意后续操作。<br>一个监视器解锁,happens-before 于随后对这个监视器锁的加锁。<br>一个volatile域的写,happens-before 于任意后续对这个volatile域的读。<br>如果A happens-before B,且B happens-before C,那么A happens-before C。</p>
<p>两个操作之间具有happens-before关系,并不意味着前一个操作必须要在后一个操作之前执行。happens-before仅仅要求前一个操作(执行的结果)对后一个操作可见,且前一个操作按顺序排在第二个操作之前。</p>
<p><strong><em>指令重排序</em></strong><br>happen-before规则是编译器重排序和处理器重排序的基础。<br>程序执行时,编译器和处理器会根据执行效率对程序进行指令重排序。<br>编译器重排序,编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。(编译器级别)<br>指令级重排序,现代处理器采用了指令级并行技术(Instruction-Level Parallelism, ILP)来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。(cpu级别)<br>内存系统重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。(CPU级别)</p>
<p>编译器重排序由JMM的编译器重排序规则来禁止,处理器重排序可以通过内存屏障来禁止重排序。每个处理器processor的写缓冲区仅对自身可见。常见的处理器都允许store-load的重排序。</p>
<p>JMM的内存屏障分为以下四类:<br>JMM内存屏障分为四类</p>
<blockquote>
<ul>
<li>LoadLoadBarries<br>如:Load1–>LoadLoad–>Load2 确保load1数据装载一定在load2及所有后续装载指令1前装载。</li>
<li>StoreStoreBarries<br>如:Store1–>StroreStore–>Store2 确保Store1数据对其他处理器可见一定在Store2及所有后续存储指令存储的前面。</li>
<li>LoadStoreBarries<br>如:Load1–>LoadStore–>Store2</li>
<li>StoreLoadBarries<br>如: Store1–>StoreLoad–>Load2</li>
</ul>
</blockquote>
<p><strong><em>as-if-serial语义</em></strong><br>编译器和处理器不会改变存在数据依赖关系(仅针对单个处理器中执行的指令序列和单个线程中执行的操作,不包括不同处理器之间和不同线程之间的)的两个操作的执行顺序。因此重排序并不会给单线程带来内存可见性问题。这个就是as-if-serial语义。</p>
<p>as-if-serial:无论如何重排序,程序执行的结果应该与代码顺序执行的结果一致(Java编译器,运行时和处理器都会保证java在单线程下遵循as-if-serial语义)。</p>
<p><strong><em>原子性</em></strong><br>JMM对正确同步的多线程程序的内存一致性做了如下保证:<br>如果程序是正确同步的,程序的执行将具有顺序一致性(sequentially consistent)<br>即程序的执行结果与该程序在顺序一致性内存模型中的执行结果相同.</p>
<p>对64位(long,double)变量的读写可能不是原子操作,java内存模型允许JVM将没有被volatile修饰的64位数据类型的读写操作划分为两次32位的读写操作来完成。一般商用的JVM都对这部分做了原子性操作的保证,不用特意处理。<br>导致问题:可能会出现读取到”半个变量”的情况<br>解决办法:加volatile关键字。</p>
<p><strong><em>加volatile关键字</em></strong><br>volatile能够保证volatile变量的可见性,不能保证volatile变量复合操作的原子性<br>volatile如何实现内存可见性,深入来说通过加入内存屏障和禁止重排序优化来实现的。</p>
<p>对volatie变量执行写操作时,会在写操作后加入一条store屏障指令。</p>
<blockquote>
<ul>
<li>会把CPU写缓冲区的缓存强制刷新到主内存中。</li>
<li>防止处理器把volatile变量前面的操作重排序到valatile写操作之后。</li>
</ul>
</blockquote>
<p>对volatie变量执行读操作时,会在读操作前加入一条load屏障指令。</p>
<blockquote>
<ul>
<li>CPU缓冲区失效,从主内存读。</li>
<li>防止重排序。</li>
</ul>
</blockquote>
<p>volatile禁止重排序的规则</p>
<blockquote>
<ul>
<li>当第二个操作是volatile写时,不管第一个操作是什么,都不能重排序。这个规则确保volatile写之前的操作不会被编译器重排序到volatile写之后。</li>
<li>当第一个操作是volatile读时,不管第二个操作是什么,都不能重排序。这个规则确保volatile读之后的操作不会被编译器重排序到volatile读之前。</li>
<li>当第一个操作是volatile写,第二个操作是volatile读时,不能重排序。</li>
</ul>
</blockquote>
<p>volatile内存屏障的规则</p>
<blockquote>
<ul>
<li>在每个volatile写操作的前面插入一个StoreStore屏障。</li>
<li>在每个volatile写操作的后面插入一个StoreLoad屏障。</li>
<li>在每个volatile读操作的后面插入一个LoadLoad屏障。</li>
<li>在每个volatile读操作的后面插入一个LoadStore屏障。</li>
</ul>
</blockquote>
<p><strong><em>锁和CAS</em></strong><br>锁除了让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消息。<br>JVM中concurrent包中的锁主要依赖的是AbstractQueuedSynchronizer框架,即AQS实现的。AQS会维护一个volatile的Long型同步状态。</p>
<p>java的CAS同时具有 volatile 读和volatile写的内存语义,即编译器不能对CAS与CAS前面和后面的任意内存操作重排序。CAS会使用现代处理器上提供的高效机器级别原子指令,这些原子指令以原子方式对内存执行读-改-写操作,这是在多处理器中实现同步的关键。volatile变量的读/写和CAS可以实现线程之间的通信,如下</p>
<blockquote>
<ul>
<li>A线程写volatile变量,随后B线程读这个volatile变量。</li>
<li>A线程写volatile变量,随后B线程用CAS更新这个volatile变量。</li>
<li>A线程用CAS更新一个volatile变量,随后B线程用CAS更新这个volatile变量。</li>
<li>A线程用CAS更新一个volatile变量,随后B线程读这个volatile变量。</li>
</ul>
</blockquote>
<p>conocurrent包的通用实现模式</p>
<blockquote>
<ul>
<li>声明共享状态为volatile</li>
<li>使用CAS的原子条件更新来实现线程之间的同步</li>
<li>配合以volatile和CAS所具有的volatile读/写的内存语义,来实现线程之间的通信。</li>
</ul>
</blockquote>
<p><strong><em>final</em></strong><br>对于final域,只要对象是正确构造的(被构造对象的引用在构造函数中没有“逸出”),那么不需要使用同步(指lock和volatile的使用),就可以保证任意线程都能看到这个final域在构造函数中被初始化之后的值。<br>JSR133对写final域的重排序规则会要求译编器在final域的写之后,构造函数return之前,插入一个StoreStore障屏。读final域的重排序规则要求编译器在读final域的操作前面插入一个LoadLoad屏障。</p>
<p>JMM在不同的处理器中需要插入的内存屏障的数量和种类也不相同。</p>
<blockquote>
<ul>
<li>对于不计写读操作的处理器,JMM需要插入的内存屏障为StoreLoad Barries</li>
<li>对于不计写读操作和写写操作的处理器, JMM需要插入的内存屏障为StoreLoad Barries,StoreStore Barries.</li>
<li>对于不计写读,写写,读写和读读操作的处理器,JMM需要插入的内存屏障为StoreLoad Barries,StoreStore Barries,LoadStore Barries,LoadLoad Barries.</li>
</ul>
</blockquote>
<p>JSR-133对JDK5之前的旧内存模型的修补主要有两方面:</p>
<blockquote>
<ul>
<li>增强volatile的内存语义。旧内存模型允许volatile变量与普通变量重排序。JSR-133严格限制volatile变量与普通变量的重排序,使volatile的写-读和锁的释放-获取具有相同的内存语义。</li>
<li>增强final的内存语义。在旧内存模型中,多次读取同一个final变量的值可能会不相同。JSR-133为final增加了两个重排序规则。保证了final初始化的安全性。即如果一个对象的引用在构造阶段不允许逸出(escape),那么一旦构造函数完成,并且线程发布了对另一个对象的引用,那么在不使用同步的条件下,这个对象的final域字段就能保证对所有其他线程是可见的、正确的并且是不变的。</li>
</ul>
</blockquote>
]]></content>
<summary type="html">
<p>##Java Memory Model<br>线程之间的通信机制有两种:共享内存和消息传递。</p>
<blockquote>
<ul>
<li>线程之间的公共状态,在共享内存的并发模型里,是通过写-读内存中的公共状态来隐式进行通信。在消息传递的并发模型里,是通过明确的发送
</summary>