如何在基于mysql innodb的php SessionHandler中防止死锁

如何在基于mysql innodb的php SessionHandler中防止死锁,php,mysql,session,innodb,deadlock,Php,Mysql,Session,Innodb,Deadlock,我通过实现SessionHandlerInterface实现了自己的基于innodb的PHP SessionHandler。由于许多同时发生的请求会经常发生,我必须防止赛车情况。 我的提供程序不支持通过选择GET LOCK…实现互斥锁。另外,我不想使用基于文件系统的锁定。 所以我决定使用innodb基于行的锁 我通过selectid fromsession FOR UPDATE(启动新事务后)在已实现的SessionHandlerInterface::read()方法中获得锁,并通过Sessio

我通过实现SessionHandlerInterface实现了自己的基于innodb的PHP SessionHandler。由于许多同时发生的请求会经常发生,我必须防止赛车情况。 我的提供程序不支持通过
选择GET LOCK…
实现互斥锁。另外,我不想使用基于文件系统的锁定。 所以我决定使用innodb基于行的锁

我通过
selectid fromsession FOR UPDATE
(启动新事务后)在已实现的
SessionHandlerInterface::read()
方法中获得锁,并通过
SessionHandlerInterface::write()
方法中的
COMMIT
释放锁

另外,我在
SessionHandlerInterface::destroy()
方法中执行
DELETE FROM session,其中ID=?
,在
SessionHandlerInterface::gc()方法中执行
DELETE FROM session,其中TIMESTAMPDIFF(SECOND,access,NOW())>?

SessionHandlerInterface::gc()
方法中的
DELETE
似乎是产生死锁的查询-至少
SHOW ENGINE INNODB STATUS
输出(示例1)

总结(
[…]
=一些其他代码):

显示引擎INNODB状态输出(示例2,不同的PC):


为什么要投否决票?没有评论?拜托。。。好问题。我会使用memcache会话处理程序,而不用担心数据库。您有apache或更好的Web服务器吗?PHP是在每个请求上加载还是只在.PHP文件上加载?Apache2.4,如果memcache可用,还不知道(还没有),不知道有什么特殊的处理程序。几乎每一个请求都会加载PHP,因为其他资源,如js、css甚至一些图像都是从db加载的,至少是通过PHP加载的。尚未优化http头-但锁应该可以正常工作。我使用
选择GET LOCK
时没有问题,但我的提供者环境无法处理该方法(系统错误)。如@DanFromGermany所述,有比基于数据库的会话更好的解决方案。您可以使用基于cookie的会话,其中会话信息被序列化为文本、加密、压缩和编码,这通常适合于一个cookie(或者您可以将信息分布在80个cookie上,每个cookie可以容纳4kb的数据)。这样就可以将会话存储转移到客户端。至于死锁——你不应该锁定行,你已经在一个事务中了。如果事务失败,您必须在放弃之前重试几次。您无法防止死锁,但可以(通过重试)从死锁中恢复。请记住,如果出现网络故障、断开连接等,大多数锁定机制都会释放锁。如果您不注意这一点,代码中可能会有一些“神秘”的错误。
[...]

protected static function lock($ID)
{
        $e = null;
        $i = 0;
        while($i < 10)
        {
            $e = null;

            try
            {
                DB::startTransaction("START TRANSACTION");
                DB::select("SELECT `ID` FROM `session` FOR UPDATE");
                break;
            }
            catch(MySQLi_SQL_Exception $e)
            {
                if(in_array($e->getCode(), [DB::ER_LOCK_WAIT_TIMEOUT, DB::ER_LOCK_DEADLOCK], true))
                {
                    usleep(10);
                    $i++;
                }
                else
                    throw $e;
            }
        }

        if($e) throw $e;
}

protected static function unlock($ID)
{
    DB::commit("COMMIT");
}

public function read($ID)
{
    self::lock($ID);
    $data = DB::select("SELECT `data` FROM `session` WHERE `ID` = ?", $ID, 'single', '');
    [...]
}

public function write($ID, $data)
{
    [...]
    $insert = (bool) DB::insert("INSERT INTO `session` (`ID`, `data`, `creation`, `access`, `access_micros`, `userAgent`, `IP`) VALUES (?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE `data` = ?, `access` = ?, `access_micros` = ?", $vals);

    self::unlock($ID);
    [...]
}

public function destroy($ID)
{ 
    return (bool) DB::delete("DELETE FROM `session` WHERE `ID` = ?", [$ID]);
}

