情景:
交易A开始......
START TRANSACTION;
UPDATE table_name SET column_name=column_name+1 WHERE id = 1 LIMIT 1;
同时,交易B开始......
START TRANSACTION;
UPDATE table_name SET column_name=column_name+1 WHERE id = 2 LIMIT 1;
UPDATE table_name SET column_name=column_name-1 WHERE id = 1 LIMIT 1;
COMMIT;
现在,事务B正在等待第1行,它在事务A中被锁定。
交易A继续......
UPDATE table_name SET column_name=column_name-1 WHERE id = 2 LIMIT 1;
COMMIT;
现在我们有一个死锁,因此两个交易都在等待彼此解锁他们想要更新的行:'(
正如我在标题中提到的,我们如何防止RDBMS事务中的死锁?
我认为解决这种情况的唯一方法是回滚事务B并重新执行它。但是,我们怎样才能发现我们处于僵局,并立即摆脱它,我们怎样才能保证我们不会进入无限循环(例如,在非常繁重的Web应用程序中)。
如果有必要,我使用MySQL。但是欢迎任何其他RDBMS的解决方案 - 帮助其他人从谷歌来到这里:)
答案 0 :(得分:3)
大多数数据库(如果不是全部)将自动检测到死锁,选择一个会话作为受害者,并自动回滚该会话的事务以打破僵局。例如,这是MySQL deadlock detection and rollback文档。
死锁是编程错误。避免死锁的一个简单解决方案是确保始终按特定顺序锁定行。例如,如果您有一个想要更新两个不同行的事务,请始终先更新public static void insertionSort(int[] array) {
for (int top = 1; top < array.length; top++) {
int temp = array[top]; // copy item that into temp variable
int pos = top - 1;
while (pos > 0 && array[pos] > temp) { //<----- need to change '>' to '>='
// move items that are bigger than temp up one position
array[pos+1] = array[pos];
pos--;
}
array[pos ] = temp; // place temp into last vacated position // <------------------------need to change 'array[pos ]' to 'array[pos + 1]'
}
}
行,然后更大 public static boolean contains(int[] array, int val) {
for (int i = 0; i < array.length; i++) {
if (array[i] == val)
return true;
else //<---------- need to remove this
return false; //<---------- need to remove this
}
return false;
}
秒。如果您的代码始终如此,那么您至少不会遇到行级死锁。除此之外,为代码中的关键部分实现适当的序列化。具体而言,这取决于您的应用程序。