乐观锁
老是认为不会产生并发问题,每次去取数据的时候总认为不会有其余线程对数据进行修改,所以不会上锁,可是在更新时会判断其余线程在这以前有没有对数据进行修改,通常会使用版本号机制或CAS操做实现。mysql
例如:sql
有这样一个表:数据库
每次更新时update在条件后再附加一个时间为条件:并发
update user_info set password='somelog' where username='somelog' and time='2018-07-11';
由于若是并发操做,同一刻查询的时间同样,可是先插入时将时间更改,那么后更新的操做就不能进行,由于time的值被前一个操做更改了。spa
这就是乐观锁的实现原理,更新时附加一个版本号。线程
悲观锁
老是假设最坏的状况,每次取数据时都认为其余线程会修改,因此都会加锁(读锁、写锁、行锁等),当其余线程想要访问数据时,都须要阻塞挂起。能够依靠数据库实现,如行锁、读锁和写锁等,都是在操做以前加锁,在Java中,synchronized的思想也是悲观锁。
注:要使用数据库的悲观锁,咱们必须关闭mysql数据库的自动提交属性,由于MySQL默认使用autocommit模式,也就是说,当你执行一个更新操做后,MySQL会马上将结果进行提交。code
悲观锁分为两种:共享锁和排它锁blog
共享锁是其它事务能够读可是不能写
排他锁是只有本身得事务有权限对此数据进行读写事务
SQL写法
共享锁(S):it
SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE;
排他锁(X):
SELECT * FROM table_name WHERE ... FOR UPDATE;
加锁必须先开启事务:begin;(开启事务)->加锁、操做->commit;(提交事务,归还锁)
加锁分为显式加锁与隐式加锁,上面的写法是显式加锁。mysql在执行insert、update会自动加锁,mysql对select却不会加锁。
例如:
不加锁
select * from data where username=‘somelog’;
加排它锁:
select * from data where username=‘somelog’ for update;
若是一个事务加了排它锁以后,另一个事务不加锁的select也能够查询到数据
以上能够看出,锁不是针对事务的,排它锁只有一把,谁拿了谁就能够进行更新,可是没有拿到锁的事务只要在select不加上排它锁也能够查询到数据。