Monthly Archives: June 2018
时间复杂度:O(1)、O(n)、O(n²)、O(nlogn)等
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)进行混淆。
前提[编辑]
二阶段提交算法的成立基于以下假设:
- 该分布式系统中,存在一个节点作为协调者(Coordinator),其他节点作为参与者(Cohorts)。且节点之间可以进行网络通信。
- 所有节点都采用预写式日志,且日志被写入后即被保持在可靠的存储设备上,即使节点损坏不会导致日志数据的消失。
- 所有节点不会永久性损坏,即使损坏后仍然可以恢复。
基本算法[编辑]
以下对二阶段提交算法分阶段进行说明。
第一阶段(提交请求阶段)[编辑]
- 协调者节点向所有参与者节点询问是否可以执行提交操作,并开始等待各参与者节点的响应。
- 参与者节点执行询问发起为止的所有事务操作,并将Undo信息和Redo信息写入日志。
- 各参与者节点响应协调者节点发起的询问。如果参与者节点的事务操作实际执行成功,则它返回一个”同意”消息;如果参与者节点的事务操作实际执行失败,则它返回一个”中止”消息。
有时候,第一阶段也被称作投票阶段,即各参与者投票是否要继续接下来的提交操作。
第二阶段(提交执行阶段)[编辑]
成功[编辑]
当协调者节点从所有参与者节点获得的相应消息都为”同意”时:
- 协调者节点向所有参与者节点发出”正式提交”的请求。
- 参与者节点正式完成操作,并释放在整个事务期间内占用的资源。
- 参与者节点向协调者节点发送”完成”消息。
- 协调者节点收到所有参与者节点反馈的”完成”消息后,完成事务。
失败[编辑]
如果任一参与者节点在第一阶段返回的响应消息为”终止”,或者 协调者节点在第一阶段的询问超时之前无法获取所有参与者节点的响应消息时:
- 协调者节点向所有参与者节点发出”回滚操作”的请求。
- 参与者节点利用之前写入的Undo信息执行回滚,并释放在整个事务期间内占用的资源。
- 参与者节点向协调者节点发送”回滚完成”消息。
- 协调者节点收到所有参与者节点反馈的”回滚完成”消息后,取消事务。
有时候,第二阶段也被称作完成阶段,因为无论结果怎样,协调者都必须在此阶段结束当前事务。
算法示意[编辑]
下述流程图简单示意了二阶段提交算法中协调者和参与者之间的通信流程
协调者 参与者 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/
关联条目[编辑]
参照[编辑]
- 跳转^ 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等),每个字符集都有一个默认“字符序”。
什么是字符集、字符序?简单的来说:
- 字符集(character set):定义了字符以及字符的存储编码。
- 字符序(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
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_FLOAT , PIPES_AS_CONCAT , ANSI_QUOTES , IGNORE_SPACE , and ONLY_FULL_GROUP_BY 几种的组合。 |
TRADITIONAL模式 | 严格模式,当向mysql数据库插入数据时,进行数据的严格校验,保证错误数据不能插入,报error错误。用于事物时,会进行事物的回滚。等于STRICT_TRANS_TABLES , STRICT_ALL_TABLES , NO_ZERO_IN_DATE , NO_ZERO_DATE ,ERROR_FOR_DIVISION_BY_ZERO , and NO_ENGINE_SUBSTITUTION .的组合 |
STRICT_TRANS_TABLES模式 | 严格模式,进行数据的严格校验,错误数据不能插入,报error错误。 |
目前新版本MySQL5.7.22的默认模式为 STRICT_TRANS_TABLES, NO_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 出现过多(待选)索引.
推荐阅读:什么情况下会用到临时表