Spring Boot 入门之基础篇

世界上最好的官方教程:https://docs.spring.io/spring-boot/docs/1.5.8.RELEASE/reference/html/index.html
中文版本:https://blog.csdn.net/qq_36348557/article/details/69396589
maven全局配置文件settings.xml详解:https://blog.csdn.net/u012225679/article/details/73740785
https://www.extlight.com/2017/11/23/Spring-Boot-%E5%85%A5%E9%97%A8%E4%B9%8B%E5%9F%BA%E7%A1%80%E7%AF%87%EF%BC%88%E4%B8%80%EF%BC%89/

https://www.cnblogs.com/zengkefu/p/5742617.html

部署项目教程参考:https://blog.csdn.net/taoshujian/article/details/75570780

分布式事务XA解决方案之两阶段提交(2PC)

https://zh.wikipedia.org/wiki/%E4%BA%8C%E9%98%B6%E6%AE%B5%E6%8F%90%E4%BA%A4

对于三阶段提交请参考:
https://www.cnblogs.com/binyue/p/3678390.html
https://www.cnblogs.com/charlesblc/p/6289348.html

计算机网络以及数据库领域内,二阶段提交英语:Two-phase Commit)是指,为了使基于分布式系统架构下的所有节点在进行事务提交时保持一致性而设计的一种算法(Algorithm)。通常,二阶段提交也被称为是一种协议(Protocol)。在分布式系统中,每个节点虽然可以知晓自己的操作时成功或者失败,却无法知道其他节点的操作的成功或失败。当一个事务跨越多个节点时,为了保持事务的ACID特性,需要引入一个作为协调者的组件来统一掌控所有节点(称作参与者)的操作结果并最终指示这些节点是否要把操作结果进行真正的提交(比如将更新后的数据写入磁盘等等)。因此,二阶段提交的算法思路可以概括为: 参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作。

需要注意的是,二阶段提交(英文缩写:2PC)不应该与并发控制中的二阶段锁(英文缩写:2PL)进行混淆。

前提[编辑]

二阶段提交算法的成立基于以下假设:

  1. 该分布式系统中,存在一个节点作为协调者(Coordinator),其他节点作为参与者(Cohorts)。且节点之间可以进行网络通信。
  2. 所有节点都采用预写式日志,且日志被写入后即被保持在可靠的存储设备上,即使节点损坏不会导致日志数据的消失。
  3. 所有节点不会永久性损坏,即使损坏后仍然可以恢复。

基本算法[编辑]

以下对二阶段提交算法分阶段进行说明。

第一阶段(提交请求阶段)[编辑]

  1. 协调者节点向所有参与者节点询问是否可以执行提交操作,并开始等待各参与者节点的响应。
  2. 参与者节点执行询问发起为止的所有事务操作,并将Undo信息Redo信息写入日志。
  3. 各参与者节点响应协调者节点发起的询问。如果参与者节点的事务操作实际执行成功,则它返回一个”同意”消息;如果参与者节点的事务操作实际执行失败,则它返回一个”中止”消息。

有时候,第一阶段也被称作投票阶段,即各参与者投票是否要继续接下来的提交操作。

第二阶段(提交执行阶段)[编辑]

成功[编辑]

当协调者节点从所有参与者节点获得的相应消息都为”同意”时:

  1. 协调者节点向所有参与者节点发出”正式提交”的请求。
  2. 参与者节点正式完成操作,并释放在整个事务期间内占用的资源。
  3. 参与者节点向协调者节点发送”完成”消息。
  4. 协调者节点收到所有参与者节点反馈的”完成”消息后,完成事务。

失败[编辑]

fail

如果任一参与者节点在第一阶段返回的响应消息为”终止”,或者 协调者节点在第一阶段的询问超时之前无法获取所有参与者节点的响应消息时:

  1. 协调者节点向所有参与者节点发出”回滚操作”的请求。
  2. 参与者节点利用之前写入的Undo信息执行回滚,并释放在整个事务期间内占用的资源。
  3. 参与者节点向协调者节点发送”回滚完成”消息。
  4. 协调者节点收到所有参与者节点反馈的”回滚完成”消息后,取消事务。

有时候,第二阶段也被称作完成阶段,因为无论结果怎样,协调者都必须在此阶段结束当前事务。

算法示意[编辑]

下述流程图简单示意了二阶段提交算法中协调者和参与者之间的通信流程

    协调者                                              参与者
                              QUERY TO COMMIT
                -------------------------------->
                              VOTE YES/NO           prepare*/abort*
                <-------------------------------
