事务
数据库一个很重要的功能就是事务。
所谓事务一个很简单的例子就是:现在我要交易给你一百块钱,这个交易,对于数据库意味着我的余额减100,你的余额加100两个操作。事务需要保证不管出现任何意外的情况,在其他人看来,这个两个操作要么都成功,要么都失败。
“在其他人看来"这点很重要,因为我们当前会话的数据库的操作总是有先有后,但是我们要保证对于其同时进行的其他查询会话的数据一致性。
那么如何实现事务呢,一般是通过锁机制或者并发机制来实现的。
锁
比较简单的方式是通过锁来实现的。这个方式就好比告诉其他人“我们两个在交易过程中,谁也不许看” 只有等我们交易完了,其他人才能查询我们的余额。
简单的概括来说有以下几个特点
- 读操作和写操作冲突,不能同时操作,不同会话的读操作之间不冲突。
- 冲突时后面的操作会等待,影响并发性能
- update等写操作会自动加锁,但是读操作如果需要限制并发,则需要手动加锁,有下面两种。
select… lock in share mode 表锁
select … for update 行锁,如果存储引擎支持的话
这种方式比较简单粗暴,由于锁冲突的时候会产生等待,并发性能能会明显下降。
多版本并发
这是一种更加复杂,但是性能更好的方案。简单的来说就是“交易过程中其他人可以看,但是看到的是我们交易完成前的录像”,在数据库中,其他人查询并不需要等待,但是查询到的是事务开始前的快照,
这是InnoDB默认使用的方案。写会产生锁,但是读不需要持有锁,读写不冲突,所以并发性能高。
锁加在哪里
我们前边讲过,Innodb中,主键和数据共同构成表的数据结构,Innodb的锁是行锁,主要是加在主键记录上(还有一种间隙锁会锁住主键的间隙),类似于下图所示
值得注意的是,如果你通过了索引过滤了数据,是会锁住索引过滤后的主键记录,这并不会锁住很多数据而影响并发性。
但是如果你的语句没有用到索引,而是使用了一个全表扫描,那很不幸,你所有扫描到的数据都会加锁,即使你最后只获得一条数据。这时候就会很大的影响你系统的并发能力了。
以上就是MySQL的并发与锁的机制,希望能对大家高并发系统的设计有所帮助。