共享锁【S锁】
又称读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。

排他锁【X锁】
又称写锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。

show engine innodb status;发现有死锁.

 insert into b  select * from s where ;

        我们是mysql数据库,可重复读隔离级别, 在insert into b  select * from s where 这种语句下会对表b加X锁,对s表扫描的行加S共享读锁(通过主键排序或则不加排序字段会逐步地锁定已经扫描过的记录,如果是按非主键排序则一开始就锁整张表)。

        这样s表上加了S共享锁的记录其他事物就无法再加X锁即不可被修改,Select是逐行加锁容易死锁,如果在逐行加锁的过程中发现某行数据被其他事物锁住,它就会拿着已加锁的行不放等待其他事物释放锁,如果其他事物再反过来请求它已加锁的行就会造成互相等待锁的死锁情况。这个文章分析的很清楚

 

如何解决呢?

一、如果数据量不大可以分两步,先缓存select的结果,再insert,这样不会对select的表加锁;如果数据量较大会占用较大的内存就不能这样做了。

二、只要不在select上加锁就行,可以设置降低insert select单个会话级别的事务隔离级别为(注意不要改全局的!), 这样就不会再加锁,但是不能保证insert select的数据安全,如果insert过程中有其他事务修改数据那么可能获取到的就是修改后的数据;

mysql insert into select 会不会锁表 insert into select from 锁表_死锁