00:00
现在呢,我们来看一下第四种玩法,就是MYSQ的乐观锁。MY乐观锁它需要借助于时间戳或者是无性版本号等于实现。那么它需要依赖于CIS这种机制,这种机制啊。好,那么这种CS机制啊,MYSQ本身呢,并没有,那需要我们呢,通过代码,通过SQL语句来去实现。好,我们把这一块呢给它移走,然后把我们这个呢,给它放大一点。那么什么是CS呢?咱们要去了解什么是CS,好,咱们去说明一下啊,CS是个什么东西?那么其实CS它的全称啊是compare and sweep,翻过来什么意思呢?哎,经常也有人呢,会误会成啥呢,误会成。
01:01
Compare and set and set,那其实呢,这是不对的啊,全称呢,应该是compare and sweep。那么它翻译过来就是比较并交换的意思啊,比较并交换的意思。CS到底怎么理解呢?那么CS呢,一般会有三个元素,一个呢是变量X,如果变量X的值等于旧值A,那我就可以更新为新值B。如果X的值不等于就值A,那么则放弃本次更新。那么在生活中呢?我们也有这种例子。啊,很多同学呢,应该都玩过啊,我们的修改密码。那么修改密码呀,咱怎么修改呢?我们首先会输入一个用户名,那么这个用户名就类似于我们的X。然后我们还要去输入旧的密码,这个旧的密码呢,就类似于我们的A。
02:02
那我们还会输入新的密码。新的密码呢,就类似于我们的B。如果X的值。等于这个旧密码的情况下啊,或者说呢,这个用户名的旧密码输入正确的情况下,A,输入正确的情况下,我才能去更新密码B。更新为B,那否则呢,我们应该是放弃本次修改。那么这这就是CS思想了。那么在数据库里面,我们的乐观锁。这个CS利用时间拖和版本号来实现。那么这里的话呢,MYSQ本身啊,它其实并没有这种东西啊。我们只能借助于。呃,额外的一些列,以及通过SQL语句或者代码来去实现它。那我们来看一下,首先呢,我们只要在MYSQL数据库表里面增加一列哈。这一列呢,可以是时间戳。
03:02
那么也可以是我们的版本号。那么这两个呢,都是可以的。那比如说时间戳,那么在数据库表啊,最后呢,咱可以添加一列,这一列呢,是时间戳这一列啊OK,那么咱每次写的时候呢,我们都会更新时间戳。把时间出呢设置为你当前最新系统时间就可以了。那比如说呢,我们来去查询库存的时候,那我们都可以去。根据商品编号来查询。那么此时我们会查询到这两条记录,那就可以从两条记录里面的一条记录中来去扣减库存了,比如说呢,我就可以从这条记录里面来去扣减库存。那么扣减的时候,那怎么扣减呢?那么其实本质呢,就是更新啊。那假如说我已经查询到固定数量是4997件,那那time啊time simple,那时间戳已经查询到了。
04:05
都已经查询到了,那咱更新的时候,咱肯定要在这个数量的基础上得以减一,咱肯定是塞,那么count,那么等于呢,4996。并且这个时间戳,因为我要更新了,所以时间拖了,大家去重置来一个啊time啊STEM,然后等一下,等于系统当前时间。那么条件更新条件我们应该是VRID等于一我要更新这条库存记录,那么同时呢,还得要再加一个条件and。我们的时间戳和我查询那个时间戳,和我上一步查询那个时间戳,那么是不是一样子的,如果不一样了,那说明什么?说明这个中间有其他人介入了。有其他人也来做写的操作了,哎,可能是更新啊,可能是更新操作。
05:03
那么如果我这里呢,依然不管不顾这一块呢,我不管不顾,然后去更新的话,就会出现什么情况。这个库存数量可能早已经不是4997了。但是你还在这个4997的基础上减一键更新进去呢。哎,那就会出现并发性的问题。所以呢,如果如果我们这里的话呢,不加它就出问题啊。所以呢,咱一定得要加这样的一个玩意儿来去判断时间戳是不是和我第一步查询的这个时间戳是一样的。那么如果不一样,咱第二步者更新操作就不应该发生了,所以咱就要加上这样的一个条件。那不更新咋办呢?咱们再进行重试呀,我再去查,然后再去更新啊,判断判断更新,再去查,再去判断更新。知道什么位置呢?知道我查询的这个时间戳。和更新时是时间戳是一样的情况下。
06:03
那我才能去执行更新操作啊。OK,那么这咱们这个时间出这个东西。它呢可以解决。那我们这个version呢,其实思路呢也是一样的啊,那我们也可以呢,在表里面添加一个version。模型,那么我们呢,可以直接的去演示一下,比如说呢,我们就选择version。我可以呢,在数据库表里面来去添加一个栏位,这个栏位呢,就是version这样一个玩意儿,我就来一个int类型的。In类型的,然后不为空。好,我来去保存一下。绑定好之后呢,来看一下,那我们的数据库就多了一个version这样的一个字段。那么version字段啊,哎,我每次写呢,咱都可以递增,递增一啊A加一。那么在查询的时候呢,我们会查询出我们的库存以及呢对应的版本号。
07:02
那比如咱第一步查询,我们可以查询出库存呢,是4000。4997件库存单元号呢是零。那么第二步更新的时候,那咱可以这样子啊,跟时间抽呢有点类似。肯定是在4997的基础上减移过之后呢,更新到数据库,但肯定是set,那么count。Set count啊,Count,那么等于呢?S等于。4996。然后并且呢,这个version啊,咱应该是在之前的基础上。之前的基础上来应加一的啊,来应加一。并加一操作啊。好,那么然后呢,我们的更新条件应该是V2。让ID呢等于一,并且按的性。应该等于几呢?等于零。
08:02
等于零,等于我上次查询这个版本号。如果不等于了,说明什么,说明在这个查询和更新之间啊,又有其他人来做写的操作去了,因为每写一次呀,这个版本号呢,就加一啊。那么具体思后语句。啊,该怎么去实现,咱可以呢,把完整的最后语句都写一下啊,咱们呢,可以去新建一个查询。在这个里面呢,那么第一步差评怎么写呢?应该是select啊,新from,然后DB stock,那么we pro back等于1001,然后呢,我们来执行查询。他可以查询出两条库存。那也是呢,我就从这条库存里面来用减库存来扣减库存。那我们应该是第二步,Update,呃,Update DB stock set count等于,那我在这个代码里面肯定会在这个数量的基础上,诶减一过之后呢,更新到数据库。
09:08
应该设置为多少呢?设置为4996。然后呢,同时版本号,因为我要做更新操作了,版本号呢,我也我要进加一来一个set version等于version加一。那么更新条件应该是不要ID等于1AND version等于咱上一步查询的那个版本号。在上一步查询的时候呢,半米号几呢是零要等于零。如果不等于零,那我们应该取消本次更新。那这就典型的CS思想。那么咱的这个version版本号吧,如果等于我们这个上一步查询的旧值,可以执行更新。否则呢,放弃更新。如果我们这个地方不去加这个判断的话啊,有可能会出现什么情况呢。
10:03
但中间呢,可能别人横插一脚,你还不知道呢。啊,那么如果这个版本号不等于零了。那你也不知道啊。那么别人的库存可能早已经不是4997了,结果你还在4997的基础上减一过之后写入数据库呢?那就容易出现并发性的问题。好,那么有了这个CS氢氧之后呀。那么咱就很好处理了。如果是位置等于零的话,那么咱可以进行更新操作。如果咱们这个位置不等于零,本次更新的影响条数是等于零的啊,影响条数等于零。哎,那你比如说呢。如果我这个位置已经不是零了,是一了,别人都已经更新过了,对吧?啊,咱回到数据库表里面去啊,这个位置呢,已经是一了,来了以保存,那么此时我来执行这个更新的SQL语句,它最终返回的什么东西呢?影响条数影响行是零。
11:04
如果阴阳行是零,说明别人可能已经。操作过库存记录了,那我可以进行重试,我再去查询,再去更新,再查询更新。那么知道什么位置呢?知道更新啊,知道我们的更新的影响条数是一的情况下,那说明体库存就已经成功了。好,那么比如说呢,我们再回到数据库表里面去,如果这个位置呢是零,那么是零的情况下,那我这个第二步的定操作,那么就可以执行成功。说明没有被别人横插一脚。那么受影响的行呢,是一。那在MY里面咱就可以拿到这个受影响的行当啊,受影响的基督书的。好,那么这个思后语句咱们这么去写,那代码又该如何去写呢?我们来,可以翻开我们的ID。
12:00
那么在idea里面呢,咱们可以呢,去改造一下啊,我们这个这个方法,咱们再把这个方法呢,给它拷贝一下,让它放到上面去。那么这个位置呢,咱给它改成一个三。那么改成三之后呀,来看啊,咱们要在MY里面。啊,My base以实现咱们这两行代码啊。像第一行代码,咱们就直接使用通用map来提供的话就可以了。那我们这个差评啊。给它替换成。点上替换成点上讲的是select,应该是一个list,因为我可能会有多条库存记录。来,去一个query rapper。点上一口。那么呢,列名是pro code,然后呢,这个子呀,我们是1001啊,当然我们这里应该是双引号啊,加一个双引号。
13:06
啊,然后泛型啊,我们是定的。Talk啊,那么此时呢?我还是依然取第一条。那么这个地方呢,咱是查询库存信息,那这个库存信息里面呢,是有版本号的啊。啊,咱没有锁定有版本号,我们使用的是乐观锁嘛。好,我们依然取第一条库存。那么去完之后呢,我来去判断它是否为空,并且数量是否大于我要购买的数量。哎,我要买一件,你有一件就可以了,只要大于零就可以了啊,加上扣减库存,接下来呢,我们还得要去更新一下版本号stop.set诶,好像没有version字段,我们又扩展一个version字段,来一个private in version。然后呢,我们在这里呢,要把这个无性版本号也给它更新掉,咱应该是在原来版本号的基础上等于加一就可以了。
14:05
然后呢,我们也不能使用这个更新方法啊,我们要使用的是update这个方法,把stock呢放进去。那么更新条件,那么咱应该是根据ID和version再去更新的。那么咱们应该这么去写,你有一个update re,点上equal,好,ID等于我们库存的ID。那么再再去点上EQ,让版本号等于我们之前查询的这个版本号,来一个talk。那么之前查询的版本号是多少呢?已经被我们给覆盖掉了。但应该在这个talk对象里面啊,但是已经被我给覆盖掉了。那我得要去获取原来这个版本号,咱可以把这个东西啊给它声明到。外面去啊。来一个version,让他把这个version呢给它放在。啊,这个位置。好,那放好之后呢,那我们的来看影响条数如果等于零。
15:06
那说明什么?说明咱更新失败了。中间被别人横插了一脚。典型的是D,如果等于零的话。那我们就要去递归,再来去重试,再调用这个方法呢,查询,然后呢,减库存,减完之后呢,更新进去。那么知道阴量调试是一的情况下,是退出我们这个递归要点啊,那么这个地方它应该是递归调用,相当于就重式了。OK,那么这个地方呢,如果更新失败,那么可进行重试。好,那我们这个地方呢,就需要我们的泛型啊套泛型,把泛型呢拷贝到这个位置。那么依然有错啊,这个位置呢,少了一个负号,我们给它加上去。那么加上之后呢,那咱这里呢,啊还有错对吧,来看一下。
16:03
啊,这个分号呢,写成中文的了。那我们来去重新启动。我们先把服务一呢给它重启一下。人类找到这个服务二,我们也给他重启一下,那么两个服务呢,我们都已经在重启中了啊,服务一已经重启好了。那么服务二呢,已经统计好了。那我们呢,可以去试一下。我来点击刷新,好来看最终我们的数据库里面的数据来刷,诶4995件版本号呢加了一个,那我再去更新一次,那么库存呢,应该又减了一件,那版本号呢又加了一个。好,代码呢,应该没啥问题。
我来说两句