commit*/abort*                COMMIT/ROLLBACK
                -------------------------------->
                              ACKNOWLEDGMENT        commit*/abort*
                <--------------------------------  
end

“*” 所标记的操作意味着此类操作必须记录在稳固存储上.[1]

缺点[编辑]

二阶段提交算法的最大缺点就在于 它的执行过程中间,节点都处于阻塞状态。即节点之间在等待对方的相应消息时,它将什么也做不了。特别是,当一个节点在已经占有了某项资源的情况下,为了等待其他节点的响应消息而陷入阻塞状态时,当第三个节点尝试访问该节点占有的资源时,这个节点也将连带陷入阻塞状态。

另外,协调者节点指示参与者节点进行提交等操作时,如有参与者节点出现了崩溃等情况而导致协调者始终无法获取所有参与者的响应信息,这时协调者将只能依赖协调者自身的超时机制来生效。但往往超时机制生效时,协调者都会指示参与者进行回滚操作。这样的策略显得比较保守。

推荐:https://timyang.net/distributed/time-to-move-on-from-two-phase/

关联条目[编辑]

参照[编辑]

  1. 跳转^ C. Mohan, Bruce Lindsay and R. Obermarck (1986): “Transaction management in the R* distributed database management system”,ACM Transactions on Database Systems (TODS), Volume 11 Issue 4, Dec. 1986, Pages 378 – 396

了解MySQL中的字符集

https://dev.mysql.com/doc/refman/5.7/en/charset.html

平时我们只说了字符集这个概念,另外还有对应的“字符序”。一个字符集(如utf8)对应多个字符序(utf8_general_ci、utf8_german2_ci等),每个字符集都有一个默认“字符序”。

什么是字符集、字符序?简单的来说:

  1. 字符集(character set):定义了字符以及字符的存储编码。
  2. 字符序(collation):定义了字符的比较规则。

可以通过命令查看字符集、字符序信息:

SHOW CHARACTER SET;

在我们开发中,一般要保持服务器端的字符集与客户端的字符集保持一致,不然容易出现乱码的情况。

MySQL提供了不同级别的设置,包括server级、database级、table级、column级,可以提供非常精准的设置。

参考文章:https://www.cnblogs.com/chyingp/p/mysql-character-set-collation.html

Linux下对进程通信管理的信号机制概述

今天看到了篇使用golang实现的系统无感重启的文章,https://gravitational.com/blog/golang-ssh-bastion-graceful-restarts/,一般用来平滑处理一些系统服务,避免先停止再启用导致的服务不可用的情况。其中用到了信号机制,这里找了一些文章主要有来介绍这方面的文章,以便加深理解。https://blog.csdn.net/junyucsdn/article/details/50519248

https://blog.csdn.net/tiany524/article/details/17048069

https://my.oschina.net/chenliang165/blog/125825

MySQL中的sql_mode模式

官方文档:https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sql-mode-setting

一、模式分类

在MySQL8.0中主要包括以下几种模式

ONLY_FULL_GROUP_BY 对于GROUP BY聚合操作,如果在SELECT中的列,没有在GROUP BY中出现,那么将认为这个SQL是不合法的,因为列不在GROUP BY从句中
STRICT_TRANS_TABLES 在该模式下,如果一个值不能插入到一个事务表中,则中断当前的操作,对非事务表不做任何限制
NO_ZERO_IN_DATE 在严格模式,不接受月或日部分为0的日期。如果使用IGNORE选项,我们为类似的日期插入’0000-00-00’。在非严格模式,可以接受该日期,但会生成警告。
NO_ZERO_DATE 在严格模式,不要将 ‘0000-00-00’做为合法日期。你仍然可以用IGNORE选项插入零日期。在非严格模式,可以接受该日期,但会生成警告
ERROR_FOR_DIVISION_BY_ZERO 在严格模式,在INSERT或UPDATE过程中,如果被零除(或MOD(X,0)),则产生错误(否则为警告)。如果未给出该模式,被零除时MySQL返回NULL。如果用到INSERT IGNORE或UPDATE IGNORE中,MySQL生成被零除警告,但操作结果为NULL。
NO_ENGINE_SUBSTITUTION 如果需要的存储引擎被禁用或未编译,那么抛出错误。不设置此值时,用默认的存储引擎替代,并抛出一个异常。

修改当前数据库的模式,有两种办法,一种是全局,一种是会话期间

SET GLOBAL sql_mode = 'modes';
SET SESSION sql_mode = 'modes';

