0

我有两个函数用于从名为 tree_elements 的表中创建虚拟路径名。对表的任何更新都会调用函数 path(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
4

1 回答 1

0

您不必插入或更新数据来锁定表(或表的页)。选择数据可以锁定表(根据 RDBMS 引擎的默认锁定策略)这就是为什么我们有特定的指令告诉引擎在选择数据时不要对表加锁。(在 SQL Server 中,您可以通过将 With NoLock 指令在 talbe 名称后)。当您在表格中选择多行时,可能会锁定表格的多个页面。当您在同一个表上运行两个不同的查询并且查询 1 锁定了查询 2 需要的页面并且查询 2 锁定了查询 1 需要的页面时,您将遇到死锁。一种解决方案是强制查询使用将保证页面将按一定顺序锁定。通常死锁条件是最难处理的问题。

于 2012-02-19T12:41:33.447 回答