乐观锁和悲观锁
1、悲观锁。先取锁,再访问。
1)修改记录前,增加排它锁
2)如果加锁失败,则说明有其他线程在修改该记录,那么需要等待或抛出异常,由开发者决定
3)如果加锁成功,则修改记录,事务完后释放锁
4)期间如果其它线程对该记录进行修改或者加排它锁,都会等待我们解锁或者抛出异常
包括:
1)共享锁(读锁),多个事务共享一把读锁,只能读,不能写。
2)排它锁(写锁),如果一个事务获取了数据行的排它锁,其它事务都不能获取改行的其它所,包括共享锁和排它锁。
注意:
1)有索引的可以行锁,没有索引的会表锁,锁表会出问题
2)增加额外开销
3)增加产生死锁的机会
4)降低并发性,一个事务锁定了某行数据,其它事务就必须等待该事务处理完
2、乐观锁
实现:冲突检测和数据更新。CAS(Compare and Swap)。
1)获取记录,select quantity from itmes where id=1,假如quantity=3
2)更新记录,并将上一步查出来的quanlity作为条件,如果当前库存数与第一次取出来的库存数相等则更新,否则认为过期
update itmes set quantity=2 where id=1 and quantity=3
问题:ABA问题
1)线程1读取数据A
2)线程2读取数据A
3)线程2通过CAS比较是A,然后修改为了B
4)线程3读取B
5)线程3通过CAS发现是B没错,然后修改为A
5)线程1通过CAS认为是A没错,然后修改为自己要修改的值
数据的值改变了,但是线程1并没有发现,虽然线程1没有错,但是不代表没有问题。
乐观锁使用场景:订单表、流水表修改等
解决:
1)增加自增标志位
2)时间戳
3)问题:如果存在大量的并发,则只会有一条记录修改成功,会出现大量的失败
4)原子操作实现。update items set quantity = quantity -1;
没仔细了解锁之前,都是用update items set quantity = quantity -1来解决这类问题,主要是因为懒,能写一句干嘛写两句。
了解了锁之后,忽然发现这句update变牛x了。