同样,查看方法为

SELECT @@GLOBAL.sql_mode;
SELECT @@SESSION.sql_mode;

二、最重要的几种sql_mode

ANSI模式 宽松模式,对插入数据进行校验,如果不符合定义类型或长度,对数据类型调整或截断保存,报warning警告。
ANSI模式等于
 REAL_AS_FLOATPIPES_AS_CONCATANSI_QUOTESIGNORE_SPACE, and ONLY_FULL_GROUP_BY几种的组合。
TRADITIONAL模式 严格模式,当向mysql数据库插入数据时,进行数据的严格校验,保证错误数据不能插入,报error错误。用于事物时,会进行事物的回滚。等于STRICT_TRANS_TABLESSTRICT_ALL_TABLESNO_ZERO_IN_DATENO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO, and NO_ENGINE_SUBSTITUTION.的组合
STRICT_TRANS_TABLES模式 严格模式,进行数据的严格校验,错误数据不能插入,报error错误。

目前新版本MySQL5.7.22的默认模式为 STRICT_TRANS_TABLESNO_ENGINE_SUBSTITUTION 两种。对于不同版本默认的sql_mode可查看https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_sql_mode

 

了解MySQL中的驱动表

一、为什么要用小表驱动大表

1、驱动表的定义

当进行多表连接查询时, [驱动表] 的定义为:

1)指定了联接条件时,满足查询条件的记录行数少的表为[驱动表]

2)未指定联接条件时,行数少的表为[驱动表](重要)

忠告:如果你搞不清楚该让谁做驱动表、谁 join 谁,请让 MySQL 运行时自行判断

既然“未指定联接条件时,行数少的表为[驱动表]”了,而且你也对自己写出的复杂的 Nested Loop Join 不太有把握(如下面的实例所示),就别指定谁 left/right join 谁了,请交给 MySQL优化器 运行时决定吧。

2、mysql关联查询的概念:

MySQL 表关联的算法是 Nest Loop Join(嵌套循环),是通过驱动表的结果集作为循环基础数据,然后一条一条地通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。

例: user表10000条数据,class表20条数据

SELECT * FROM user u LEFT JOIN class c u.userid=c.userid

这样则需要用user表循环10000次才能查询出来,而如果用class表驱动user表则只需要循环20次就能查询出来

SELECT * FROM class c LEFT JOIN user u c.userid=u.userid

小结果集驱动大结果集

de.cel 在2012年总结说,不管是你,还是 MySQL,优化的目标是尽可能减少JOIN中Nested Loop的循环次数。

以此保证:永远用小结果集驱动大结果集(Important)!

相关算法参考:https://blog.csdn.net/caomiao2006/article/details/52205177

二、优化联表查询

优化第一步之:根据驱动表的字段排序

left join不变,干嘛要根据非驱动表的字段排序呢?我们前面说过“对驱动表可以直接排序,对非驱动表(的字段排序)需要对循环查询的合并结果(临时表)进行排序!”的。

explain

SELECT mb.id……

FROM mb LEFT JOIN mbei ON mb.id=mbei.mb_id INNER JOINu ON mb.uid=u.uid

WHERE 1=1

ORDER BY mb.id DESC

limit 0,10

也满足业务场景,做到了rows最小:

优化第二步:去除所有JOIN,让MySQL自行决定,explain第一张表就是驱动表,数据量比其它两张表都要小!

explain
SELECT mb.id…… 
FROM mb,mbei,u   
WHERE 
    mb.id=mbei.mb_id
    and mb.uid=u.user_id
order by mbei.apply_time desc
limit 0,10

立竿见影,驱动表一样是小表 mbei:

id select_type table   type    possible_keys      key          key_len  ref                rows    Extra
1  SIMPLE        mbei ALL      mb_id  (NULL)      (NULL)      (NULL)                         13388 Using filesort
1  SIMPLE        mb      eq_ref  PRIMARY,userid  PRIMARY 4            mbei.mb_id   1
1  SIMPLE        u         eq_ref  PRIMARY            PRIMARY 4            mb.uid           1  Using index

 

三、总结

1、不要过于相信你的运气!

2、不要相信你的开发环境里SQL的执行速度!

3、请拿起 explain 武器,如果你看到以下现象,请优化:

1)出现了Using temporary

2)rows过多,或者几乎是全表的记录数

3)key 是 (NULL)

4)possible_keys 出现过多(待选)索引.

推荐阅读:什么情况下会用到临时表