今天在项目性能测试中遇到个Mysql的DeadLock的问题。
后来根据数据库日子查找原因,大概模拟一下发生的情形。
数据库用的innoDB。
InnoDB行锁是通过给索引上的索引项加锁来实现的,InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!
下面例子中id是主键,操作都走索引,锁都是row lock。
table中数据
用2个线程做如下操作,将发生死锁现象,且1个线程执行成功,另一个线程失败。
最终结果:第一条数据被改变,第3条数据不变。
MySql的InnoDB,\加了事务的select语句索引的记录,会加S锁, insert,delete,update会加X锁。
设定左边为线程1,右边为线程2
线程1在id=1的一行记录上加了S锁, 当线程2要update操作这行记录时,要在记录上加X锁, 此时需要等待线程1释放id=1记录上的S锁。
线程2在id=3的一行记录上加了S锁, 当线程1要update操作这行记录时,要在记录上加X锁, 此时需要等待线程2释放id=3记录上的S锁。
彼此互相等待,然后就死锁了。
Mysql释放死锁的机制,看锁定的记录数,一般会允许锁定记录多的事务执行通过, 而锁定记录少的事物回滚。范围同等时应该是按X锁请求的先后了。
补充说明: InnoDB 如果where后面的条件字段没有索引,则加锁时是会锁表。走索引只会锁查询或操作的记录。InnoDB事务中的查询条件需要小心了
互斥 |
S |
X |
S |
否 |
是 |
X |
是 |
是 |
先写这么多。