sql执行以及乐观锁具体实现在哪?
并发执行到update语句时,两个线程竞争最后的库存,此时事务都未提交时,执行完update语句返回什么?以及乐观锁具体实现在哪?
正在回答 回答被采纳积分+1
我在这里举例一个金额扣减的例子,你理解这个案例了,那么对于库存的扣减也就理解了
开启两个事务,在这两个事务中同时对数据库表的同一行数据进行更新,则第一个事务的update语句先执行,而第二个事务的update语句后执行,那么要等到第一个事务提交之后,第二个事务的更新语句才能从阻塞状态变成执行状态。
查询都是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;
}
超卖
事务只有写锁,并发的时候多个线程都可以读到有足够的库存 比如大家都读取有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是串行执行的, 所有的并行都被改成串行了。
// 打个比喻,十条大道进高速,可是高速只有一个收费口。 在多的并发并行都得串行通过闸口。 谁通过了谁拿锁,走的时候还锁,下一个继续
从儿实现了分布式锁了。 就这么简单
乐观锁不是一个具体锁,是一种机制,老师在写sql语句的时候写了一下,当前数量少于购买数量就不让买了
where子句:
stock >= #{pendingCounts}
个人认为,如果有两个人购买商品牙刷,但是数据库牙刷只有一个的话,谁先点击购买,谁就能买到,点击慢的会提示牙刷商品不足了。乐观锁具体实现在哪,需要查看乐观锁的原理,我也不太清楚,好像是悲观锁在买东西的时候就是,只能一个人买别人不能买了,直到第一个人买完别人才能买。乐观锁好像是我买的时候别人也能买,但是我点击的慢了就没了
发生扣除如果少于0,如此就不能继续了
恭喜解决一个难题,获得1积分~
来为老师/同学的回答评分吧
0 星