2012-02-19 46 views
0

我有兩個函數用於從名爲tree_elements的表創建虛擬路徑名。在表的任何更新上調用函數路徑(id,language)。不時表的更新導致出現錯誤消息(例如)死鎖:如何在只有select查詢的情況下避免mysql函數中的死鎖?

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

有一個答案[這裏](http://stackoverflow.com/questions/917640/any-way-to-select-without-causing-locking-in-mysql),其可以使用的。 – Bojangles 2012-02-19 12:46:54

回答

0

您不必插入或更新數據,以鎖定表(或表的頁面)。選擇數據可以鎖定表(根據RDBMS引擎的默認鎖策略)這就是爲什麼我們有具體的指示告訴引擎不要把鎖在一個表,而選擇數據。(在SQL Server中,你可以得到這個通過把用NoLock指令在一個talbe的名字之後)。 當您在表格中選擇多行時,表格可能會鎖定多個頁面。當您在同一個表上運行兩個不同的查詢並且查詢1鎖定查詢2需要的頁面並且查詢2鎖定查詢1需要的頁面時,您將遇到死鎖。一種解決方案是強制查詢使用某個索引保證頁面將以特定的順序被鎖定。通常,死鎖條件是最難處理的問題。

+0

謝謝。同時我用SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED將我的函數中的SELECT括起來;和SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;分別。到目前爲止沒有新的錯誤消息。 – 2012-02-19 19:37:02