我有两个函数用于从名为tree_elements的表创建虚拟路径名。在表的任何更新时调用函数路径(id,language)。有时,表的更新会导致死锁,并显示错误消息(示例):
select path(621163,"de")
Deadlock found when trying to get lock; try restarting transaction
我不明白为什么会有锁定。这些函数仅使用选择,不更新,不插入,不删除。我该如何避免这种现象?
有我的功能:
mysql> show create function path\G
*************************** 1. row ***************************
Function: path
sql_mode:
Create Function: CREATE DEFINER=`root`@`localhost` FUNCTION `path`(id integer, language char(2)) RETURNS varchar(255) CHARSET utf8
READS SQL DATA
DETERMINISTIC
COMMENT 'Converts a record id into an url string with path'
begin
declare ret varchar(255);
declare r varchar(255);
declare element varchar(255);
set ret = path_component(id,language);
set id = (select id_parent from tree_elements t where t.id=id);
while (id > 0) do
set element = concat(path_component(id,language), '/');
if (locate( element, ret )) then return concat( 'Infinite loop in path for id ', id ); end if;
set ret = concat(path_component(id,language), '/', ret );
set id = (select id_parent from tree_elements t where t.id=id);
end while;
return ret;
end
character_set_client: latin1
collation_connection: latin1_swedish_ci
Database Collation: utf8_general_ci
mysql> show create function path_component\G
*************************** 1. row ***************************
Function: path_component
sql_mode:
Create Function: CREATE DEFINER=`root`@`localhost` FUNCTION `path_component`( id integer, language char(2)) RETURNS varchar(500) CHARSET utf8
READS SQL DATA
DETERMINISTIC
begin
declare f varchar(255);
set f = (select case language
when 'en' then title_en
when 'de' then title_de
else title_en
end
from tree_elements t where t.id=id);
if (isnull(f) or length(trim(f)) = 0) then
set f = (select title_en from tree_elements t where t.id=id);
end if;
return url(f);
end
character_set_client: latin1
collation_connection: utf8_general_ci
Database Collation: utf8_general_ci
答案 0 :(得分:0)
您不必插入或更新数据来锁定表(或表的页面)。选择数据可以锁定表(根据RDBMS引擎的默认锁定策略)这就是为什么我们有特定的指令告诉引擎在选择数据时不要对表进行锁定。(在SQL Server中,你可以通过使用名称后的NoLock指令)。 当您在表中选择多行时,表可能会锁定多个页面。当您在同一个表上运行两个不同的查询并且查询1锁定查询2需要的页面并且查询2锁定查询1需要的页面时,您将获得死锁。一种解决方案是强制查询使用某个索引保证页面将按特定顺序锁定。通常死锁条件是最难处理的问题。