因为项目的数据更新频率很高,导致经常出现死锁的问题。感觉以下遇到的一种情况比较典型,也比较tricky,计之。
问题描述:
如以下两条非常简单的SQL语句,它们共同组成了一个Transaction,那么在多线程高频率执行时就会引起死锁问题(当然这里要考虑锁的级别问题,一般多类似这种系统都会选择行锁,那么以下引起死锁的条件是两条语句都对同一行操作):
问题分析:
select语句需要“Shared Lock”,因而多个线程可以同时进入,而update需要“Exclusive Lock”,当两个线程同时执行了select语句,而获得了“Shared Lock”,而他们在接下来执行update语句时,都需要获得“Exclusive Lock”而产生竞争,导致死锁。
解决方案1:
互换他们的顺序,这样,在第一次执行update语句时,他们会竞争"Exclusive Lock"而引起没有得到“Exclusive Lock”的线程等待:
解决方案2:
采用“Hold Lock”方式,即在所有操作之前做一个dummy的update操作,这样可以保证在进Transaction之前需要先获得一个“Exclusive Lock”
问题描述:
如以下两条非常简单的SQL语句,它们共同组成了一个Transaction,那么在多线程高频率执行时就会引起死锁问题(当然这里要考虑锁的级别问题,一般多类似这种系统都会选择行锁,那么以下引起死锁的条件是两条语句都对同一行操作):
select <column1> from <table> where <column2> = ?
update <table> set <column1> = %d where <column2> = '%s'
update <table> set <column1> = %d where <column2> = '%s'
问题分析:
select语句需要“Shared Lock”,因而多个线程可以同时进入,而update需要“Exclusive Lock”,当两个线程同时执行了select语句,而获得了“Shared Lock”,而他们在接下来执行update语句时,都需要获得“Exclusive Lock”而产生竞争,导致死锁。
解决方案1:
互换他们的顺序,这样,在第一次执行update语句时,他们会竞争"Exclusive Lock"而引起没有得到“Exclusive Lock”的线程等待:
1, update <table> set <column2> = <column2> + <some value> where <column1> = '%s'
2. select <column1> from <table> where <column2> = ?
3. <column1> - <some value> to get the old <column1> value.
2. select <column1> from <table> where <column2> = ?
3. <column1> - <some value> to get the old <column1> value.
解决方案2:
采用“Hold Lock”方式,即在所有操作之前做一个dummy的update操作,这样可以保证在进Transaction之前需要先获得一个“Exclusive Lock”