并发事务,防止出现死锁、施加排他锁 xxx for update
遇到一个并发事务死锁的问题,事务对一个表执行删除操作,对另外一个表执行更新操作,使用的是Hibernate操作数据库。在并发应用时,如果有2个线程同时操作同一条数据就会导致死锁的发生,这个问题通过代码层面解决吗?如果有2个以上线程调用这个方法对同一个客户执行操作就会导致死锁发生,两个线程各持有一个表的锁。有什么机制可以避免这种情况发生么? 、
select for update 某个线程操作时对它施加排他锁,锁住你要操作的数据;这样别人就在等待,不会死锁,但相对于是串行化
行级锁与死锁
MyISAM中是不会产生死锁的,因为MyISAM总是一次性获得所需的全部锁,要么全部满足,要么全部等待。而在InnoDB中,锁是逐步获得的,就造成了死锁的可能。
在MySQL中,行级锁并不是直接锁记录,而是锁索引。索引分为主键索引和非主键索引两种,如果一条sql语句操作了主键索引,MySQL就会锁定这条主键索引;如果一条语句操作了非主键索引,MySQL会先锁定该非主键索引,再锁定相关的主键索引。 在UPDATE、DELETE操作时,MySQL不仅锁定WHERE条件扫描过的所有索引记录,而且会锁定相邻的键值,即所谓的next-key locking。
当两个事务同时执行,一个锁住了逐渐索引在等待其他相关索引,一个锁定了非主键索引,在等待主键索引。这样就会发生死锁。
发生死锁后,InnoDB一般都可以检测到,并使一个事务释放锁回退,另一个获取锁完成事务。
有多种方法可以避免死锁,这里只介绍常见的三种,具体如下
1、如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。
2、在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;
3、对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;