mysql行级锁怎么加 mysql行锁语句( 六 )


(3)在事务中,如果要更新记录,应该直接申请足够级别的锁,即排他锁,而不应该先申请共享锁,更新时再申请排他锁 , 甚至死锁 。
(4)在REPEATEABLE-READ隔离级别下,如果两个线程同时对相同条件记录用SELECT...ROR UPDATE加排他锁,在没有符合该记录情况下,两个线程都会加锁成功 。程序发现记录尚不存在,就试图插入一条新记录,如果两个线程都这么做,就会出现死锁 。这种情况下,将隔离级别改成READ COMMITTED , 就可以避免问题 。
(5)当隔离级别为READ COMMITED时 , 如果两个线程都先执行SELECT...FOR UPDATE,判断是否存在符合条件的记录 , 如果没有 , 就插入记录 。此时,只有一个线程能插入成功,另一个线程会出现锁等待,当第1个线程提交后 , 第2个线程会因主键重出错,但虽然这个线程出错了,却会获得一个排他锁!这时如果有第3个线程又来申请排他锁,也会出现死锁 。对于这种情况 , 可以直接做插入操作,然后再捕获主键重异常,或者在遇到主键重错误时,总是执行ROLLBACK释放获得的排他锁 。
尽管通过上面的设计和优化等措施,可以大减少死锁,但死锁很难完全避免 。因此,在程序设计中总是捕获并处理死锁异常是一个很好的编程习惯 。
如果出现死锁,可以用SHOW INNODB STATUS命令来确定最后一个死锁产生的原因和改进措施 。
总结
对于MyISAM的表锁,主要有以下几点
(1)共享读锁(S)之间是兼容的,但共享读锁(S)和排他写锁(X)之间,以及排他写锁之间(X)是互斥的,也就是说读和写是串行的 。
(2)在一定条件下,MyISAM允许查询和插入并发执行,我们可以利用这一点来解决应用中对同一表和插入的锁争用问题 。
(3)MyISAM默认的锁调度机制是写优先,这并不一定适合所有应用,用户可以通过设置LOW_PRIPORITY_UPDATES参数,或在INSERT、UPDATE、DELETE语句中指定LOW_PRIORITY选项来调节读写锁的争用 。
(4)由于表锁的锁定粒度大,读写之间又是串行的,因此,如果更新操作较多,MyISAM表可能会出现严重的锁等待 , 可以考虑采用InnoDB表来减少锁冲突 。
对于InnoDB表,主要有以下几点
(1)InnoDB的行销是基于索引实现的 , 如果不通过索引访问数据,InnoDB会使用表锁 。
(2)InnoDB间隙锁机制,以及InnoDB使用间隙锁的原因 。
(3)在不同的隔离级别下,InnoDB的锁机制和一致性读策略不同 。
(4)MySQL的恢复和复制对InnoDB锁机制和一致性读策略也有较大影响 。
(5)锁冲突甚至死锁很难完全避免 。
在了解InnoDB的锁特性后,用户可以通过设计和SQL调整等措施减少锁冲突和死锁,包括:
尽量使用较低的隔离级别
精心设计索引,并尽量使用索引访问数据,使加锁更精确,从而减少锁冲突的机会 。
选择合理的事务大?。?小事务发生锁冲突的几率也更小 。
给记录集显示加锁时,最好一次性请求足够级别的锁 。比如要修改数据的话,最好直接申请排他锁,而不是先申请共享锁,修改时再请求排他锁,这样容易产生死锁 。
不同的程序访问一组表时,应尽量约定以相同的顺序访问各表,对一个表而言 , 尽可能以固定的顺序存取表中的行 。这样可以大减少死锁的机会 。
尽量用相等条件访问数据,这样可以避免间隙锁对并发插入的影响 。
不要申请超过实际需要的锁级别;除非必须,查询时不要显示加锁 。
对于一些特定的事务,可以使用表锁来提高处理速度或减少死锁的可能

推荐阅读