TCC和两阶段提交
经常在网络上看见有人介绍TCC时,都提一句,”TCC是两阶段提交的一种”。其理由是TCC将业务逻辑分成try、confirm/cancel在两个不同的阶段中执行。其实这个说法,是不正确的。可能是因为既不太了解两阶段提交机制、也不太了解TCC机制的缘故,于是将两阶段提交机制的prepare、commit两个事务提交阶段和TCC机制的try、confirm/cancel两个业务执行阶段互相混淆,才有了这种说法。 两阶段提交(Two Phase Commit,下文简称2PC),简单的说,是将事务的提交操作分成了prepare、commit两个阶段。其事务处理方式为: 1、 在全局事务决定提交时,a)逐个向RM发送prepare请求;b)若所有RM都返回OK,则逐个发送commit请求最终提交事务;否则,逐个发送rollback请求来回滚事务; 2、 在全局事务决定回滚时,直接逐个发送rollback请求即可,不必分阶段。 * 需要注意的是:2PC机制需要RM提供底层支持(一般是兼容XA),而TCC机制则不需要。 TCC(Try-Confirm-Cancel),则是将业务逻辑分成try、confirm/cancel两个阶段执行,具体介绍见TCC事务机制简介。其事务处理方式为: 1、 在全局事务决定提交时,调用与try业务逻辑相对应的confirm业务逻辑; 2、 在全局事务决定回滚时,调用与try业务逻辑相对应的cancel业务逻辑。 可见,TCC在事务处理方式上,是很简单的:要么调用confirm业务逻辑,要么调用cancel逻辑。这里为什么没有提到try业务逻辑呢?因为try逻辑与全局事务处理无关。 当讨论2PC时,我们只专注于事务处理阶段,因而只讨论prepare和commit,所以,可能很多人都忘了,使用2PC事务管理机制时也是有业务逻辑阶段的。正是因为业务逻辑的执行,发起了全局事务,这才有其后的事务处理阶段。实际上,使用2PC机制时————以提交为例————一个完整的事务生命周期是:begin -> 业务逻辑 -> prepare -> commit。 再看TCC,也不外乎如此。我们要发起全局事务,同样也必须通过执行一段业务逻辑来实现。该业务逻辑一来通过执行触发TCC全局事务的创建;二来也需要执行部分数据写操作;此外,还要通过执行来向TCC全局事务注册自己,以便后续TCC全局事务commit/rollback时回调其相应的confirm/cancel业务逻辑。所以,使用TCC机制时————以提交为例————一个完整的事务生命周期是:begin -> 业务逻辑(try业务) -> commit(comfirm业务)。 综上,我们可以从执行的阶段上将二者一一对应起来: 1、 2PC机制的业务阶段 等价于 TCC机制的try业务阶段; 2、 2PC机制的提交阶段(prepare & commit) 等价于 TCC机制的提交阶段(confirm); 3、 2PC机制的回滚阶段(rollback) 等价于 TCC机制的回滚阶段(cancel)。 因此,可以看出,虽然TCC机制中有两个阶段都存在业务逻辑的执行,但其中try业务阶段其实是与全局事务处理无关的。认清了这一点,当我们再比较TCC和2PC时,就会很容易地发现,TCC不是两阶段提交,而只是它对事务的提交/回滚是通过执行一段confirm/cancel业务逻辑来实现,仅此而已。 参考博客: 1. https://blog.csdn.net/Paranoia_ZK/article/details/79481976#commentsedit TCC和两阶段分布式事务处理的区别 2. https://blog.csdn.net/Saintyyu/article/details/100822735 X/Open DTP模型与XA协议之我见 3、https://blog.csdn.net/Saintyyu/article/details/101054542 分布式事务的七种实现方案汇总分析 from:https://blog.csdn.net/Saintyyu/article/details/100862449
View Details终于有人把“TCC分布式事务”实现原理讲明白了!
之前网上看到很多写分布式事务的文章,不过大多都是将分布式事务各种技术方案简单介绍一下。很多朋友看了还是不知道分布式事务到底怎么回事,在项目里到底如何使用。 所以这篇文章,就用大白话+手工绘图,并结合一个电商系统的案例实践,来给大家讲清楚到底什么是 TCC 分布式事务。 首先说一下,这里可能会牵扯到一些 Spring Cloud 的原理,如果有不太清楚的同学,可以参考之前的文章:《拜托,面试请不要再问我Spring Cloud底层原理!》。 业务场景介绍 咱们先来看看业务场景,假设你现在有一个电商系统,里面有一个支付订单的场景。 那对一个订单支付之后,我们需要做下面的步骤: 更改订单的状态为“已支付” 扣减商品库存 给会员增加积分 创建销售出库单通知仓库发货 这是一系列比较真实的步骤,无论大家有没有做过电商系统,应该都能理解。 进一步思考 好,业务场景有了,现在我们要更进一步,实现一个 TCC 分布式事务的效果。 什么意思呢?也就是说,[1] 订单服务-修改订单状态,[2] 库存服务-扣减库存,[3] 积分服务-增加积分,[4] 仓储服务-创建销售出库单。 上述这几个步骤,要么一起成功,要么一起失败,必须是一个整体性的事务。 举个例子,现在订单的状态都修改为“已支付”了,结果库存服务扣减库存失败。那个商品的库存原来是 100 件,现在卖掉了 2 件,本来应该是 98 件了。 结果呢?由于库存服务操作数据库异常,导致库存数量还是 100。这不是在坑人么,当然不能允许这种情况发生了! 但是如果你不用 TCC 分布式事务方案的话,就用个 Spring Cloud 开发这么一个微服务系统,很有可能会干出这种事儿来。 我们来看看下面的这个图,直观的表达了上述的过程: 所以说,我们有必要使用 TCC 分布式事务机制来保证各个服务形成一个整体性的事务。 上面那几个步骤,要么全部成功,如果任何一个服务的操作失败了,就全部一起回滚,撤销已经完成的操作。 比如说库存服务要是扣减库存失败了,那么订单服务就得撤销那个修改订单状态的操作,然后得停止执行增加积分和通知出库两个操作。 说了那么多,老规矩,给大家上一张图,大伙儿顺着图来直观的感受一下: 落地实现 TCC 分布式事务 那么现在到底要如何来实现一个 TCC 分布式事务,使得各个服务,要么一起成功?要么一起失败呢? 大家稍安勿躁,我们这就来一步一步的分析一下。咱们就以一个 Spring Cloud 开发系统作为背景来解释。 TCC 实现阶段一:Try 首先,订单服务那儿,它的代码大致来说应该是这样子的:
|
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 |
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OrderService</span> </span>{ <span class="hljs-comment">// 库存服务</span> <span class="hljs-meta">@Autowired</span> <span class="hljs-keyword">private</span> InventoryService inventoryService; <span class="hljs-comment">// 积分服务</span> <span class="hljs-meta">@Autowired</span> <span class="hljs-keyword">private</span> CreditService creditService; <span class="hljs-comment">// 仓储服务</span> <span class="hljs-meta">@Autowired</span> <span class="hljs-keyword">private</span> WmsService wmsService; <span class="hljs-comment">// 对这个订单完成支付</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">pay</span><span class="hljs-params">()</span></span>{ <span class="hljs-comment">//对本地的的订单数据库修改订单状态为"已支付"</span> orderDAO.updateStatus(OrderStatus.PAYED); <span class="hljs-comment">//调用库存服务扣减库存</span> inventoryService.reduceStock(); <span class="hljs-comment">//调用积分服务增加积分</span> creditService.addCredit(); <span class="hljs-comment">//调用仓储服务通知发货</span> wmsService.saleDelivery(); } } |
如果你之前看过 Spring Cloud 架构原理那篇文章,同时对 Spring Cloud 有一定的了解的话,应该是可以理解上面那段代码的。 其实就是订单服务完成本地数据库操作之后,通过 Spring Cloud 的 Feign 来调用其他的各个服务罢了。 但是光是凭借这段代码,是不足以实现 TCC 分布式事务的啊?!兄弟们,别着急,我们对这个订单服务修改点儿代码好不好。 首先,上面那个订单服务先把自己的状态修改为:OrderStatus.UPDATING。 这是啥意思呢?也就是说,在 pay() 那个方法里,你别直接把订单状态修改为已支付啊!你先把订单状态修改为 UPDATING,也就是修改中的意思。 这个状态是个没有任何含义的这么一个状态,代表有人正在修改这个状态罢了。 然后呢,库存服务直接提供的那个 reduceStock() 接口里,也别直接扣减库存啊,你可以是冻结掉库存。 […]
View DetailsVSCode插件开发全攻略(十)打包、发布、升级
更多文章请戳VSCode插件开发全攻略系列目录导航。 发布方式 插件开发完了,如何发布出去分享给他人呢?主要有3种方法: 方法一:直接把文件夹发给别人,让别人找到vscode的插件存放目录并放进去,然后重启vscode,一般不推荐; 方法二:打包成vsix插件,然后发送给别人安装,如果你的插件涉及机密不方便发布到应用市场,可以尝试采用这种方式; 方法三:注册开发者账号,发布到官网应用市场,这个发布和npm一样是不需要审核的。 本地打包 无论是本地打包还是发布到应用市场都需要借助vsce这个工具。 安装:
|
1 2 |
npm i vsce -g |
打包成vsix文件:
|
1 2 |
vsce package |
打包的时候如果没有设置repository会有提示,所以最好设置一下。 生成好的vsix文件不能直接拖入安装,只能从扩展的右上角选择Install from VSIX安装: 发布应用市场 Visual Studio Code的应用市场基于微软自己的Azure DevOps,插件的身份验证、托管和管理都是在这里。 要发布到应用市场首先得有应用市场的publisher账号; 而要有发布账号首先得有Azure DevOps组织; 而创建组织之前,首先得创建Azure账号; 创建Azure账号首先得有Microsoft账号; 是不是有点晕,梳理一下: 一个Microsoft账号可以创建多个Azure组织; 一个组织可以创建多个publisher账号; 同时一个组织可以创建多个PAT(Personal Access Token,个人访问令牌); 3.1. 注册账号 首先访问 https://login.live.com/ 登录你的Microsoft账号,没有的先注册一个: 然后访问: https://aka.ms/SignupAzureDevOps ,如果你从来没有使用过Azure,那么会看到如下提示: 点击继续,默认会创建一个以邮箱前缀为名的组织。 3.2. 创建令牌 默认进入组织的主页后,点击右上角的Security: 点击创建新的个人访问令牌,这里特别要注意Organization要选择all accessible organizations,Scopes要选择Full access,否则后面发布会失败。 创建令牌成功后你需要本地记下来,因为网站是不会帮你保存的。 3.3. 创建发布账号 获得个人访问令牌后,使用vsce以下命令创建新的发布者:
|
1 2 |
vsce create-publisher your-publisher-name |
your-publisher-name必须是字母数字下划线,这是全网唯一的账号,然后会依次要求输入昵称、邮箱、令牌: 创建成功后会默认登录这个账号,接下来你可以直接发布了,当然,如果你是在其它地方创建的,可以试用vsce login your-publisher-name来登录。 除了用命令之外,你还可以使用网页版创建发布账号:https://marketplace.visualstudio.com/manage 3.4. 发布 发布很简单:
|
1 2 |
vsce publish |
发布成功后大概需要过几分钟才能在应用市场搜到。过几分钟就可以访问网页版的插件主页:https://marketplace.visualstudio.com/items?itemName=sxei.vscode-plugin-demo vscode里面也能搜到了: 3.4.1. 发布注意事项 README.md文件默认会显示在插件主页; README.md中的资源必须全部是HTTPS的,如果是HTTP会发布失败; CHANGELOG.md会显示在变更选项卡; 如果代码是放在git仓库并且设置了repository字段,发布前必须先提交git,否则会提示Git working directory not clean; 另外,如前面所说,如果Organization没有选择all accessible organizations,或者Scopes没有选择Full access,发布的时候可能会报如下错误:
|
1 2 3 4 |
Error: Failed Request: Unauthorized(401) - https://marketplace.visualstudio.com/_apis/gallery Be sure to use a Personal Access Token <span class="hljs-built_in">which</span> has access to **all accessible accounts**. See https://code.visualstudio.com/docs/tools/vscecli<span class="hljs-comment">#_common-questions for more information.</span> |
3.4.2. 增量发布 版本号:major.minor.patch 如果想让发布之后版本号的patch自增,例如:1.0.2 -> 1.0.3,可以这样:
|
1 2 |
vsce publish patch |
执行这个命令后会自动修改package.json里面的版本号。同理,vsce publish minor也是可以的。 3.5. 取消发布
|
1 2 |
vsce unpublish (publisher name).(extension name) |
3.6. 更新 如果修改了插件代码想要重新发布,只需要修改版本号然后重新执行vsce publish即可。 插件升级 4.1. 发布到了应用市场 如果发布到了应用市场,那么一般来说会自动检测有没有新版本,有的话会自动无感知升级,但具体什么时候会去检测我还没有研究过,已经确定的是在扩展面板搜索插件名字会自动检测,重启vscode也会检测。 4.2. 如果是本地打包 如果是打包成vsix,那么只能自己实现升级检测功能呢,通过对比服务器上某个文件的版本号,具体我就不细讲了。 […]
View DetailsVSCode插件开发全攻略(一)概览
文章索引 VSCode插件开发全攻略(一)概览 VSCode插件开发全攻略(二)HelloWord VSCode插件开发全攻略(三)package.json详解 VSCode插件开发全攻略(四)命令、菜单、快捷键 VSCode插件开发全攻略(五)跳转到定义、自动补全、悬停提示 VSCode插件开发全攻略(六)开发调试技巧 VSCode插件开发全攻略(七)WebView VSCode插件开发全攻略(八)代码片段、设置、自定义欢迎页 VSCode插件开发全攻略(九)常用API总结 VSCode插件开发全攻略(十)打包、发布、升级 本系列文章同步首发于多个平台,限于精力有限,后续如有更新和修改,仅更新我的个人博客上的内容,欢迎戳这里查看最新版:http://blog.haoji.me/vscode-plugin-overview.html 写在前面 一年前我写了一篇3万多字的Chrome插件(扩展)开发全攻略,反响还不错,帮助了很多新手快速上手,甚至包括大名鼎鼎的红芯浏览器(戳这里了解更多)。 最近因工作需要又接触到了vscode插件开发,所以趁势再写一篇有关vscode插件开发的文章,记录一些自己踩过的坑以及接触vscode插件开发这2个多月以来的心得体会,让大家少走一些弯路避免重复踩坑。 目前网上有关介绍vscode插件开发的文章也有挺多的,但都不够深入,基本上都是点到为止,篇幅不大,本系列文章争取多讲一些,涵盖面会更广,干货更多。 鉴于之前写过几篇内容较多的文章大家都反馈说阅读麻烦,一篇文章内容太多看起来太累,所以这次就拆分来写。 关于vscode插件 相信大家对vscode应该都不陌生,VSCode是微软出的一款轻量级代码编辑器,免费而且功能强大,以功能强大、提示友好、不错的性能和颜值俘获了大量开发者的青睐,对JavaScript和NodeJS的支持非常好,自带很多功能,例如代码格式化,代码智能提示补全、Emmet插件等。 再强大的IDE那也不可能面面俱到什么功能都塞进去,那样只会导致IDE本身太臃肿。功能嘛,按需索取,所以,vscode的很多强大功能都是基于插件实现的,IDE只提供一个最基本的框子和最基本功能,由插件来丰富和扩展它的功能。 vscode插件可以很轻松的在应用商店搜索并下载到,应用商店官网是:https://marketplace.visualstudio.com/vscode ,vscode推出时间本身并不长,但生态发展得非常好,应用商店已经有各种各样丰富的插件供大家使用了。 因为vscode本身都是用浏览器实现的,所以其插件不用说肯定也是基于HTML+JS等前端技术实现,从形式上看就是一个类似于npm包的vsix文件,只不过按照一些特殊规范来实现一些特殊功能,所以vscode插件开发难度不大,甚至可以说熟悉了相关API之后很容易。 有必要学习vscode插件开发吗 有!而且非常有必要!每个人都会多多少少有一些自己的特殊定制需求,当你不知道开发一个IDE插件其实也很容易、或者你没有意识到通过开发插件可以帮你提升多大效率时,你并不会下意识的将一些问题的解决方式往IDE插件开发上去想。至少我曾经就是这样的,提升开发效率大部分时候想到的都是写一些脚本工具、写一些浏览器插件、写一些客户端工具等,接触到IDE插件开发之后发现原来有些问题可以通过更高效的方式来解决,毕竟IDE才是我们程序员每天接触最多的东西。 但至于可以开发什么样的插件、实现什么样的功能、以什么样的形式呈现,这就要靠你从工作和生活中去发现、去找灵感并提炼了。 demo下载 本系列文章所有demo均在这个仓库里:https://github.com/sxei/vscode-plugin-demo ,可以直接下载运行。当然还有更简单的,这个demo已经发布到应用市场了,大家可以直接点击这里下载安装,或则您也可以直接在vscode里面搜索plugin-Demo就能搜到: vscode插件能做什么 既然前面讲到学习vscode插件开发很有必要,那插件到底能做什么呢?能实现什么功能?能从哪些方面动手脚?下面我们就来列举一些好让大家有个大概了解。 6.1. 不受限的本地磁盘访问 因为vscode是基于Electron开发的,可以使用nodejs随意读写本地文件、跨域请求、甚至创建一个本地server,这都是没有任何限制的,所以只要你想做,基本上没有不能实现的。 6.2. 自定义命令、快捷键、菜单 vscode插件很多功能都是基于一个个命令实现的,我们可以自定义一些命令,这个命令将出现在按下Ctrl+Shift+P后的命令列表里面,同时可以给命令配置快捷键、配置资源管理器菜单、编辑器菜单、标题菜单、下拉菜单、右上角图标等。 6.3. 自定义跳转、自动补全、悬浮提示 自定义跳转: 自动补全: 提示: 6.4. 自定义设置、自定义欢迎页 6.5. 自定义WebView 6.6. 自定义左侧功能面板 6.7. 自定义颜色、图标主题 6.8. 新增语言支持 给某一种原有没有的语言提供语言支持,语言支持包括很多方面,比如代码高亮、语法解析、折叠、跳转、补全等; 6.9. Markdown增强 你可以自定义markdown预览的样式、添加一些新语法、新功能的支持。 6.10. 其它 其它还有比如状态栏修改、通知提示、编辑器控制、git源代码控制、任务定义、Language Server、Debug Adapter等等。 收尾 本文作为开篇,不做太多详细介绍,只是为了让大家对vscode插件有一个大致了解,后面再分篇慢慢细讲。 参考资料 微软VSCode插件开发官方文档:https://code.visualstudio.com/docs/extensions/overview from:https://www.cnblogs.com/liuxianan/p/vscode-plugin-overview.html
View Detailsnginx http to https
if ($server_port !~ 443){ rewrite ^(/.*)$ https://$host$1 permanent; }
View DetailsJS判断是否是数组
1、通过instanceof判断 instanceof运算符用于检验构造函数的prototype属性是否出现在对象的原型链中的任何位置,返回一个布尔值。
|
1 2 3 4 |
let a = []; a instanceof Array; //true let b = {}; b instanceof Array; //false |
在上方代码中,instanceof运算符检测Array.prototype属性是否存在于变量a的原型链上,显然a是一个数组,拥有Array.prototype属性,所以为true。 需要注意的是,prototype属性是可以修改的,所以并不是最初判断为true就一定永远为真。 其次,当我们的脚本拥有多个全局环境,例如html中拥有多个iframe对象,instanceof的验证结果可能不会符合预期,例如:
|
1 2 3 4 5 6 7 8 |
//为body创建并添加一个iframe对象 var iframe = document.createElement('iframe'); document.body.appendChild(iframe); //取得iframe对象的构造数组方法 xArray = window.frames[0].Array; //通过构造函数获取一个实例 var arr = new xArray(1,2,3); arr instanceof Array;//false |
导致这种问题是因为iframe会产生新的全局环境,它也会拥有自己的Array.prototype属性,让不同环境下的属性相同很明显是不安全的做法,所以Array.prototype !== window.frames[0].Array.prototype,想要arr instanceof Array为true,你得保证arr是由原始Array构造函数创建时才可行。 2、通过constructor判断 我们知道,实例的构造函数属性constructor指向构造函数,那么通过constructor属性也可以判断是否为一个数组。
|
1 2 |
let a = [1,3,4]; a.constructor === Array;//true |
同样,这种判断也会存在多个全局环境的问题,导致的问题与instanceof相同。 3、通过Object.prototype.toString.call()判断 Object.prototype.toString().call()可以获取到对象的不同类型,多个全局环境也适用
|
1 2 3 4 5 6 7 8 9 |
// 检验是否是数组 let a = [1,2,3] Object.prototype.toString.call(a) === '[object Array]';//true //检验是否是函数 let b = function () {}; Object.prototype.toString.call(b) === '[object Function]';//true //检验是否是数字 let c = 1; Object.prototype.toString.call(c) === '[object Number]';//true |
4、通过Array.isArray()判断 简单好用,而且对于多全局环境,Array.isArray() 同样能准确判断,但有个问题,Array.isArray() 是在ES5中提出,也就是说在ES5之前可能会存在不支持此方法的情况。
|
1 2 |
let a = [1,2,3] Array.isArray(a);//true |
最终推荐方法
|
1 2 3 4 5 |
if (!Array.isArray) { Array.isArray = function(arg) { return Object.prototype.toString.call(arg) === '[object Array]'; }; } |
from:https://www.cnblogs.com/chenmeijiao/p/12060845.html
View DetailsUnsupported Modules Detected: Compilation is not supported for following modules: app, KeyboardView.
打开AS时出现了Unsupported Modules Detected: Compilation is not supported for following modules: app, KeyboardView. Unfortunately you can’t have non-Gradle Java modules and Android-Gradle modules in one project的错误,解决步骤如下: (1)关闭as (2)删除.idea目录 (3)删除app/build目录 (4)重新打开as from:https://blog.csdn.net/qq_40600379/article/details/106485687
View Detailsnetstat查看端口状态
netstat netstat -tunlp 用于显示 tcp,udp 的端口和进程等相关情况。 netstat 查看端口占用语法格式:
|
1 |
netstat -tunlp | grep 端口号 |
-t (tcp) 仅显示tcp相关选项 -u (udp)仅显示udp相关选项 -n 拒绝显示别名,能显示数字的全部转化为数字 -l 仅列出在Listen(监听)的服务状态 -p 显示建立相关链接的程序名 例如查看 8000 端口的情况,使用以下命令:
|
1 2 |
# netstat -tunlp | grep 8000 tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN 26993/nodejs |
更多命令:
|
1 2 3 |
netstat -ntlp //查看当前所有tcp端口 netstat -ntulp | grep 80 //查看所有80端口使用情况 netstat -ntulp | grep 3306 //查看所有3306端口使用情况 |
from:https://www.cnblogs.com/music-liang/p/11912928.html
View DetailsNo cached version of com.android.tools.build:gradle:3.6.2 available for offlin 解决办法
忙了一早晨,就是因为这个错误提示!!!!No cached version of com.android.tools.build:gradle:3.6.2 available for offlin 先说我的android studio 版本号:3.6.2 在之前的版本当中Settings->Builder….bababa… >gradel> offline work有这么个选项,但是在最新的版本当中是没有这个选项的!!!我找了一早晨!! 好了废话不多说,正题,位置在哪里?在这里!!! 默认的状态是: 你只要取消选中就是offline work不启动,也就是离线模式不不启用!!如果在截图当中没有这个,那么这个界面就在view->window tool->gradle,只要你选择了就会在右则弹出来这个选项 from:https://www.cnblogs.com/flay/p/12641381.html
View Details安卓解决:Could not resolve all artifacts for configuration ':classpath’;
前天电脑重装了系统,所有东西重新配置,打开项目编译后发现:Could not resolve all artifacts for configuration ':classpath';这是什么鬼,然后常规clean、rebuild、offline work、修改本地gradle…一番操作之后,依然没用。最后上google寻求帮助,成功解决了这个问题。真凶尚不明确,怀疑是网络问题,资源库加载不下来。 解决办法如下:在根目录的build文件里加上这两句镜像代码,重新编译解决
|
1 |
maven{url 'http://maven.aliyun.com/nexus/content/groups/public/'} |
from:https://blog.csdn.net/c18871189293/article/details/105681103
View Details