public function gc($maxlifetime)
{
    DB::delete("DELETE FROM `session` WHERE TIMESTAMPDIFF(SECOND, `access`, NOW()) > ?", $maxlifetime);
    return true;
}
------------------------
LATEST DETECTED DEADLOCK
------------------------
2016-03-08 23:47:51 20a4
*** (1) TRANSACTION:
TRANSACTION 2564667, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 1284, OS thread handle 0x7e8, query id 1028285 localhost 127.0.0.1 U2251792 statistics
SELECT `ID` FROM `session` WHERE `ID` = '76157b19ce3c89f0985b585d8019a5ab0fa6444c6e516a844bd8cea6f6eba357' FOR UPDATE
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 2533 page no 3 n bits 72 index `PRIMARY` of table `db2251792`.`session` trx id 2564667 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 9; compact format; info bits 0
0: len 30; hex 373631353762313963653363383966303938356235383564383031396135; asc 76157b19ce3c89f0985b585d8019a5; (total 64 bytes);
1: len 6; hex 000000272233; asc    '"3;;
2: len 7; hex 3b00000152219e; asc ;   R! ;;
3: len 0; hex ; asc ;;
4: len 5; hex 9998d17b78; asc    {x;;
5: len 5; hex 9998d17bf3; asc    { ;;
6: len 3; hex 0e6a93; asc  j ;;
7: len 30; hex 4d6f7a696c6c612f352e30202857696e646f7773204e542031302e303b20; asc Mozilla/5.0 (Windows NT 10.0; ; (total 110 bytes);
8: len 4; hex 7f000001; asc     ;;

*** (2) TRANSACTION:
TRANSACTION 2564660, ACTIVE 0 sec starting index read, thread declared inside InnoDB 5000
mysql tables in use 1, locked 1
3 lock struct(s), heap size 360, 2 row lock(s)
MySQL thread id 1281, OS thread handle 0x20a4, query id 1028318 localhost 127.0.0.1 U2251792 updating
DELETE FROM `session` WHERE TIMESTAMPDIFF(SECOND, `access`, NOW()) > 3600
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 2533 page no 3 n bits 72 index `PRIMARY` of table `db2251792`.`session` trx id 2564660 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 9; compact format; info bits 0
0: len 30; hex 373631353762313963653363383966303938356235383564383031396135; asc 76157b19ce3c89f0985b585d8019a5; (total 64 bytes);
1: len 6; hex 000000272233; asc    '"3;;
2: len 7; hex 3b00000152219e; asc ;   R! ;;
3: len 0; hex ; asc ;;
4: len 5; hex 9998d17b78; asc    {x;;
5: len 5; hex 9998d17bf3; asc    { ;;
6: len 3; hex 0e6a93; asc  j ;;
7: len 30; hex 4d6f7a696c6c612f352e30202857696e646f7773204e542031302e303b20; asc Mozilla/5.0 (Windows NT 10.0; ; (total 110 bytes);
8: len 4; hex 7f000001; asc     ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 2533 page no 3 n bits 72 index `PRIMARY` of table `db2251792`.`session` trx id 2564660 lock_mode X waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 9; compact format; info bits 0
0: len 30; hex 373631353762313963653363383966303938356235383564383031396135; asc 76157b19ce3c89f0985b585d8019a5; (total 64 bytes);
1: len 6; hex 000000272233; asc    '"3;;
2: len 7; hex 3b00000152219e; asc ;   R! ;;
3: len 0; hex ; asc ;;
4: len 5; hex 9998d17b78; asc    {x;;
5: len 5; hex 9998d17bf3; asc    { ;;
6: len 3; hex 0e6a93; asc  j ;;
7: len 30; hex 4d6f7a696c6c612f352e30202857696e646f7773204e542031302e303b20; asc Mozilla/5.0 (Windows NT 10.0; ; (total 110 bytes);
8: len 4; hex 7f000001; asc     ;;

*** WE ROLL BACK TRANSACTION (1)
------------------------
LATEST DETECTED DEADLOCK
------------------------
2016-03-07 17:47:37 1894
*** (1) TRANSACTION:
TRANSACTION 3925672, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 312, 1 row lock(s)
MySQL thread id 25345, OS thread handle 0x3a40, query id 5247758 localhost 127.0.0.1 U2251792 Sending data
SELECT `ID` FROM `session` FOR UPDATE
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 3918 page no 3 n bits 104 index `PRIMARY` of table `db2251792`.`session` trx id 3925672 lock_mode X waiting
Record lock, heap no 33 PHYSICAL RECORD: n_fields 9; compact format; info bits 0
0: len 30; hex 363039303961363661393234616563366263666232636562346562343162; asc 60909a66a924aec6bcfb2ceb4eb41b; (total 64 bytes);
1: len 6; hex 0000003be6a0; asc    ;  ;;
2: len 7; hex 1d000001ab02e9; asc        ;;
3: len 30; hex 61596d5a57532b752f336945486a645a586a4f45745539387170517a546d; asc aYmZWS+u/3iEHjdZXjOEtU98qpQzTm; (total 192 bytes);
4: len 5; hex 9998cf1bdf; asc      ;;
5: len 5; hex 9998cf1be4; asc      ;;
6: len 3; hex 00023e; asc   >;;
7: len 30; hex 4d6f7a696c6c612f352e30202857696e646f7773204e542031302e303b20; asc Mozilla/5.0 (Windows NT 10.0; ; (total 109 bytes);
8: len 4; hex 7f000001; asc     ;;

*** (2) TRANSACTION:
TRANSACTION 3925665, ACTIVE 1 sec inserting, thread declared inside InnoDB 5000
mysql tables in use 1, locked 1
3 lock struct(s), heap size 312, 3 row lock(s)
MySQL thread id 25341, OS thread handle 0x1894, query id 5247805 localhost 127.0.0.1 U2251792 update
INSERT INTO `session` (`ID`, `data`, `creation`, `access`, `access_micros`, `userAgent`, `IP`) VALUES ('41e4530eb45871ee64277560290062949b18e6fdb6f8e9cddb097ecd3ccb7c12', '+w1R6dDO2Xx1bzYV4IVt4JV/LFTwb+HtrGvQNK+JgzBs4DQfrjlmUiPX46VjAG0ONjiIHBPiGUAbZXd3Nvy25Lm3pVInq0qkGRDj6GaLVgQ2MSQkjk2YGfY3VMOYRM/23YD6XvPr6DdUIz7120skEBX2SrFUuRX7lBzUZROBJxUVXQ+/mal+paHacMoYJfjF', '2016-03-07 17:47:37', '2016-03-07 17:47:37', 40240, 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.75 Safari/537.36', '\0\0') ON DUPLICATE KEY UPDATE `data` = '+w1R6dDO2Xx1bzYV4IVt4JV/LFTwb+HtrGvQNK+JgzBs4DQfrjlmUiPX46VjAG0ONjiIHBPiGUAbZXd3Nvy25Lm3pVInq0qkGRDj6GaLVgQ2MSQkjk2YGfY3VMOYRM/23YD6XvPr6DdUIz7120skEBX2SrFUuRX7lBzUZROBJxUVXQ+/mal+paHacMoYJfjF', `access` = '2016-03-07 17:47:37', `access_micros` = 40240
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 3918 page no 3 n bits 104 index `PRIMARY` of table `db2251792`.`session` trx id 3925665 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;

Record lock, heap no 33 PHYSICAL RECORD: n_fields 9; compact format; info bits 0
0: len 30; hex 363039303961363661393234616563366263666232636562346562343162; asc 60909a66a924aec6bcfb2ceb4eb41b; (total 64 bytes);
1: len 6; hex 0000003be6a0; asc    ;  ;;
2: len 7; hex 1d000001ab02e9; asc        ;;
3: len 30; hex 61596d5a57532b752f336945486a645a586a4f45745539387170517a546d; asc aYmZWS+u/3iEHjdZXjOEtU98qpQzTm; (total 192 bytes);
4: len 5; hex 9998cf1bdf; asc      ;;
5: len 5; hex 9998cf1be4; asc      ;;
6: len 3; hex 00023e; asc   >;;
7: len 30; hex 4d6f7a696c6c612f352e30202857696e646f7773204e542031302e303b20; asc Mozilla/5.0 (Windows NT 10.0; ; (total 109 bytes);
8: len 4; hex 7f000001; asc     ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 3918 page no 3 n bits 104 index `PRIMARY` of table `db2251792`.`session` trx id 3925665 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 33 PHYSICAL RECORD: n_fields 9; compact format; info bits 0
0: len 30; hex 363039303961363661393234616563366263666232636562346562343162; asc 60909a66a924aec6bcfb2ceb4eb41b; (total 64 bytes);
1: len 6; hex 0000003be6a0; asc    ;  ;;
2: len 7; hex 1d000001ab02e9; asc        ;;
3: len 30; hex 61596d5a57532b752f336945486a645a586a4f45745539387170517a546d; asc aYmZWS+u/3iEHjdZXjOEtU98qpQzTm; (total 192 bytes);
4: len 5; hex 9998cf1bdf; asc      ;;
5: len 5; hex 9998cf1be4; asc      ;;
6: len 3; hex 00023e; asc   >;;
7: len 30; hex 4d6f7a696c6c612f352e30202857696e646f7773204e542031302e303b20; asc Mozilla/5.0 (Windows NT 10.0; ; (total 109 bytes);
8: len 4; hex 7f000001; asc     ;;

*** WE ROLL BACK TRANSACTION (1)