sql执行以及乐观锁具体实现在哪?

sql执行以及乐观锁具体实现在哪?

并发执行到update语句时,两个线程竞争最后的库存,此时事务都未提交时,执行完update语句返回什么?以及乐观锁具体实现在哪?http://img1.sycdn.imooc.com//climg/5de8680709914f3016480650.jpg

正在回答 回答被采纳积分+1

登陆购买课程后可参与讨论,去登陆

8回答
静默_Love 2021-03-02 22:03:59

我在这里举例一个金额扣减的例子,你理解这个案例了,那么对于库存的扣减也就理解了

开启两个事务,在这两个事务中同时对数据库表的同一行数据进行更新,则第一个事务的update语句先执行,而第二个事务的update语句后执行,那么要等到第一个事务提交之后,第二个事务的更新语句才能从阻塞状态变成执行状态。 http://img1.sycdn.imooc.com//climg/603e45b10953bbec31601020.jpg在上面的图中,左边的事务执行完余额更新操作后commit之后,虽然右边的事务中执行的查询操作,每次都是查询都是20,(当前的事务隔离级别为可重复读)但是执行更新操作后变成了-20,此时我们应该添加乐观锁*且不能通过java代码进行判断,直接更新某个变量为绝对值,而应该是相对值

update account set balance=balance-20 where id =1; //	需要添加乐观锁
update account set balance=balabce-20 where id =1 and balance>0;

// 不能在java代码中更具select取出的值为20,然后通过if判断20>0就,简单的调用update字段语句
if(balance>0){
remain = balance-20
executeSql("update account set balance = remain where id =1 and balance>0")
因为隔离级别为可重复读,此时读取的balance都是进入事务之前的值,却不是最新的,所以我们的sql语句使用的变量应该是由数据库控制的变量如balance = balance-20,而不是通过java代码读取的balance进行计算,通过数据库的变量能够进行更新,如上面最后出现的-20;
}


一条路走到黑777 2020-07-13 21:33:52

超卖

    事务只有写锁,并发的时候多个线程都可以读到有足够的库存  比如大家都读取有4件库存

    现在用户并发的购买一件商品时

    因为事务只是写锁,线程门排队一个个进行写数据,每个线程都将库存数据更新为3       (没错,第一个人将4改成3, 第二个人将3改成3, 第三个人将3改成3,以此类推。 然后一件商品被卖了上万件)  // 秒杀商品亏死你     


你要明白,读和写是两个操作。   事务只有写锁,没有读锁


悲观锁

    update语句后面接for update       这个是读写锁。   

     // 第一个线程读取到后,不允许别人在去读。 只有第一个线程完成事务后,第二个线程才能读

      //比如你在下单时,因为是读锁,锁住商品不让别人去读,然后其他人在首页刷新商品时就刷新不出来了,因为库存被你读锁锁住了,他们读取不到库存。   你一个人成功的把整个网站给堵住了。  超级厉害。  性能超低,所以也不推荐使用


乐关锁

    其原理就是利用事务本身就是写锁来实现的

update

    items_spec

set

    tocke = stock - #{pendingCounts}

where

    id = #{specId}

and

    tocke >= #{pendingCounts}


    注意and后面的语句。  事务在进行写时,会锁住数据,然后进行了数据判断,条件不符合。 就不会写了。

    // 这条语句本身会执行成功的,不会抛出异常。 只是执行的返回结果是0了(更新了0条记录,所以我们可以由此判断出库存不足)


事务和锁是两个概念,这个不要搞混了。就容易理解了


说两个题外话

    1. Java的 i++   这个是非线程安全的。  因为读取数据和写数据是两个操作。   两个线程并发的将i++  执行一万后, 结果是i小于2万(cpu好的建议执行一百万次i++)。

// 你可以找找i++的例子,就明白了。  读和写是两个操作。  就需要两把锁才能锁住了



2. 后面讲的基于redis实现分布式锁, 其原理就是利用了redis是单线,且命令是串行执行的来实现的。

    例如: 我们的Java是分布式部署,是高并发,是多线程。  然而他们都会去请求执行一个redis属性值设置,因为redis是串行执行的, 所有的并行都被改成串行了。


    // 打个比喻,十条大道进高速,可是高速只有一个收费口。  在多的并发并行都得串行通过闸口。 谁通过了谁拿锁,走的时候还锁,下一个继续

    从儿实现了分布式锁了。  就这么简单 


慕桂英43175126 2020-07-06 09:07:25

乐观锁不是一个具体锁,是一种机制,老师在写sql语句的时候写了一下,当前数量少于购买数量就不让买了

慕函数5056751 2020-07-03 16:24:15

where子句:

stock >= #{pendingCounts}

it_java6 2020-07-01 16:44:08

ItemsMapperCustom.xml

<!--乐观锁-->

<update id="decreaseItemSpecStock">


        update

            items_spec

        set

            stock = stock - #{pendingCounts}

        where

            id = #{specId}

        and

            stock >= #{pendingCounts}


    </update>


qq_丿一笑奈何_0 2020-06-27 20:46:59

个人认为,如果有两个人购买商品牙刷,但是数据库牙刷只有一个的话,谁先点击购买,谁就能买到,点击慢的会提示牙刷商品不足了。乐观锁具体实现在哪,需要查看乐观锁的原理,我也不太清楚,好像是悲观锁在买东西的时候就是,只能一个人买别人不能买了,直到第一个人买完别人才能买。乐观锁好像是我买的时候别人也能买,但是我点击的慢了就没了

快乐撸猫少年 2020-04-15 21:23:59

MySQL的默认存储引擎是InnoDB,默认行锁。所以在update的时候会在对同一条记录加锁。虽然存在两个线程的update的事务未提交,但是innodb的update操作是采用当前读的方式。假设线程A开启事务A并执行update操作后,但未提交事务;此时线程B也开启事务B并update操作。此时线程B的update是基于当前读的方式获取到线程A更改后的结果。如果事务A在此时想提交事务,这是不允许的。根据两阶段锁协议,事务B没提交,因为此时在这条记录上的写锁还没有释放。所以必须等待事务B提交后释放锁。

  • SO...
    2020-06-26 20:40:41
  • htdica #2
    这里你是假设A先拿到锁还是B先拿到锁呢,感觉你这里写的不是很清楚
    2020-07-08 00:08:02
  • 事务A 做了update,如果不commit,B的update会被阻塞,所以B要执行,必须要等A commit之后,B才会执行
    2020-07-12 00:31:02
Java架构师讲师团 2019-12-05 11:19:50

发生扣除如果少于0,如此就不能继续了

问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星

相似问题

登录后可查看更多问答,登录/注册

请稍等 ...
意见反馈 帮助中心 APP下载
官方微信

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师