算一算也工作几年了,这几年的时间认识了很多人,有漂亮的姑娘,有特有趣的同事,有初来深圳时一无所有但是却都一起快乐的朋友,也有经历了很多美好的爱人,许多许多,林林种种,有句歌词说,没有梦想,何必远方,我到是觉得,有没有梦想,都要远方,因为远方有你没见过的风景,远方有你没交过的有趣的朋友,远方也有许多你没做过,但是一定很有意思的事,总之,人生是需要远方的。
BB结束-----
在接触数据库之前,很难想象技术中会有这么多的锁,数据信息时代,最重要的就是数据,一切技术归根到底,都是为数据服务,所以数据的安全尤为重要,所以数据不能放肆,而克制他的东西就是锁。
好多锁,现在一个一个说
1 乐观锁
我们修改数据的时候,我们会建立一个事务,然后查询出数据,然后进行修改的操作,这时候存在一种可能,别的事务也拿到了这个数据,并且有可能也修改了数据,这时候,第一个事务在去修改数据,那就不准确了,但是乐观锁的思想是,不回存在另一个事务修改这个数据。所以不去建锁,呵呵,所以乐观锁他就没有锁命令,但是却需要我们在程序中处理,要在数据库表增加一个version字段,记录当前数据的版本号,在修改数据时,判断当前数据的版本号和数据库是否一致,如果一致就修改,不一致就报错。
2 悲观锁
这个锁,他就是认为在A事务修改数据时,B事务也会过来修改数据,是不是很极端,没错就是很极端,他是一种思想,靠这个思想来解决问题的还有两种锁,共享锁(读锁),排他锁(写锁)
1)共享锁
这个锁,前面加了一个共享,这名字不太好,都共享了,还锁毛呀!,但是他确实锁了,在一个会话访问他的时候,其他的回话只允许读加共享锁的数据,不能写也就是修改。他是需要命令来加的,举个栗子
begin;/begin work;/start transaction; (三者选一就可以)
#(lock in share mode 共享锁)
SELECT * from TABLE where id = 1 lock in share mode;
执行完这段话后,就会对这行数据加上了共享锁,然后其他的回话就只能读取他不能修改他了,只有执行完commit才能修改成功,负责就会一直阻塞。另外,如果当前的回话如果增加了对这条数据的delete,update,那就会自动对这条数据进行排他锁
2)排他锁
这个锁,相当与上一个锁的升级,他是当前回话访问的数据,其他的回话既不能读也不能写,多嚣张。举个栗子
set autocommit=0;
# 设置完autocommit后,我们就可以执行我们的正常业务了。具体如下:
# 1. 开始事务 begin;/begin work;/start transaction; (三者选一就可以)
# 2. 查询表信息(for update 加锁) select status from TABLE where id=1 for update;
# 3. 插入一条数据 insert into TABLE (id,value) values (2,2);
# 4. 修改数据为 update TABLE set value=2 where id=1;
# 5. 提交事务 commit;/commit work
值得一提的是,mysql默认的是自动提交事务,也就是autocommit,我之前自己学习的时候,使用两个回话测试事务,结果测试不成功,原来mysql的事务默认是自动提交的...
他的加锁是通过for update来执行的
3 行锁
这个锁,是最常见的锁,因为他是通过事务控制的,并不需要执行什么命令
他有一些特点
1)锁的粒度小,精确到行
2)开销大,加锁满,会出现死锁,因为太过精确,所以要耗费更多的资源
3)发生锁冲突低,适合高并发,因为锁在行上,所以可以有效的减少阻塞
除此之外非常值得一提的是,他会升级成表锁,啥时候呢,如果修改时的条件不是索引列时就会升级成表锁,表锁就有点可怕了,因为会增加阻塞的概率。
那为什么会是这样的呢,为什么一定要是索引列呢,因为mysql不能判定,要修改的数据是多少行,万一修改的数据行太多呢,这样数据库的开销就太大了,而索引的原则就是加载行数据较少的字段。
4 表锁
上面已经介绍了,就不多过说了。
5 间隙锁
这个是对一个区间的查询
举个栗子
Select * from emp where empid > 100 for update;
这样就加上了间隙锁,这个间隙锁也是针对索引列的,那为甚要用间隙锁呢,因为他可以防止幻读,幻读就是在一个事务里面第一次查询一个阶段的数据总数是A,但是同样的查询条件,第二次查询出来的总数就变成B了,导致好像出现了幻觉,而加上了间隙锁的数据,第二次查询他还是A,这样就解决了幻读,但是他有一个问题,加上了这个锁之后,这个锁之间的数据,是不允许被插入和修改的,就造成了阻塞,所以还是要慎用。
6 死锁
这个是最头疼的,这个场景也挺值得思考的,如果申请锁是有序的就不会造成死锁,但是什么时候会出现死锁呢,
比如A事务,他修改数据时会锁数据,然后继续执行,执行到下一个修改,执行不下去了,因为这个修改的数据被B事务锁住了。
然后我们看B事务,他修改数据是锁住数据(这个锁住的数据就是刚刚A事务要修改的数据),然后继续向下执行修改下一条数据,这时候发现这条数据被A事务锁住了,这下就杠上了,也就是死锁了。
那怎么解决掉呢,我们可以通过查进程的方式,然后杀进程来解决
也可以通过查看数据库表中是哪个事务对应的sql锁住来解决
但是最好的还是防患于未然,就是避免产生这种现象,那有啥方案呢
1)减少大事务,很简单,大事务就会增加阻塞的时间
2)给表添加合理的索引,因为不走索引,那就是表锁了,就容易死锁了
3)按顺序修改表,一次性最好把需要的所有数据都上锁。
4)降低事务的隔离级别
以上所写的锁,都是针对InnoDB引擎,mysql有两种引擎,MyIsam和InnoDb,这两个引擎的差别还是很大的
1 不同点
1)MyIsam是不支持事务的
2)MyIsam是不支持高并发的
3)MyIsam使用的是表锁而InnoDb默认的是行锁
这个不同点估计大家看到前两条就会放弃Myisam了,不支持事务问题就太大了。