隔离级别:可重复读
事务1:
select * from user where id >2;
如果查询结果: 1条数据
此时其它事务 insert into user ('username','password') values ('zhangsan','zhangsan');
再在事务1 中查询 查询结果 1条数据
如果使用 select * from user where id >2 for update;(lock in share mode)
则可以查询2条数据

使用lock in share mode 容易出现死锁;
并且一个事务使用乐观锁锁住行或表 其它事务无法操作行或表;当2个事务都锁住同一块区域后2个事务都无法操作次区域;那这个共享锁 和排他锁的区别呢?
1. select *** for update 的使用场景
为了让自己查到的数据确保是最新数据,并且查到后的数据只允许自己来修改的时候,需要用到 for update 子句。
2. select *** lock in share mode 使用场景
为了确保自己查到的数据没有被其他的事务正在修改,也就是说确保查到的数据是最新的数据,并且不允许其他人来修改数据。但是自己不一定能够修改数据,因为有可能其他的事务也对这些数据 使用了 in share mode 的方式上了 S 锁。
性能影响:
select for update 语句,相当于一个 update 语句。在业务繁忙的情况下,如果事务没有及时的commit或者rollback 可能会造成其他事务长时间的等待,从而影响数据库的并发使用效率。
select lock in share mode 语句是一个给查找的数据上一个共享锁(S 锁)的功能,它允许其他的事务也对该数据上 S锁,但是不能够允许对该数据进行修改。如果不及时的commit 或者rollback 也可能会造成大量的事务等待。
for update 和 lock in share mode 的区别:前一个上的是排他锁(X 锁),一旦一个事务获取了这个锁,其他的事务是没法在这些数据上执行 for update ;后一个是共享锁,多个事务可以同时的对相同数据执行 lock in share mode。
开启事务后,会在第一次执行查询语句时保一次数据库快照,然后每次查询都是在这个快照里查询数据。
比如:
事务1:执行查询语句
事务2: 执行新增或修改;
事务1:执行查询语句,不会查询出来事务2提交的数据,即便事务2已经提交;
开启事务1,执行查询语句
事务2执行修改操作并提交;
事务1 查询数据,可以查询事务2提交的数据,因为此时事务已才生成快照。
悲观锁、乐观锁、排他锁、共享锁
1、悲观锁:只要加锁就是悲观锁: 如新增、修改, 查询带lock in share mode或 for update;如java里面的lock、synchronize
2、乐观锁: 没有其它人会改值,所以跟没锁一样,但是在数据一致性上需要做要求,比如可以加个版本号,如修改数据时先
查询select name,version from user where id = 1;
更新时使用 update name = "a" where id = 1 and version = "查询出来的sersion";
此时如果修改数据行数不同证明有几行数据被修改了,可以再进行回滚。如果是使用id精确查询那么update返回结果是0 则表示修改失败。
3、排他锁: 新增、修改 查询带for update
4、共享锁: lock in share mode;
事务1 加了共享锁、事务2 也可以加共享锁
事务1加了共享锁,事务2 无法加排它锁(for update、修改)
事务1 加了共享锁(行锁),事务2可以加共享锁(同一行),然后可以对该行进行修改(即可以再加排它锁);
事务1 加了共享锁(表锁),事务2无法加排它锁,即便先加共享锁也不能再加排它锁。
加锁只会对影响的行加锁,即where条件查询出来的数据(有索引,没有索引会加表锁);
新增也会加锁,属于表锁;如果此事务没有commit;其它事务无法加表锁;
网友评论